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

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

ComponentBase: added addParameter.

  • Property svn:executable set to *
File size: 16.8 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
209ComponentBase::COMPONENT_CONFIGURATION ComponentBase::configurationState() const
210{
211 return m_configurationState;
212}
213
214void ComponentBase::setConfigurationState(COMPONENT_CONFIGURATION state)
215{
216 m_configurationState = state;
217}
218
219bool ComponentBase::isConfigured() const
220{
221 return (m_configurationState == CONFIGURED_OK);
222}
223
224QString ComponentBase::getName() const
225{
226 return m_componentName;
227}
228
229ComponentBase::InputsMap & ComponentBase::inputs()
230{
231 return m_inputs;
232}
233
234const ComponentBase::InputsMap & ComponentBase::inputs() const
235{
236 return m_inputs;
237}
238
239ComponentBase::OutputsMap & ComponentBase::outputs()
240{
241 return m_outputs;
242}
243
244const ComponentBase::OutputsMap & ComponentBase::outputs() const
245{
246 return m_outputs;
247}
248
249InputInterfaceBase* ComponentBase::getInput(QString inputName) const
250{
251 if (inputs().contains(inputName)) {
252 return inputs()[inputName].get();
253 }
254 LOG_WARN("Component " << getName() << " does not contain input " << inputName);
255 return NULL;
256}
257
258OutputInterfaceBase* ComponentBase::getOutput(QString outputName) const
259{
260 if (outputs().contains(outputName)) {
261 return outputs()[outputName].get();
262 }
263 LOG_WARN("Component " << getName() << " does not contain output " << outputName);
264 return NULL;
265}
266
267bool ComponentBase::hasGui() const
268{
269 return mHasGui;
270}
271
272bool ComponentBase::isOutputVerbose() const
273{
274 return mVerbose || (getVerbosityLevel() > 0);
275}
276
277int ComponentBase::getVerbosityLevel() const
278{
279 return mVerbosityLevel;
280}
281
282po::options_description_easy_init ComponentBase::addParameters()
283{
284 return mOptionsDescription.add_options();
285}
286
287void ComponentBase::addParameter(const char* name, const char* description)
288{
289 addParameters()(name, description);
290}
291
292void ComponentBase::addParameter(const char* name, const po::value_semantic* s)
293{
294 addParameters()(name, s);
295}
296
297void ComponentBase::addParameter(const char* name, const po::value_semantic* s, const char* description)
298{
299 addParameters()(name, s, description);
300}
301
302class DomElementParser
303 : boost::noncopyable
304{
305public:
306 DomElementParser(QDomElement const& args);
307
308 /** Sets options descriptions to use. */
309 DomElementParser& options(const boost::program_options::options_description& desc);
310
311 /** Parses the options and returns the result of parsing.
312 Throws on error.
313 */
314 boost::program_options::basic_parsed_options<char> run();
315
316 /** Specifies that unregistered options are allowed and should
317 be passed though. For each command like token that looks
318 like an option but does not contain a recognized name, an
319 instance of basic_option<charT> will be added to result,
320 with 'unrecognized' field set to 'true'. It's possible to
321 collect all unrecognized options with the 'collect_unrecognized'
322 funciton.
323 */
324 DomElementParser& allow_unregistered();
325
326private:
327 boost::program_options::basic_parsed_options<char> parseDomElement(
328 const QDomElement& dom_element,
329 const boost::program_options::options_description& desc,
330 bool allow_unregistered = false);
331
332private:
333 boost::program_options::options_description const* m_desc;
334 QDomElement const& m_dom_element;
335 bool m_allow_unregistered;
336};
337
338DomElementParser::DomElementParser(const QDomElement& dom_element)
339 : m_dom_element(dom_element)
340 , m_allow_unregistered(false)
341{
342}
343
344DomElementParser& DomElementParser::options(const boost::program_options::options_description& desc)
345{
346 m_desc = &desc;
347 return *this;
348}
349
350DomElementParser& DomElementParser::allow_unregistered()
351{
352 m_allow_unregistered = true;
353 return *this;
354}
355
356#include <boost/iterator/iterator_facade.hpp>
357#include <boost/program_options/errors.hpp>
358
359namespace detail
360{
361template <typename charT>
362class basic_dom_element_iterator
363 : public boost::iterator_facade<
364 basic_dom_element_iterator<charT>
365 , const boost::program_options::option
366 , boost::random_access_traversal_tag
367 >
368{
369public:
370 typedef boost::program_options::option ValueType;
371 typedef basic_dom_element_iterator<charT> self_type;
372 typedef typename self_type::iterator_facade_ base_type;
373 typedef typename self_type::difference_type difference_type;
374
375 basic_dom_element_iterator<charT>(QDomElement const& dom_element)
376 : m_dom_element(NULL)
377 , m_at_eof(true)
378 , m_i(dom_element.attributes().size())
379 {
380 }
381
382 basic_dom_element_iterator<charT>(QDomElement const& dom_element,
383 std::set<std::string> const& allowed_options,
384 bool allow_unregistered = false)
385 : m_dom_element(&dom_element)
386 , m_allowed_options(allowed_options)
387 , m_allow_unregistered(allow_unregistered)
388 , m_i(0)
389 {
390 m_attrs = m_dom_element->attributes();
391 m_at_eof = !(m_i < m_attrs.size());
392 if (!m_at_eof) {
393 get();
394 }
395 }
396
397private:
398 friend class ::boost::iterator_core_access;
399
400 bool equal(const basic_dom_element_iterator<charT>& other) const
401 {
402 if (m_at_eof && other.m_at_eof) {
403 return true;
404 }
405 return false;
406 }
407
408 void increment()
409 {
410 ++m_i;
411 m_at_eof = !(m_i < m_attrs.size());
412 if (!m_at_eof) {
413 get();
414 }
415 }
416
417 const ValueType& dereference() const
418 {
419 return m_value;
420 }
421
422 void advance(size_t n)
423 {
424 m_i += n;
425 m_at_eof = !(m_i < m_attrs.size());
426 if (!m_at_eof) {
427 get();
428 }
429 }
430
431 difference_type distance_to(const basic_dom_element_iterator<charT>& other) const
432 {
433 return other.m_i - this->m_i;
434 }
435
436private:
437 ValueType& value()
438 {
439 return m_value;
440 }
441
442 void get()
443 {
444 using namespace boost::program_options;
445
446 QDomNode node = m_attrs.item(m_i);
447 QDomAttr attr = node.toAttr();
448
449 string name = attr.name().toStdString();
450 string value = attr.value().toStdString();
451
452 bool registered = allowed_option(name);
453 if (!registered && !m_allow_unregistered) {
454 boost::throw_exception(unknown_option(name));
455 }
456
457 this->value().string_key = name;
458 this->value().value.clear();
459 this->value().value.push_back(value);
460 this->value().unregistered = !registered;
461 //this->value().original_tokens.push_back(name);
462 //this->value().original_tokens.push_back(value);
463 }
464
465 bool allowed_option(const std::string& s) const
466 {
467 set<string>::const_iterator it = m_allowed_options.find(s);
468 if (it != m_allowed_options.end()) {
469 return true;
470 }
471 return false;
472 }
473
474private:
475 const QDomElement* m_dom_element;
476 std::set<std::string> m_allowed_options;
477 bool m_allow_unregistered;
478
479 QDomNamedNodeMap m_attrs;
480 int m_i;
481 bool m_at_eof;
482 ValueType m_value;
483};
484
485typedef basic_dom_element_iterator<char> dom_element_iterator;
486typedef basic_dom_element_iterator<wchar_t> wdom_element_iterator;
487
488}
489
490boost::program_options::basic_parsed_options<char> DomElementParser::run()
491{
492 assert(m_desc);
493 return parseDomElement(m_dom_element, *m_desc, m_allow_unregistered);
494}
495
496boost::program_options::basic_parsed_options<char> DomElementParser::parseDomElement(
497 const QDomElement& dom_element,
498 const boost::program_options::options_description& desc,
499 bool allow_unregistered)
500{
501 // TODO: use XPath paths
502
503 typedef char charT;
504
505 using boost::program_options::error;
506 using boost::shared_ptr;
507 using namespace boost::program_options;
508 using ::detail::basic_dom_element_iterator;
509
510 set<string> allowed_options;
511
512 const vector<shared_ptr<option_description> >& options = desc.options();
513 for (unsigned i = 0; i < options.size(); ++i) {
514 const option_description& d = *options[i];
515
516 if (d.long_name().empty()) {
517 boost::throw_exception(
518 error("abbreviated option names are not permitted when parsing DOM elements"));
519 }
520
521 allowed_options.insert(d.long_name());
522 }
523
524 // Parser returns char strings
525 parsed_options result(&desc);
526 copy(basic_dom_element_iterator<charT>(dom_element, allowed_options, allow_unregistered),
527 basic_dom_element_iterator<charT>(dom_element),
528 back_inserter(result.options));
529
530 // Convert char strings into desired type.
531 return basic_parsed_options<charT>(result);
532}
533
534DomElementParser parseDomElement();
535
536/** Creates instance of 'command_line_parser', passes parameters to it,
537 and returns the result of calling the 'run' method.
538 */
539boost::program_options::basic_parsed_options<char>
540parseDomElement(QDomElement const& domElement, const boost::program_options::options_description&);
541
542boost::program_options::basic_parsed_options<char>
543parseDomElement(QDomElement const& domElement, const boost::program_options::options_description& desc)
544{
545 return DomElementParser(domElement)
546 .options(desc)
547 .run();
548}
549
550void ComponentBase::parseParameters(XmlComponentConfig const& cfg)
551{
552 LOG_INFO("Parsing parameters...");
553 LOG_INFO(mOptionsDescription);
554
555 po::variables_map vm;
556 try {
557 po::store(
558 DomElementParser(cfg.getDomElement())
559 .options(mOptionsDescription)
560 .allow_unregistered() // FIXME: temporary only, at term all the components specify all parameters
561 .run()
562 , vm);
563 po::notify(vm);
564 } catch (po::error& e) {
565 LOG_WARN(e.what());
566 BOOST_THROW_EXCEPTION(PacpusException(e.what()));
567 }
568
569 LOG_INFO("Parsed parameter values:\n" << vm);
570}
571
572//vector<string> convertAttributesToArgumentVector(const QDomNamedNodeMap & attributes)
573//{
574// vector<string> xargs;
575// xargs.reserve(attributes.size());
576//
577// for (int i = 0; i < attributes.size(); ++i) {
578// QDomAttr parameter = attributes.item(i).toAttr();
579// if (parameter.isNull()) {
580// LOG_WARN("node is not a parameter");
581// continue;
582// }
583//
584// QString arg = QString("--") + parameter.name() + "=";
585//
586// bool shouldAddQuotes = parameter.value().contains(' ');
587// if (shouldAddQuotes) {
588// arg += '\"';
589// arg += parameter.value();
590// arg += '\"';
591// } else {
592// arg += parameter.value();
593// }
594//
595// LOG_DEBUG("parameter: " << arg);
596// xargs.push_back(arg.toStdString());
597// }
598//
599// return xargs;
600//}
Note: See TracBrowser for help on using the repository browser.