source: pacpusframework/trunk/src/PacpusLib/ComponentBase.cpp@ 279

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

[ComponentBase] MAJOR: Using: boost::thread to start each component.

  • Property svn:executable set to *
File size: 15.1 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/// @version $Id: ComponentBase.cpp 76 2013-01-10 17:05:10Z kurdejma $
6
7#include <Pacpus/kernel/ComponentBase.h>
8
9#include <Pacpus/kernel/ComponentManager.h>
10#include <Pacpus/kernel/Log.h>
11#include <Pacpus/kernel/PacpusException.h>
12
13#include <boost/program_options/parsers.hpp>
14#include <boost/program_options/variables_map.hpp>
15#include <boost/thread/thread.hpp>
16#include <ostream>
17#include <string>
18#include <vector>
19
20namespace po = boost::program_options;
21using namespace pacpus;
22using namespace std;
23
24vector<string> convertAttributesToArgumentVector(const QDomNamedNodeMap & attributes);
25
26namespace std
27{
28
29template <typename _Elem, typename _Traits>
30std::basic_ostream<_Elem, _Traits> & operator<<(std::basic_ostream<_Elem, _Traits> & os, const boost::program_options::variables_map & vm)
31{
32 for (po::variables_map::const_iterator i = vm.begin(); i != vm.end(); ++i) {
33 const po::variable_value & v = i->second;
34 if (v.empty()) {
35 continue;
36 }
37 const type_info & type = v.value().type();
38 if (type == typeid(string)) {
39 const string & val = v.as<string>();
40 os << i->first << "=" << val;
41 } else if (type == typeid(long)) {
42 int val = v.as<long>();
43 os << i->first << "=" << val;
44 } else if (type == typeid(int)) {
45 int val = v.as<int>();
46 os << i->first << "=" << val;
47 } else if (type == typeid(unsigned long)) {
48 int val = v.as<unsigned long>();
49 os << i->first << "=" << val;
50 } else if (type == typeid(unsigned int)) {
51 int val = v.as<unsigned int>();
52 os << i->first << "=" << val;
53 } else if (type == typeid(double)) {
54 int val = v.as<double>();
55 os << i->first << "=" << val;
56 } else if (type == typeid(float)) {
57 int val = v.as<float>();
58 os << i->first << "=" << val;
59 } else if (type == typeid(bool)) {
60 int val = v.as<bool>();
61 os << i->first << "=" << val;
62 } else {
63 // unknown value type
64 os << i->first;
65 }
66 os << "\n";
67 }
68 return os;
69}
70
71} // namespace std
72
73DECLARE_STATIC_LOGGER("pacpus.core.ComponentBase");
74
75ComponentBase::ComponentBase(const QString & componentName)
76 : m_componentName(componentName)
77 , m_isActive(false)
78 , mIsRecording(true)
79 , m_manager(NULL)
80 , m_ui(NULL)
81 , m_componentState(NOT_MONITORED)
82 , mOptionsDescription("Component parameters")
83{
84 LOG_TRACE("constructor");
85 // Get a pointer on the instance of ComponentManager.
86 m_manager = ComponentManager::getInstance();
87 LOG_INFO("component " << getName() << " was created");
88
89 addParameters()
90 ("name", po::value<string>(&mName)->required(), "component name")
91 ("type", po::value<string>(&mTypeName)->required(), "component type")
92 ("ui", po::value<bool>(&mHasGui)->default_value(false), "whether to show GUI")
93 ("verbose", po::value<bool>(&mVerbose)->default_value(false), "set output verbose")
94 ("verbosity-level", po::value<int>(&mVerbosityLevel)->default_value(0), "set verbosity level")
95 ("recording", po::value<bool>(&mIsRecording)->default_value(false), "whether to record data")
96 ;
97}
98
99ComponentBase::~ComponentBase()
100{
101 LOG_TRACE("destructor");
102}
103
104bool ComponentBase::isActive() const
105{
106 return m_isActive;
107}
108
109void ComponentBase::setActive(bool isActive)
110{
111 m_isActive = isActive;
112}
113
114bool ComponentBase::isRecording() const
115{
116 return mIsRecording;
117}
118
119void ComponentBase::setRecording(bool isRecording)
120{
121 mIsRecording = isRecording;
122}
123
124const XmlComponentConfig ComponentBase::xmlParameters() const
125{
126 return param;
127}
128
129int ComponentBase::startComponent()
130{
131 if (isActive()) {
132 LOG_DEBUG("component already started, cannot (re-)start");
133 return false;
134 }
135
136 setActive(true);
137 boost::thread worker(&ComponentBase::startActivity, this);
138 //startActivity();
139 return true;
140}
141
142int ComponentBase::stopComponent()
143{
144 if (!isActive()) {
145 LOG_DEBUG("component already stopped, cannot (re-)stop");
146 return false;
147 }
148
149 setActive(false);
150 stopActivity();
151
152 return true;
153}
154
155void ComponentBase::setState(const COMPONENT_STATE state)
156{
157 m_componentState = state;
158}
159
160// FIXME: this should be const.
161ComponentBase::COMPONENT_STATE ComponentBase::getState()
162{
163 COMPONENT_STATE state = m_componentState;
164 if (ComponentBase::NOT_MONITORED != m_componentState) {
165 m_componentState = ComponentBase::MONITOR_NOK;
166 }
167 return state;
168}
169
170ComponentBase::COMPONENT_CONFIGURATION ComponentBase::configurationState() const
171{
172 return m_configurationState;
173}
174
175void ComponentBase::setConfigurationState(COMPONENT_CONFIGURATION state)
176{
177 m_configurationState = state;
178}
179
180bool ComponentBase::isConfigured() const
181{
182 return (m_configurationState == CONFIGURED_OK);
183}
184
185QString ComponentBase::getName() const
186{
187 return m_componentName;
188}
189
190ComponentBase::InputsMap & ComponentBase::inputs()
191{
192 return m_inputs;
193}
194
195const ComponentBase::InputsMap & ComponentBase::inputs() const
196{
197 return m_inputs;
198}
199
200ComponentBase::OutputsMap & ComponentBase::outputs()
201{
202 return m_outputs;
203}
204
205const ComponentBase::OutputsMap & ComponentBase::outputs() const
206{
207 return m_outputs;
208}
209
210InputInterfaceBase * ComponentBase::getInput(QString inputName) const
211{
212 if (inputs().contains(inputName)) {
213 return inputs()[inputName];
214 }
215 LOG_WARN("Component " << getName() << " does not contain input " << inputName);
216 return NULL;
217}
218
219OutputInterfaceBase * ComponentBase::getOutput(QString outputName) const
220{
221 if (outputs().contains(outputName)) {
222 return outputs()[outputName];
223 }
224 LOG_WARN("Component " << getName() << " does not contain output " << outputName);
225 return NULL;
226}
227
228bool ComponentBase::hasGui() const
229{
230 return mHasGui;
231}
232
233bool ComponentBase::isOutputVerbose() const
234{
235 return mVerbose || (getVerbosityLevel() > 0);
236}
237
238int ComponentBase::getVerbosityLevel() const
239{
240 return mVerbosityLevel;
241}
242
243po::options_description_easy_init ComponentBase::addParameters()
244{
245 return mOptionsDescription.add_options();
246}
247
248class DomElementParser
249{
250public:
251 DomElementParser(QDomElement const& args);
252
253 /** Sets options descriptions to use. */
254 DomElementParser& options(const boost::program_options::options_description& desc);
255
256 /** Parses the options and returns the result of parsing.
257 Throws on error.
258 */
259 boost::program_options::basic_parsed_options<char> run();
260
261 /** Specifies that unregistered options are allowed and should
262 be passed though. For each command like token that looks
263 like an option but does not contain a recognized name, an
264 instance of basic_option<charT> will be added to result,
265 with 'unrecognized' field set to 'true'. It's possible to
266 collect all unrecognized options with the 'collect_unrecognized'
267 funciton.
268 */
269 DomElementParser& allow_unregistered();
270
271private:
272 boost::program_options::basic_parsed_options<char> parseDomElement(
273 const QDomElement& dom_element,
274 const boost::program_options::options_description& desc,
275 bool allow_unregistered = false);
276
277private:
278 const boost::program_options::options_description* m_desc;
279 const QDomElement& m_dom_element;
280 bool m_allow_unregistered;
281};
282
283DomElementParser::DomElementParser(const QDomElement& dom_element)
284 : m_dom_element(dom_element)
285 , m_allow_unregistered(false)
286{
287}
288
289DomElementParser& DomElementParser::options(const boost::program_options::options_description& desc)
290{
291 m_desc = &desc;
292 return *this;
293}
294
295DomElementParser& DomElementParser::allow_unregistered()
296{
297 m_allow_unregistered = true;
298 return *this;
299}
300
301#include <boost/iterator/iterator_facade.hpp>
302#include <boost/program_options/errors.hpp>
303
304namespace detail
305{
306template <typename charT>
307class basic_dom_element_iterator
308 : public boost::iterator_facade<
309 basic_dom_element_iterator<charT>
310 , const boost::program_options::option
311 , boost::random_access_traversal_tag
312 >
313{
314public:
315 typedef boost::program_options::option ValueType;
316 typedef basic_dom_element_iterator<charT> self_type;
317 typedef typename self_type::iterator_facade_ base_type;
318 typedef typename self_type::difference_type difference_type;
319
320 basic_dom_element_iterator<charT>(QDomElement const& dom_element)
321 : m_dom_element(NULL)
322 , m_at_eof(true)
323 , m_i(dom_element.attributes().size())
324 {
325 }
326
327 basic_dom_element_iterator<charT>(QDomElement const& dom_element,
328 std::set<std::string> const& allowed_options,
329 bool allow_unregistered = false)
330 : m_dom_element(&dom_element)
331 , m_allowed_options(allowed_options)
332 , m_allow_unregistered(allow_unregistered)
333 , m_i(0)
334 {
335 m_attrs = m_dom_element->attributes();
336 m_at_eof = !(m_i < m_attrs.size());
337 if (!m_at_eof) {
338 get();
339 }
340 }
341
342private:
343 friend class ::boost::iterator_core_access;
344
345 bool equal(const basic_dom_element_iterator<charT>& other) const
346 {
347 if (m_at_eof && other.m_at_eof) {
348 return true;
349 }
350 return false;
351 }
352
353 void increment()
354 {
355 ++m_i;
356 m_at_eof = !(m_i < m_attrs.size());
357 if (!m_at_eof) {
358 get();
359 }
360 }
361
362 const ValueType& dereference() const
363 {
364 return m_value;
365 }
366
367 void advance(size_t n)
368 {
369 m_i += n;
370 m_at_eof = !(m_i < m_attrs.size());
371 if (!m_at_eof) {
372 get();
373 }
374 }
375
376 difference_type distance_to(const basic_dom_element_iterator<charT>& other) const
377 {
378 return other.m_i - this->m_i;
379 }
380
381private:
382 ValueType& value()
383 {
384 return m_value;
385 }
386
387 void get()
388 {
389 using namespace boost::program_options;
390
391 QDomNode node = m_attrs.item(m_i);
392 QDomAttr attr = node.toAttr();
393
394 string name = attr.name().toStdString();
395 string value = attr.value().toStdString();
396
397 bool registered = allowed_option(name);
398 if (!registered && !m_allow_unregistered) {
399 boost::throw_exception(unknown_option(name));
400 }
401
402 this->value().string_key = name;
403 this->value().value.clear();
404 this->value().value.push_back(value);
405 this->value().unregistered = !registered;
406 //this->value().original_tokens.push_back(name);
407 //this->value().original_tokens.push_back(value);
408 }
409
410 bool allowed_option(const std::string& s) const
411 {
412 set<string>::const_iterator it = m_allowed_options.find(s);
413 if (it != m_allowed_options.end()) {
414 return true;
415 }
416 return false;
417 }
418
419private:
420 const QDomElement* m_dom_element;
421 std::set<std::string> m_allowed_options;
422 bool m_allow_unregistered;
423
424 QDomNamedNodeMap m_attrs;
425 int m_i;
426 bool m_at_eof;
427 ValueType m_value;
428};
429
430typedef basic_dom_element_iterator<char> dom_element_iterator;
431typedef basic_dom_element_iterator<wchar_t> wdom_element_iterator;
432
433}
434
435boost::program_options::basic_parsed_options<char> DomElementParser::run()
436{
437 assert(m_desc);
438 return parseDomElement(m_dom_element, *m_desc, m_allow_unregistered);
439}
440
441boost::program_options::basic_parsed_options<char> DomElementParser::parseDomElement(
442 const QDomElement& dom_element,
443 const boost::program_options::options_description& desc,
444 bool allow_unregistered)
445{
446 // TODO: use XPath paths
447
448 typedef char charT;
449
450 using boost::program_options::error;
451 using boost::shared_ptr;
452 using namespace boost::program_options;
453 using ::detail::basic_dom_element_iterator;
454
455 set<string> allowed_options;
456
457 const vector<shared_ptr<option_description> >& options = desc.options();
458 for (unsigned i = 0; i < options.size(); ++i) {
459 const option_description& d = *options[i];
460
461 if (d.long_name().empty()) {
462 boost::throw_exception(
463 error("abbreviated option names are not permitted when parsing DOM elements"));
464 }
465
466 allowed_options.insert(d.long_name());
467 }
468
469 // Parser returns char strings
470 parsed_options result(&desc);
471 copy(basic_dom_element_iterator<charT>(dom_element, allowed_options, allow_unregistered),
472 basic_dom_element_iterator<charT>(dom_element),
473 back_inserter(result.options));
474
475 // Convert char strings into desired type.
476 return basic_parsed_options<charT>(result);
477}
478
479DomElementParser parseDomElement();
480
481/** Creates instance of 'command_line_parser', passes parameters to it,
482 and returns the result of calling the 'run' method.
483 */
484boost::program_options::basic_parsed_options<char>
485parseDomElement(QDomElement const& domElement, const boost::program_options::options_description&);
486
487boost::program_options::basic_parsed_options<char>
488parseDomElement(QDomElement const& domElement, const boost::program_options::options_description& desc)
489{
490 return DomElementParser(domElement)
491 .options(desc)
492 .run();
493}
494
495void ComponentBase::parseParameters(XmlComponentConfig const& cfg)
496{
497 LOG_INFO("Parsing parameters...");
498 LOG_INFO(mOptionsDescription);
499
500 po::variables_map vm;
501 try {
502 po::store(
503 DomElementParser(cfg.getDomElement())
504 .options(mOptionsDescription)
505 .allow_unregistered() // FIXME: temporary only, at term all the components specify all parameters
506 .run()
507 , vm);
508 po::notify(vm);
509 } catch (po::error& e) {
510 LOG_WARN(e.what());
511 throw PacpusException(e.what());
512 }
513
514 LOG_INFO("Parsed parameter values:\n" << vm);
515}
516
517vector<string> convertAttributesToArgumentVector(const QDomNamedNodeMap & attributes)
518{
519 vector<string> xargs;
520 xargs.reserve(attributes.size());
521
522 for (int i = 0; i < attributes.size(); ++i) {
523 QDomAttr parameter = attributes.item(i).toAttr();
524 if (parameter.isNull()) {
525 LOG_WARN("node is not a parameter");
526 continue;
527 }
528
529 QString arg = QString("--") + parameter.name() + "=";
530
531 bool shouldAddQuotes = parameter.value().contains(' ');
532 if (shouldAddQuotes) {
533 arg += '\"';
534 arg += parameter.value();
535 arg += '\"';
536 } else {
537 arg += parameter.value();
538 }
539
540 LOG_DEBUG("parameter: " << arg);
541 xargs.push_back(arg.toStdString());
542 }
543
544 return xargs;
545}
Note: See TracBrowser for help on using the repository browser.