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

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

Fixed: Qt4 compilation on Linux

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