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

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

Fixed: problems with basic_dom_element_iterator on Unix

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