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
RevLine 
[89]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>
[182]8
[89]9#include <Pacpus/kernel/ComponentManager.h>
10#include <Pacpus/kernel/Log.h>
[201]11#include <Pacpus/kernel/PacpusException.h>
[89]12
[176]13#include <boost/program_options/parsers.hpp>
14#include <boost/program_options/variables_map.hpp>
[279]15#include <boost/thread/thread.hpp>
[202]16#include <ostream>
[176]17#include <string>
18#include <vector>
19
20namespace po = boost::program_options;
[89]21using namespace pacpus;
[176]22using namespace std;
[89]23
[182]24vector<string> convertAttributesToArgumentVector(const QDomNamedNodeMap & attributes);
[176]25
[272]26namespace std
27{
[202]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{
[231]32 for (po::variables_map::const_iterator i = vm.begin(); i != vm.end(); ++i) {
[202]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;
[263]62 } else {
63 // unknown value type
64 os << i->first;
65 }
[204]66 os << "\n";
[202]67 }
68 return os;
69}
70
71} // namespace std
72
[89]73DECLARE_STATIC_LOGGER("pacpus.core.ComponentBase");
74
[182]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")
[89]83{
84 LOG_TRACE("constructor");
85 // Get a pointer on the instance of ComponentManager.
[152]86 m_manager = ComponentManager::getInstance();
[176]87 LOG_INFO("component " << getName() << " was created");
88
[179]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")
[176]96 ;
[89]97}
98
99ComponentBase::~ComponentBase()
100{
101 LOG_TRACE("destructor");
102}
103
[152]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{
[177]116 return mIsRecording;
[152]117}
118
119void ComponentBase::setRecording(bool isRecording)
120{
[177]121 mIsRecording = isRecording;
[152]122}
123
124const XmlComponentConfig ComponentBase::xmlParameters() const
125{
126 return param;
127}
128
[89]129int ComponentBase::startComponent()
130{
[152]131 if (isActive()) {
132 LOG_DEBUG("component already started, cannot (re-)start");
133 return false;
134 }
135
136 setActive(true);
[279]137 boost::thread worker(&ComponentBase::startActivity, this);
138 //startActivity();
[89]139 return true;
140}
141
142int ComponentBase::stopComponent()
143{
[152]144 if (!isActive()) {
145 LOG_DEBUG("component already stopped, cannot (re-)stop");
146 return false;
147 }
148
149 setActive(false);
[89]150 stopActivity();
151
152 return true;
153}
154
155void ComponentBase::setState(const COMPONENT_STATE state)
156{
[152]157 m_componentState = state;
[89]158}
159
160// FIXME: this should be const.
161ComponentBase::COMPONENT_STATE ComponentBase::getState()
162{
[152]163 COMPONENT_STATE state = m_componentState;
164 if (ComponentBase::NOT_MONITORED != m_componentState) {
165 m_componentState = ComponentBase::MONITOR_NOK;
[89]166 }
167 return state;
168}
169
[152]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
[89]180bool ComponentBase::isConfigured() const
181{
[152]182 return (m_configurationState == CONFIGURED_OK);
[89]183}
184
185QString ComponentBase::getName() const
186{
[152]187 return m_componentName;
[89]188}
189
[152]190ComponentBase::InputsMap & ComponentBase::inputs()
[89]191{
[152]192 return m_inputs;
193}
[89]194
[152]195const ComponentBase::InputsMap & ComponentBase::inputs() const
196{
197 return m_inputs;
[89]198}
199
[152]200ComponentBase::OutputsMap & ComponentBase::outputs()
[89]201{
[152]202 return m_outputs;
203}
[89]204
[152]205const ComponentBase::OutputsMap & ComponentBase::outputs() const
206{
207 return m_outputs;
[89]208}
[120]209
[152]210InputInterfaceBase * ComponentBase::getInput(QString inputName) const
[120]211{
[152]212 if (inputs().contains(inputName)) {
213 return inputs()[inputName];
214 }
[176]215 LOG_WARN("Component " << getName() << " does not contain input " << inputName);
[152]216 return NULL;
[120]217}
218
[152]219OutputInterfaceBase * ComponentBase::getOutput(QString outputName) const
[120]220{
[152]221 if (outputs().contains(outputName)) {
222 return outputs()[outputName];
223 }
[206]224 LOG_WARN("Component " << getName() << " does not contain output " << outputName);
[152]225 return NULL;
[120]226}
[176]227
[181]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
[176]243po::options_description_easy_init ComponentBase::addParameters()
244{
245 return mOptionsDescription.add_options();
246}
247
[270]248class DomElementParser
[176]249{
[270]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;
[276]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;
[270]319
[278]320 basic_dom_element_iterator<charT>(QDomElement const& dom_element)
[270]321 : m_dom_element(NULL)
322 , m_at_eof(true)
[278]323 , m_i(dom_element.attributes().size())
[270]324 {
325 }
326
[278]327 basic_dom_element_iterator<charT>(QDomElement const& dom_element,
328 std::set<std::string> const& allowed_options,
[270]329 bool allow_unregistered = false)
330 : m_dom_element(&dom_element)
331 , m_allowed_options(allowed_options)
[271]332 , m_allow_unregistered(allow_unregistered)
[270]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
[271]342private:
343 friend class ::boost::iterator_core_access;
[270]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
[274]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
[270]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;
[275]406 //this->value().original_tokens.push_back(name);
407 //this->value().original_tokens.push_back(value);
[270]408 }
409
410 bool allowed_option(const std::string& s) const
411 {
[278]412 set<string>::const_iterator it = m_allowed_options.find(s);
413 if (it != m_allowed_options.end()) {
[270]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{
[271]446 // TODO: use XPath paths
447
[270]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),
[278]472 basic_dom_element_iterator<charT>(dom_element),
[270]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{
[176]497 LOG_INFO("Parsing parameters...");
498 LOG_INFO(mOptionsDescription);
499
[201]500 po::variables_map vm;
[176]501 try {
502 po::store(
[270]503 DomElementParser(cfg.getDomElement())
[176]504 .options(mOptionsDescription)
[180]505 .allow_unregistered() // FIXME: temporary only, at term all the components specify all parameters
[176]506 .run()
507 , vm);
508 po::notify(vm);
[270]509 } catch (po::error& e) {
[201]510 LOG_WARN(e.what());
511 throw PacpusException(e.what());
[176]512 }
513
[204]514 LOG_INFO("Parsed parameter values:\n" << vm);
[176]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.