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

Last change on this file since 290 was 290, checked in by Marek Kurdej, 10 years ago

Some clean-up.

  • 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.
[290]40bool connectInterface(OutputInterfaceBase* out, InputInterfaceBase* in, int priority, InputInterfaceBase::ReadingMode mode = InputInterfaceBase::GetLast);
[185]41
42////////////////////////////////////////////////////////////////////////////////
43
[290]44bool connectInterface(OutputInterfaceBase* out, InputInterfaceBase* in, int priority, InputInterfaceBase::ReadingMode mode)
[185]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);
[277]70 LOG_INFO("connection created: source=" << out->getSignature() << ", destination=" << in->getSignature());
[206]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
[288]127bool ComponentManager::registerComponentFactory(ComponentFactoryBase* addr, QString const& type)
[89]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
[288]143bool ComponentManager::unregisterComponentFactory(QString const& 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
[288]158bool ComponentManager::registerComponent(boost::shared_ptr<ComponentBase> addr, QString const& name)
[89]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
[288]173bool ComponentManager::unregisterComponent(QString const& 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
[288]182 boost::shared_ptr<ComponentBase> component = componentMap_.value(name, NULL);
183
[146]184 // FIXME: remove from map (causes segfault in QMap::qMapLessThanKey on Windows)
185 //componentMap_.remove(name);
[89]186 LOG_INFO("unregistered component '" << name << "'");
187 return true;
188}
189
[288]190bool ComponentManager::createComponent(QString const& type, QString const& name)
[89]191{
192 LOG_TRACE("createComponent(type=" << type << ", " << "name="<< name << ")");
193
[146]194 if (factoryMap_.contains(type)) {
195 ComponentFactoryBase* factory = factoryMap_.value(type);
196 assert(factory);
[288]197 factory->createComponent(name);
[89]198 return true;
199 }
200
201 LOG_WARN("cannot create component '" << name << "'"
202 << ". Component factory for type '" << type << "'"
203 << " does not exist or was not registered"
204 );
205 return false;
206}
207
[288]208bool ComponentManager::loadPlugin(QString const& filename)
[89]209{
210 LOG_TRACE("loadPlugin(filename=" << filename << ")");
211
212 pluginLoader_.setFileName(filename);
213
214 if (!pluginLoader_.load()) {
215 LOG_ERROR("cannot load plugin '" << filename << "'"
216 << ". Plugin loader returned error: " << pluginLoader_.errorString()
217 );
218 return false;
219 }
220
221 QObject * plugin = pluginLoader_.instance();
222 if (NULL == plugin) {
223 LOG_WARN("cannot create an instance of the plugin '" << filename << "'"
224 << ". Plugin loader returned error: " << pluginLoader_.errorString()
225 );
226 return false;
227 }
228 pluginList_.append(plugin);
229 LOG_INFO("loaded plugin '" << qobject_cast<PacpusPluginInterface*>(plugin)->name() << "'"
230 << " from file '" << pluginLoader_.fileName() << "'"
231 );
232 return true;
233}
234
[288]235bool ComponentManager::checkComponent(QString const& componentName)
[184]236{
237 if (NULL == getComponent(componentName)) {
[207]238 LOG_WARN("component " << componentName << " does not exist");
[184]239 return false;
240 }
[207]241 return true;
242}
243
[288]244bool ComponentManager::checkComponentInput(QString const& componentName, QString const& inputName)
[207]245{
246 if (!checkComponent(componentName)) {
[184]247 return false;
248 }
[207]249 if (NULL == getComponent(componentName)->getInput(inputName)) {
250 LOG_WARN("cannot make connection: component " << componentName << " does not have input " << inputName);
251 return false;
252 }
[184]253 return true;
254}
255
[288]256bool ComponentManager::checkComponentOutput(QString const& componentName, QString const& outputName)
[207]257{
258 if (!checkComponent(componentName)) {
259 return false;
260 }
261 if (NULL == getComponent(componentName)->getOutput(outputName)) {
262 LOG_WARN("cannot make connection: component " << componentName << " does not have output " << outputName);
263 return false;
264 }
265 return true;
266}
267
[288]268bool ComponentManager::createConnection(QString const& outputSignature, QString const& inputSignature, QString const& type, int priority = 0)
[89]269{
[184]270 // FIXME: use 2 signatures (output component + output connection) instead of 1 separated by a (".") dot
[89]271 QStringList output = outputSignature.split(".");
272 QStringList input = inputSignature.split(".");
273
[207]274 if (!checkComponentOutput(output[0], output[1])) {
[184]275 return false;
276 }
[207]277 if (!checkComponentInput(input[0], input[1])) {
[184]278 return false;
279 }
[206]280 // FIXME: Create communicationInterface if needed ??
[182]281 return connectInterface(
282 getComponent(output[0])->getOutput(output[1]),
283 getComponent(input[0])->getInput(input[1]),
284 priority
285 );
[89]286}
287
[288]288std::size_t ComponentManager::loadComponents(QString const& configFilename)
[89]289{
290 LOG_TRACE("loadComponents(filename=" << configFilename << ")");
291
292 // load the components tree in memory
293 xmlTree_->loadFile(configFilename);
294
295 {
296 // Load the plugins containing the components
[146]297 QStringList plugins = xmlTree_->getAllPluginsNames();
[89]298 Q_FOREACH (QString plugin, plugins) {
299 if (!loadPlugin(plugin)) {
300 LOG_WARN("cannot load plugin '" << plugin << "'");
[146]301 } else {
302 LOG_INFO("successfully loaded plugin '" << plugin << "'");
[89]303 }
304 }
305 }
306
307 QDomNodeList componentsNodeList = xmlTree_->getAllComponents();
308 XmlComponentConfig cfg;
309
310 // First, create all the components in the XML list
311 for (int i = 0; i < componentsNodeList.size(); ++i) {
312 cfg.localCopy(componentsNodeList.item(i).toElement());
313 QString componentType = cfg.getComponentType();
314 QString componentName = cfg.getComponentName();
[110]315 LOG_DEBUG("try to create component '" << componentName << "'");
316
[89]317 // create the component and automatically add it to the component manager list
318 if (!createComponent(componentType, componentName)) {
319 LOG_ERROR("cannot create component '" << componentName << "'");
320 continue;
321 }
322 }
323
324 int componentsToConfigureCount = componentMap_.count();
325
326 // Second, try to configure the components without regarding the dependencies
327 for (int i = 0; i < componentsNodeList.size(); ++i) {
328 cfg.localCopy(componentsNodeList.item(i).toElement());
329 QString componentName = cfg.getComponentName();
[110]330 LOG_DEBUG("try to configure component '" << componentName << "'");
[89]331
332 // copy locally the config parameters of the component
[288]333 ComponentSharedPointer component = getComponent(componentName);
[89]334 if (NULL == component) {
335 LOG_WARN("component '" << componentName << "' does not exist");
[201]336 continue;
337 }
338
[270]339 component->param.localCopy(cfg.getDomElement());
[201]340 try {
[176]341 component->parseParameters(cfg);
[152]342 component->setConfigurationState(component->configureComponent(cfg));
[201]343 } catch (PacpusException & e) {
344 LOG_ERROR("component '" << componentName << "' has thrown an exception");
345 LOG_ERROR(e.what());
346 component->setConfigurationState(ComponentBase::CONFIGURED_FAILED);
[89]347 }
348 } // for
349
350 // Third, if some components requested a delayed configuration, retry
[201]351 for (int i = 0, iend = componentsNodeList.size(); i < iend; ++i) {
[89]352 cfg.localCopy(componentsNodeList.item(i).toElement());
353 QString componentName = cfg.getComponentName();
354
[288]355 ComponentSharedPointer component = getComponent(componentName);
356 if (!component) {
[89]357 LOG_WARN("component '" << componentName << "' does not exist");
[201]358 continue;
359 }
360
[202]361 // add inputs and outputs
[201]362 component->addInputs();
363 component->addOutputs();
[202]364 // print inputs and outputs
[204]365 LOG_INFO("Inputs for component '" << componentName << "':\n" << component->inputs().keys());
366 LOG_INFO("Outputs for component '" << componentName << "':\n" << component->outputs().keys());
[120]367
[201]368 if (ComponentBase::CONFIGURATION_DELAYED == component->configurationState()) {
369 LOG_DEBUG("try to configure component '" << componentName << "'");
[89]370
[201]371 // copy locally the config parameters of the component
[270]372 component->param.localCopy(cfg.getDomElement());
[201]373 component->setConfigurationState(component->configureComponent(cfg));
374 }
[89]375
[201]376 if (ComponentBase::CONFIGURED_OK == component->configurationState()) {
377 --componentsToConfigureCount;
378 } else {
379 LOG_ERROR("cannot configure component '" << componentName << "'"
380 << ". Dependencies with other components are too complex"
381 << ". It was not configured, please review your configuration and/or your component"
382 );
383 component->setConfigurationState(ComponentBase::CONFIGURED_FAILED);
[89]384 }
385 } // for
386
387 LOG_INFO(componentMap_.count() << " component(s) were loaded");
388 if (componentsToConfigureCount > 0) {
389 LOG_WARN(componentsToConfigureCount << " component(s) were not configured");
390 }
391
392 // Fourthly, create connections find in the XML list
393 QDomNodeList connectionsNodeList = xmlTree_->getAllConnections();
394
[201]395 for (int i = 0, iend = connectionsNodeList.size(); i < iend; ++i) {
[89]396 cfg.localCopy(connectionsNodeList.item(i).toElement());
397 QString connectionInput = cfg.getConnectionInput();
398 QString connectionOutput = cfg.getConnectionOutput();
399 QString connectionType = cfg.getConnectionType();
400 int connectionPriority = cfg.getConnectionPriority();
401
[120]402 //TODO set connection mode from string
403
404 //InputInterfaceBase::GetLast;
405 //InputInterfaceBase::NeverSkip;
406 //InputInterfaceBase::TimeBounded;
407
[89]408 if (!createConnection(connectionOutput, connectionInput, connectionType,connectionPriority)) {
[207]409 LOG_ERROR("cannot create connection '" << connectionOutput + " => " + connectionInput << "'");
[89]410 continue;
411 }
[120]412 } // for
[89]413
414 return componentMap_.count();
415}
416
417bool ComponentManager::start()
418{
419 LOG_TRACE("start()");
420
421 bool result = true;
[146]422 for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) {
[89]423 result &= start(it.key());
[146]424 }
[89]425
426 return result;
427}
428
[288]429bool ComponentManager::start(QString const& componentName)
[89]430{
431 LOG_TRACE("start(component=" << componentName << ")");
432
[288]433 ComponentSharedPointer component = getComponent(componentName);
[153]434 if (!component) {
[89]435 LOG_WARN("cannot start component '" << componentName << "'. It does not exist!");
436 return false;
437 }
438
[201]439 if (ComponentBase::CONFIGURED_OK != component->configurationState()) {
440 LOG_WARN("cannot start component '" << componentName << "'. It has not been configured properly!");
441 return false;
442 }
443
[89]444 LOG_INFO("starting component '" << componentName << "'...");
[141]445 if (!component->startComponent()) {
[89]446 LOG_WARN("cannot start component '" << componentName << "'. It can already be started");
[141]447 }
[153]448 LOG_INFO("successfully started component '" << componentName << "'");
[89]449 return true;
450}
451
452bool ComponentManager::stop()
453{
454 LOG_TRACE("stop()");
455
456 bool result = true;
[146]457 for (ComponentMap::iterator it = componentMap_.begin(), itend = componentMap_.end(); it != itend; ++it) {
458 result &= stop(*it);
459 }
[89]460
461 return result;
462}
463
[288]464bool ComponentManager::stop(ComponentSharedPointer component) const
[146]465{
466 if (!component) {
467 LOG_WARN("NULL component pointer");
468 return false;
469 }
470 if (!component->stopComponent()) {
471 return false;
472 }
473 return true;
474}
475
[288]476bool ComponentManager::stop(QString const& componentName)
[89]477{
478 LOG_TRACE("stop(component=" << componentName << ")");
479
[288]480 ComponentSharedPointer component = getComponent(componentName);
[146]481 if (!component) {
[89]482 LOG_WARN("cannot stop component '" << componentName << "'" << ". It does not exist");
483 return false;
484 }
485
486 LOG_INFO("stopping component '" << componentName << "'...");
[146]487 if (!stop(component)) {
[89]488 LOG_WARN("cannot stop component '" << componentName << "'" << ". It can be already stopped");
[141]489 }
[89]490
491 return true;
492}
493
[288]494ComponentSharedPointer ComponentManager::getComponent(QString const& name)
[89]495{
496 LOG_TRACE("getComponent(name=" << name << ")");
497
498 ComponentMap::iterator it = componentMap_.find(name);
[141]499 if (it != componentMap_.end()) {
[89]500 return *it;
[141]501 }
[89]502
503 LOG_WARN("cannot retrieve component '" << name << "'" << ". It does not exist");
504 return NULL;
505}
506
507QStringList ComponentManager::getAllComponentsName() const
508{
509 LOG_TRACE("getAllComponentsName()");
510 return xmlTree_->getAllComponentsNames();
511}
Note: See TracBrowser for help on using the repository browser.