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

Last change on this file since 374 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
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/bind/bind.hpp>
14#include <boost/exception/detail/exception_ptr.hpp>
15#include <boost/exception/diagnostic_information.hpp>
16#include <boost/exception/exception.hpp>
17#include <boost/program_options/parsers.hpp>
18#include <boost/program_options/variables_map.hpp>
19#include <ostream>
20#include <string>
21#include <vector>
22
23namespace po = boost::program_options;
24using namespace pacpus;
25using namespace std;
26
27//vector<string> convertAttributesToArgumentVector(QDomNamedNodeMap const& attributes);
28
29namespace std
30{
31
32template <typename _Elem, typename _Traits>
33std::basic_ostream<_Elem, _Traits>& operator<<(std::basic_ostream<_Elem, _Traits>& os, boost::program_options::variables_map const& vm)
34{
35 for (po::variables_map::const_iterator i = vm.begin(); i != vm.end(); ++i) {
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;
65 } else {
66 // unknown value type
67 os << i->first;
68 }
69 os << "\n";
70 }
71 return os;
72}
73
74} // namespace std
75
76DECLARE_STATIC_LOGGER("pacpus.core.ComponentBase");
77
78ComponentBase::ComponentBase(QString const& componentName)
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")
86{
87 LOG_TRACE("constructor");
88
89 // Get a pointer on the instance of ComponentManager.
90 m_manager = ComponentManager::getInstance();
91 LOG_INFO("component " << getName() << " was created");
92
93 addParameter("name", value<string>(&mName)->required(), "component name");
94 addParameter("type", value<string>(&mTypeName)->required(), "component type");
95 addParameters()
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")
102 ;
103}
104
105ComponentBase::~ComponentBase()
106{
107 LOG_TRACE("destructor");
108}
109
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{
122 return mIsRecording;
123}
124
125void ComponentBase::setRecording(bool isRecording)
126{
127 mIsRecording = isRecording;
128}
129
130const XmlComponentConfig ComponentBase::xmlParameters() const
131{
132 return param;
133}
134
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//}
165
166int ComponentBase::startComponent()
167{
168 if (isActive()) {
169 LOG_DEBUG("component already started, cannot (re-)start");
170 return false;
171 }
172
173 setActive(true);
174 //boost::thread worker(&ComponentBase::startComponentInThread, this);
175 startActivity();
176 //moveToThread(&mThread);
177 //mThread.start();
178 return true;
179}
180
181int ComponentBase::stopComponent()
182{
183 if (!isActive()) {
184 LOG_DEBUG("component already stopped, cannot (re-)stop");
185 return false;
186 }
187
188 setActive(false);
189 stopActivity();
190 //QMetaObject::invokeMethod(&mThread, "quit");
191 return true;
192}
193
194void ComponentBase::setState(const COMPONENT_STATE state)
195{
196 m_componentState = state;
197}
198
199// FIXME: this should be const.
200ComponentBase::COMPONENT_STATE ComponentBase::getState()
201{
202 COMPONENT_STATE state = m_componentState;
203 if (ComponentBase::NOT_MONITORED != m_componentState) {
204 m_componentState = ComponentBase::MONITOR_NOK;
205 }
206 return state;
207}
208
209// FIXME: this should be const.
210ComponentBase::COMPONENT_STATE ComponentBase::state()
211{
212 return getState();
213}
214
215
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
226bool ComponentBase::isConfigured() const
227{
228 return (m_configurationState == CONFIGURED_OK);
229}
230
231QString ComponentBase::getName() const
232{
233 return m_componentName;
234}
235
236QString ComponentBase::name() const
237{
238 return getName();
239}
240
241ComponentBase::InputsMap & ComponentBase::inputs()
242{
243 return m_inputs;
244}
245
246const ComponentBase::InputsMap & ComponentBase::inputs() const
247{
248 return m_inputs;
249}
250
251ComponentBase::OutputsMap & ComponentBase::outputs()
252{
253 return m_outputs;
254}
255
256const ComponentBase::OutputsMap & ComponentBase::outputs() const
257{
258 return m_outputs;
259}
260
261InputInterfaceBase* ComponentBase::getInput(QString inputName) const
262{
263 if (inputs().contains(inputName)) {
264 return inputs()[inputName].get();
265 }
266 LOG_WARN("Component " << getName() << " does not contain input " << inputName);
267 return NULL;
268}
269
270OutputInterfaceBase* ComponentBase::getOutput(QString outputName) const
271{
272 if (outputs().contains(outputName)) {
273 return outputs()[outputName].get();
274 }
275 LOG_WARN("Component " << getName() << " does not contain output " << outputName);
276 return NULL;
277}
278
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
294po::options_description_easy_init ComponentBase::addParameters()
295{
296 return mOptionsDescription.add_options();
297}
298
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
314class DomElementParser
315 : boost::noncopyable
316{
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:
345 boost::program_options::options_description const* m_desc;
346 QDomElement const& m_dom_element;
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;
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;
386
387 basic_dom_element_iterator<charT>(QDomElement const& dom_element)
388 : m_dom_element(NULL)
389 , m_at_eof(true)
390 , m_i(dom_element.attributes().size())
391 {
392 }
393
394 basic_dom_element_iterator<charT>(QDomElement const& dom_element,
395 std::set<std::string> const& allowed_options,
396 bool allow_unregistered = false)
397 : m_dom_element(&dom_element)
398 , m_allowed_options(allowed_options)
399 , m_allow_unregistered(allow_unregistered)
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
409private:
410 friend class ::boost::iterator_core_access;
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
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
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;
473 //this->value().original_tokens.push_back(name);
474 //this->value().original_tokens.push_back(value);
475 }
476
477 bool allowed_option(const std::string& s) const
478 {
479 set<string>::const_iterator it = m_allowed_options.find(s);
480 if (it != m_allowed_options.end()) {
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{
513 // TODO: use XPath paths
514
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),
539 basic_dom_element_iterator<charT>(dom_element),
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{
564 LOG_INFO("Parsing parameters...");
565 LOG_INFO(mOptionsDescription);
566
567 po::variables_map vm;
568 try {
569 po::store(
570 DomElementParser(cfg.getDomElement())
571 .options(mOptionsDescription)
572 .allow_unregistered() // FIXME: temporary only, at term all the components specify all parameters
573 .run()
574 , vm);
575 po::notify(vm);
576 } catch (po::error& e) {
577 LOG_WARN(e.what());
578 BOOST_THROW_EXCEPTION(PacpusException(e.what()));
579 }
580
581 LOG_INFO("Parsed parameter values:\n" << vm);
582}
583
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.