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

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

Major: cleaned connection interfaces.

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