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

Last change on this file was 349, checked in by DHERBOMEZ Gérald, 9 years ago

build of the trunk (release 0.2.x) under Linux Mint 17.2

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