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

Last change on this file since 185 was 185, checked in by morasjul, 11 years ago

Fixed: dependencies.

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