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

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

Major: rethrow PacpusException on parameter parsing, set configurationState to ComponentBase::CONFIGURED_FAILED.

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