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

Last change on this file since 204 was 204, checked in by Marek Kurdej, 11 years ago

Minor: output format.

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