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

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

Update: fixed getDataSize(), getDataType() in connections.

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