source: pacpusframework/trunk/src/PacpusLib/ComponentManager.cpp@ 184

Last change on this file since 184 was 184, checked in by morasjul, 11 years ago

Minor fixes.

  • Property svn:executable set to *
File size: 13.9 KB
Line 
1// %pacpus:license{
2// This file is part of the PACPUS framework distributed under the
3// CECILL-C License, Version 1.0.
4// %pacpus:license}
5/// @author Gerald Dherbomez <firstname.surname@utc.fr>
6/// @version $Id: ComponentManager.cpp 76 2013-01-10 17:05:10Z kurdejma $
7
8#include <Pacpus/kernel/ComponentFactoryBase.h>
9#include <Pacpus/kernel/ComponentManager.h>
10#include <Pacpus/kernel/ComponentBase.h>
11#include <Pacpus/kernel/ConnectionBase.h>
12#include <Pacpus/kernel/InputOutputBase.h>
13#include <Pacpus/kernel/Log.h>
14#include <QDomNodeList>
15#include <QObject>
16
17using namespace pacpus;
18
19DECLARE_STATIC_LOGGER("pacpus.core.ComponentManager");
20
21ComponentManager * ComponentManager::mInstance = NULL;
22
23ComponentManager * ComponentManager::create()
24{
25 return getInstance();
26}
27
28ComponentManager * ComponentManager::getInstance()
29{
30 LOG_TRACE("getInstance()");
31 LOG_TRACE("before: mInstance = " << mInstance);
32
33 if (!mInstance) {
34 LOG_INFO("creating new instance...");
35 mInstance = new ComponentManager();
36 LOG_DEBUG("mInstance = " << mInstance);
37 }
38
39 LOG_TRACE("after : mInstance = " << mInstance);
40 return mInstance;
41}
42
43void ComponentManager::destroy()
44{
45 LOG_TRACE("destroy");
46
47 LOG_TRACE("before: mInstance = " << mInstance);
48 delete mInstance;
49 mInstance = NULL;
50 LOG_TRACE("after : mInstance = " << mInstance);
51}
52
53ComponentManager::ComponentManager()
54{
55 LOG_TRACE("constructor");
56
57 xmlTree_ = XmlConfigFile::create();
58 LOG_DEBUG("component manager was created");
59}
60
61ComponentManager::~ComponentManager()
62{
63 LOG_TRACE("destructor");
64
65 for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) {
66 bool unregisteredSuccessfully = unregisterComponent(it.key());
67 }
68
69 LOG_DEBUG("component manager was deleted");
70}
71
72bool ComponentManager::registerComponentFactory(ComponentFactoryBase* addr, const QString& type)
73{
74 LOG_TRACE("registerComponentFactory(type="<< type << ")");
75
76 if (factoryMap_.contains(type))
77 {
78 LOG_WARN("cannot register a component factory of type '" << type << "'. It already belongs to the manager");
79 return false;
80 }
81
82 factoryMap_[type] = addr;
83 LOG_INFO("registered component factory '" << type << "'");
84
85 return true;
86}
87
88bool ComponentManager::unregisterComponentFactory(const QString& type)
89{
90 LOG_TRACE("unregisterComponentFactory(type="<< type << ")");
91
92 if (!factoryMap_.contains(type)) {
93 LOG_WARN("cannot unregister component factory '" << type << "'. It was not registered");
94 return false;
95 }
96
97 factoryMap_.remove(type);
98 LOG_INFO("unregistered component factory '" << type << "'");
99
100 return true;
101}
102
103bool ComponentManager::registerComponent(ComponentBase* addr, const QString& name)
104{
105 LOG_TRACE("registerComponent(name="<< name << ")");
106
107 if (componentMap_.contains(name))
108 {
109 LOG_WARN("cannot register component '" << name << "'. A component with the same name exists already");
110 return false;
111 }
112
113 componentMap_[name] = addr;
114 LOG_INFO("registered component " << name);
115
116 return true;
117}
118
119bool ComponentManager::unregisterComponent(const QString& name)
120{
121 LOG_TRACE("unregisterComponent(name="<< name << ")");
122
123 if (!componentMap_.contains(name)) {
124 LOG_WARN("cannot unregister component '" << name << "'. It was not registered");
125 return false;
126 }
127
128 // FIXME: delete component
129 ComponentBase* component = componentMap_.value(name, NULL);
130 //delete component;
131
132 // FIXME: remove from map (causes segfault in QMap::qMapLessThanKey on Windows)
133 //componentMap_.remove(name);
134 LOG_INFO("unregistered component '" << name << "'");
135
136 return true;
137}
138
139bool ComponentManager::createComponent(const QString& type, const QString& name)
140{
141 LOG_TRACE("createComponent(type=" << type << ", " << "name="<< name << ")");
142
143 if (factoryMap_.contains(type)) {
144 ComponentFactoryBase* factory = factoryMap_.value(type);
145 assert(factory);
146 factory->addComponent(name);
147 return true;
148 }
149
150 LOG_WARN("cannot create component '" << name << "'"
151 << ". Component factory for type '" << type << "'"
152 << " does not exist or was not registered"
153 );
154 return false;
155}
156
157bool ComponentManager::loadPlugin(const QString& filename)
158{
159 LOG_TRACE("loadPlugin(filename=" << filename << ")");
160
161 pluginLoader_.setFileName(filename);
162
163 if (!pluginLoader_.load()) {
164 LOG_ERROR("cannot load plugin '" << filename << "'"
165 << ". Plugin loader returned error: " << pluginLoader_.errorString()
166 );
167 return false;
168 }
169
170 QObject * plugin = pluginLoader_.instance();
171 if (NULL == plugin) {
172 LOG_WARN("cannot create an instance of the plugin '" << filename << "'"
173 << ". Plugin loader returned error: " << pluginLoader_.errorString()
174 );
175 return false;
176 }
177 pluginList_.append(plugin);
178 LOG_INFO("loaded plugin '" << qobject_cast<PacpusPluginInterface*>(plugin)->name() << "'"
179 << " from file '" << pluginLoader_.fileName() << "'"
180 );
181 return true;
182}
183
184bool ComponentManager::checkComponentConnection(const QString& componentName, const QString& connectionName)
185{
186 if (NULL == getComponent(componentName)) {
187 LOG_WARN("cannot make connection : component " << componentName << " not found");
188 return false;
189 }
190 if (NULL == getComponent(componentName)->getOutput(connectionName)) {
191 LOG_WARN("cannot make connection : component " << componentName << " does not have input/output " << connectionName);
192 return false;
193 }
194 return true;
195}
196
197bool ComponentManager::createConnection(const QString& outputSignature, const QString& inputSignature, const QString& type, int priority = 0)
198{
199 // FIXME: use 2 signatures (output component + output connection) instead of 1 separated by a (".") dot
200 QStringList output = outputSignature.split(".");
201 QStringList input = inputSignature.split(".");
202
203 if (!checkComponentConnection(output[0], output[1])) {
204 return false;
205 }
206 if (!checkComponentConnection(input[0], input[1])) {
207 return false;
208 }
209 // NOTE Create communicationInterface if needed ??
210 return connectInterface(
211 getComponent(output[0])->getOutput(output[1]),
212 getComponent(input[0])->getInput(input[1]),
213 priority
214 );
215}
216
217std::size_t ComponentManager::loadComponents(const QString& configFilename)
218{
219 LOG_TRACE("loadComponents(filename=" << configFilename << ")");
220
221 // load the components tree in memory
222 xmlTree_->loadFile(configFilename);
223
224 {
225 // Load the plugins containing the components
226 QStringList plugins = xmlTree_->getAllPluginsNames();
227 Q_FOREACH (QString plugin, plugins) {
228 if (!loadPlugin(plugin)) {
229 LOG_WARN("cannot load plugin '" << plugin << "'");
230 } else {
231 LOG_INFO("successfully loaded plugin '" << plugin << "'");
232 }
233 }
234 }
235
236 QDomNodeList componentsNodeList = xmlTree_->getAllComponents();
237 XmlComponentConfig cfg;
238
239 // First, create all the components in the XML list
240 for (int i = 0; i < componentsNodeList.size(); ++i) {
241 cfg.localCopy(componentsNodeList.item(i).toElement());
242 QString componentType = cfg.getComponentType();
243 QString componentName = cfg.getComponentName();
244 LOG_DEBUG("try to create component '" << componentName << "'");
245
246 // create the component and automatically add it to the component manager list
247 if (!createComponent(componentType, componentName)) {
248 LOG_ERROR("cannot create component '" << componentName << "'");
249 continue;
250 }
251 }
252
253 int componentsToConfigureCount = componentMap_.count();
254
255 // Second, try to configure the components without regarding the dependencies
256 for (int i = 0; i < componentsNodeList.size(); ++i) {
257 cfg.localCopy(componentsNodeList.item(i).toElement());
258 QString componentName = cfg.getComponentName();
259 LOG_DEBUG("try to configure component '" << componentName << "'");
260
261 // copy locally the config parameters of the component
262 ComponentBase * component = getComponent(componentName);
263 if (NULL == component) {
264 LOG_WARN("component '" << componentName << "' does not exist");
265 } else {
266 component->param.localCopy(cfg.qDomElement());
267 component->parseParameters(cfg);
268 component->setConfigurationState(component->configureComponent(cfg));
269 }
270 } // for
271
272 // Third, if some components requested a delayed configuration, retry
273 for (int i = 0; i < componentsNodeList.size(); ++i) {
274 cfg.localCopy(componentsNodeList.item(i).toElement());
275 QString componentName = cfg.getComponentName();
276
277 ComponentBase * component = getComponent(componentName);
278 if (NULL == component) {
279 LOG_WARN("component '" << componentName << "' does not exist");
280 } else {
281 // Pacpus 2.0 : add inputs and outputs
282 component->addInputs();
283 component->addOutputs();
284
285 if (ComponentBase::CONFIGURATION_DELAYED == component->configurationState()) {
286 LOG_DEBUG("try to configure component '" << componentName << "'");
287
288 // copy locally the config parameters of the component
289 component->param.localCopy(cfg.qDomElement());
290 component->setConfigurationState(component->configureComponent(cfg));
291 }
292
293 if (ComponentBase::CONFIGURED_OK == component->configurationState()) {
294 --componentsToConfigureCount;
295 } else {
296 LOG_ERROR("cannot configure component '" << componentName << "'"
297 << ". Dependencies with other components are too complex"
298 << ". It was not configured, please review your configuration and/or your component"
299 );
300 component->setConfigurationState(ComponentBase::CONFIGURED_FAILED);
301 }
302 }
303 } // for
304
305 LOG_INFO(componentMap_.count() << " component(s) were loaded");
306 if (componentsToConfigureCount > 0) {
307 LOG_WARN(componentsToConfigureCount << " component(s) were not configured");
308 }
309
310 // Fourthly, create connections find in the XML list
311 QDomNodeList connectionsNodeList = xmlTree_->getAllConnections();
312
313 for (int i = 0; i < connectionsNodeList.size(); ++i) {
314 cfg.localCopy(connectionsNodeList.item(i).toElement());
315 QString connectionInput = cfg.getConnectionInput();
316 QString connectionOutput = cfg.getConnectionOutput();
317 QString connectionType = cfg.getConnectionType();
318 int connectionPriority = cfg.getConnectionPriority();
319
320 //TODO set connection mode from string
321
322 //InputInterfaceBase::GetLast;
323 //InputInterfaceBase::NeverSkip;
324 //InputInterfaceBase::TimeBounded;
325
326 if (!createConnection(connectionOutput, connectionInput, connectionType,connectionPriority)) {
327 LOG_ERROR("cannot create connection '" << connectionOutput+"=>"+connectionInput << "'");
328 continue;
329 }
330 } // for
331
332 return componentMap_.count();
333}
334
335bool ComponentManager::start()
336{
337 LOG_TRACE("start()");
338
339 bool result = true;
340 for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) {
341 result &= start(it.key());
342 }
343
344 return result;
345}
346
347bool ComponentManager::start(const QString& componentName)
348{
349 LOG_TRACE("start(component=" << componentName << ")");
350
351 ComponentBase* component = getComponent(componentName);
352 if (!component) {
353 LOG_WARN("cannot start component '" << componentName << "'. It does not exist!");
354 return false;
355 }
356
357 LOG_INFO("starting component '" << componentName << "'...");
358 if (!component->startComponent()) {
359 LOG_WARN("cannot start component '" << componentName << "'. It can already be started");
360 }
361 LOG_INFO("successfully started component '" << componentName << "'");
362 return true;
363}
364
365bool ComponentManager::stop()
366{
367 LOG_TRACE("stop()");
368
369 bool result = true;
370 for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) {
371 result &= stop(*it);
372 }
373
374 return result;
375}
376
377bool ComponentManager::stop(ComponentBase* component) const
378{
379 if (!component) {
380 LOG_WARN("NULL component pointer");
381 return false;
382 }
383 if (!component->stopComponent()) {
384 return false;
385 }
386 return true;
387}
388
389bool ComponentManager::stop(const QString& componentName)
390{
391 LOG_TRACE("stop(component=" << componentName << ")");
392
393 ComponentBase* component = getComponent(componentName);
394 if (!component) {
395 LOG_WARN("cannot stop component '" << componentName << "'" << ". It does not exist");
396 return false;
397 }
398
399 LOG_INFO("stopping component '" << componentName << "'...");
400 if (!stop(component)) {
401 LOG_WARN("cannot stop component '" << componentName << "'" << ". It can be already stopped");
402 }
403
404 return true;
405}
406
407ComponentBase* ComponentManager::getComponent(const QString& name)
408{
409 LOG_TRACE("getComponent(name=" << name << ")");
410
411 ComponentMap::iterator it = componentMap_.find(name);
412 if (it != componentMap_.end()) {
413 return *it;
414 }
415
416 LOG_WARN("cannot retrieve component '" << name << "'" << ". It does not exist");
417 return NULL;
418}
419
420QStringList ComponentManager::getAllComponentsName() const
421{
422 LOG_TRACE("getAllComponentsName()");
423 return xmlTree_->getAllComponentsNames();
424}
Note: See TracBrowser for help on using the repository browser.