RSB  0.17.0
ParticipantConfig.cpp
Go to the documentation of this file.
1 /* ============================================================
2  *
3  * This file is a part of the RSB project.
4  *
5  * Copyright (C) 2011 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
6  *
7  * This file may be licensed under the terms of the
8  * GNU Lesser General Public License Version 3 (the ``LGPL''),
9  * or (at your option) any later version.
10  *
11  * Software distributed under the License is distributed
12  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13  * express or implied. See the LGPL for the specific language
14  * governing rights and limitations.
15  *
16  * You should have received a copy of the LGPL along with this
17  * program. If not, go to http://www.gnu.org/licenses/lgpl.html
18  * or write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The development of this software was supported by:
22  * CoR-Lab, Research Institute for Cognition and Robotics
23  * Bielefeld University
24  *
25  * ============================================================ */
26 
27 #include "ParticipantConfig.h"
28 
29 #include <stdexcept>
30 #include <fstream>
31 
32 #include <boost/format.hpp>
33 #include <boost/filesystem/fstream.hpp>
34 
35 #include <rsc/logging/Logger.h>
36 
37 using namespace std;
38 
39 using namespace boost;
40 using namespace boost::filesystem;
41 
42 using namespace rsc::config;
43 using namespace rsc::logging;
44 using namespace rsc::runtime;
45 
46 namespace rsb {
47 
48 ParticipantConfig::Transport::Transport(const string& name,
49  bool enabled) :
50  name(name) {
51  if (name.empty()) {
52  throw invalid_argument(
53  "The name of a transport configuration cannot be empty.");
54  }
55  if (!enabled) {
56  setEnabled(false);
57  }
58 }
59 
61 }
62 
64  return name;
65 }
66 
68  return this->converters;
69 }
70 
71 rsc::runtime::Properties ParticipantConfig::Transport::getOptions() const {
72  return this->options;
73 }
74 
75 rsc::runtime::Properties& ParticipantConfig::Transport::mutableOptions() {
76  return this->options;
77 }
78 
79 
81  this->options = options;
82 }
83 
85  return this->getOptions().getAs<bool> ("enabled", true);
86 }
87 
89  Properties options = this->getOptions();
90  options["enabled"] = lexical_cast<string>(value);
91  setOptions(options);
92 }
93 
94 void ParticipantConfig::Transport::handleOption(const vector<string>& key,
95  const string& value) {
96  if ((key.size() >= 2)
97  && (key[0] == "converter")
98  && (key[1] == "cpp")) {
99  if (key.size() != 3) {
100  throw invalid_argument(
101  str(
102  format(
103  "Option key `%1%' has invalid number of components; converter-related keys for transports has to have three components")
104  % key));
105  }
106  this->converters.insert(make_pair(key[2], value));
107  } else if ((key.size() >= 2) && (key[0] == "converter")) {
108  // ignore converters for other languages
109  } else {
110  if (key.size() != 1) {
111  throw invalid_argument(
112  str(
113  format(
114  "Key `%1%' has invalid number of components; transport option keys have to have one component.")
115  % key));
116  }
117  this->options[key[0]] = value;
118  }
119 }
120 
122  return name == other.name;
123 }
124 
126  return name < other.name;
127 }
128 
130  return "Transport";
131 }
132 
133 void ParticipantConfig::Transport::printContents(ostream& stream) const {
134  stream << "name = " << this->name
135  << ", converters = " << this->converters
136  << ", options = " << this->options;
137 }
138 
140  name(name) {
141 }
142 
144  return this->name;
145 }
146 
148  this->name = name;
149 }
150 
152  return this->options;
153 }
154 
156  return this->options;
157 }
158 
160  this->options = options;
161 }
162 
164  const string& value) {
165  if (key.size() != 1) {
166  throw invalid_argument(str(format("Key `%1%' has invalid number of components; transport option keys have to have one component.")
167  % key));
168  }
169 
170  this->options.set<string>(key.front(), value);
171 }
172 
174  stream << "name = " << this->name
175  << ", options = " << this->options;
176 }
177 
179  logger(Logger::getLogger("rsb.ParticipantConfig")),
181  eventReceivingStrategy("parallel"),
182  eventSendingStrategy("direct"),
183  introspection(true) {
184 }
185 
187 }
188 
190  return qosSpec;
191 }
192 
194  return qosSpec;
195 }
196 
198  const QualityOfServiceSpec& spec) {
199  this->qosSpec = spec;
200 }
201 
203  return errorStrategy;
204 }
205 
207  this->errorStrategy = strategy;
208 }
209 
211  map<string, Transport>::const_iterator it = this->transports.find(name);
212  if (it == this->transports.end()) {
213  throw rsc::runtime::NoSuchObject(name);
214  }
215  return it->second;
216 }
217 
219  map<string, Transport>::iterator it = this->transports.find(name);
220  if (it == this->transports.end()) {
221  throw rsc::runtime::NoSuchObject(name);
222  }
223  return it->second;
224 }
225 
226 set<ParticipantConfig::Transport> ParticipantConfig::getTransports(
227  bool includeDisabled) const {
228  set<Transport> result;
229  for (map<string, Transport>::const_iterator it = this->transports.begin(); it
230  != this->transports.end(); ++it) {
231  if (it->second.isEnabled() || includeDisabled) {
232  result.insert(it->second);
233  } else {
234  RSCDEBUG(logger, "Skipping disabled transport " << it->second);
235  }
236  }
237  return result;
238 }
239 
241  transports.erase(transport.getName());
242  transports.insert(make_pair(transport.getName(), transport));
243 }
244 
246  transports.erase(transport.getName());
247 }
248 
249 void ParticipantConfig::setTransports(const set<Transport>& transports) {
250  this->transports.clear();
251  for (set<Transport>::const_iterator it = transports.begin(); it
252  != transports.end(); ++it) {
253  this->transports.insert(make_pair(it->getName(), *it));
254  }
255 }
256 
258  return this->eventReceivingStrategy;
259 }
260 
262  return this->eventReceivingStrategy;
263 }
264 
266  return this->eventSendingStrategy;
267 }
268 
270  return this->introspection;
271 }
272 
274  this->introspection = newValue;
275 }
276 
277 
278 rsc::runtime::Properties ParticipantConfig::getOptions() const {
279  return options;
280 }
281 
282 rsc::runtime::Properties& ParticipantConfig::mutableOptions() {
283  return options;
284 }
285 
286 void ParticipantConfig::setOptions(const Properties& options) {
287  this->options = options;
288 }
289 
290 void ParticipantConfig::handleOption(const vector<string>& key,
291  const string& value) {
292  // Quality of Service
293  if (key[0] == "qualityofservice") {
294  if (key.size() != 2) {
295  throw invalid_argument(
296  str(
297  format(
298  "Option key `%1%' has invalid number of components; options related to quality of service have to have two components.")
299  % key));
300  }
301  if (key[1] == "reliability") {
302  if (value == "UNRELIABLE") {
304  } else if (value == "RELIABLE") {
306  } else
307  throw invalid_argument(str(format(
308  "The value `%1%' is invalid for the key `%2%'.")
309  % value % key));
310  } else if (key[1] == "ordering") {
311  if (value == "UNORDERED") {
313  } else if (value == "ORDERED") {
315  } else
316  throw invalid_argument(str(format(
317  "The value `%1%' is invalid for the key `%2%'.")
318  % value % key));
319  }
320  // Error handling
321  } else if (key[0] == "errorhandling") {
322  if (key[1] == "onhandlererror") {
323  if (value == "LOG") {
325  } else if (value == "PRINT") {
327  } else if (value == "EXIT") {
329  } else {
330  throw invalid_argument(str(format(
331  "The value `%1%' is invalid for the key `%2%'.")
332  % value % key));
333  }
334  }
335  // Event processing
336  } else if (key[0] == "eventprocessing") {
337  EventProcessingStrategy* strategy;
338  if (key[1] == "receivingstrategy") {
339  strategy = &this->eventReceivingStrategy;
340  } else if (key[1] == "sendingstrategy") {
341  strategy = &this->eventSendingStrategy;
342  } else {
343  throw invalid_argument(
344  str(format("`%2%' is not a valid sub-key of `%1%'.")
345  % key[0] % key[1]));
346  }
347  if (key.size() == 2) {
348  strategy->setName(value);
349  } else {
350  vector<string> subKey;
351  copy(key.begin() + 2, key.end(), back_inserter(subKey));
352  strategy->handleOption(subKey, value);
353  }
354 
355  // Introspection
356  } else if (key[0] == "introspection") {
357  if ((key.size() == 2) && (key[1] == "enabled")) {
358  this->introspection = lexical_cast<bool>(value);
359  }
360 
361  // Transports
362  } else if (key[0] == "transport") {
363  if (key.size() < 3) {
364  throw invalid_argument(
365  str(
366  format(
367  "Option key `%1%' has invalid number of components; transport-related keys have to have at least three components.")
368  % key));
369  }
370  map<string, Transport>::iterator it = this->transports.find(key[1]);
371  if (it == this->transports.end()) {
372  addTransport(Transport(key[1]));
373  it = this->transports.find(key[1]);
374  }
375  Transport& transport = it->second;
376  vector<string> subKey;
377  copy(key.begin() + 2, key.end(), back_inserter(subKey));
378  transport.handleOption(subKey, value);
379  // Global (participant-wide) options
380  } else {
381  if (key.size() == 1) {
382  this->options[key[0]] = value;
383  }
384  }
385 }
386 
387 void ParticipantConfig::printContents(std::ostream& stream) const {
388  stream << "qosSpec = " << this->qosSpec
389  << ", errorStrategy = " << this->errorStrategy
390  << ", transports = " << this->getTransports(true)
391  << ", eventReceivingStrategy = " << this->eventReceivingStrategy
392  << ", eventSendingStrategy = " << this->eventSendingStrategy
393  << ", options = " << this->options;
394 }
395 
396 }
void setOptions(const rsc::runtime::Properties &options)
Sets the additional options besides the transport-specific ones.
Specification of desired quality of service settings for sending and receiving events.
void setQualityOfServiceSpec(const QualityOfServiceSpec &spec)
Sets the desired QoS settings.
QualityOfServiceSpec qosSpec
Uses stderr for printing a message.
rsc::runtime::Properties getOptions() const
Returns the specified options for the transport.
rsc::runtime::Properties getOptions() const
Returns additional options besides the transport-specific ones.
rsc::runtime::Properties & mutableOptions()
Returns the options for the transport.
bool operator==(const Transport &other) const
Every listener receives the events of one informer in the order the informer sent the events...
void handleOption(const std::vector< std::string > &key, const std::string &value)
QualityOfServiceSpec & mutableQualityOfServiceSpec()
Returns mutable quality of service settings.
EventProcessingStrategy eventSendingStrategy
ErrorStrategy getErrorStrategy() const
Returns the selected error strategy for the configured participant.
std::string getName() const
Returns the name of the implementation to be selected.
std::string getName() const
Returns the name of this transport description.
EventProcessingStrategy eventReceivingStrategy
STL namespace.
rsc::runtime::Properties getOptions() const
Returns the options for the strategy.
void handleOption(const std::vector< std::string > &key, const std::string &value)
rsc::logging::LoggerPtr logger
void printContents(std::ostream &stream) const
Events may be dropped and not be visible to a listener.
void addTransport(const Transport &transport)
Adds a transport to the list of desired transport mechanisms.
ConverterNames getConverters() const
void setName(const std::string &name)
Sets the name of the implementation to be selected.
rsc::runtime::Properties options
EventProcessingStrategy & mutableEventReceivingStrategy()
void setOptions(const rsc::runtime::Properties &options)
Sets the options for the strategy.
rsc::runtime::Properties options
bool isIntrospectionEnabled() const
Indicates whether introspection should be enabled for the participant.
rsc::runtime::Properties & mutableOptions()
Returns the options for the strategy.
const EventProcessingStrategy & getEventReceivingStrategy() const
Description of a desired transport.
rsc::runtime::Properties & mutableOptions()
Returns a mutable reference to the freestyle options in this configuration.
bool operator<(const Transport &other) const
void removeTransport(const Transport &transport)
Removes a transport from the list of desired transports if it was present.
void printContents(std::ostream &stream) const
void setTransports(const std::set< Transport > &transports)
Replaces all existing transports with the ones given here.
The events are delivered in arbitrary order.
ErrorStrategy
Possible error handling strategies in user-provided code like event handlers.
Logs a message using the logging mechanism.
QualityOfServiceSpec getQualityOfServiceSpec() const
Returns the current settings for QoS.
Transport & mutableTransport(const std::string &name)
Returns a single configured transport which can be modified in place.
Instances of this class describe the selection and configuration of an event processing strategy...
void setIsIntrospectionEnabled(bool newValue)
Controls whether introspection should be enabled for the participant.
void setErrorStrategy(const ErrorStrategy &strategy)
Sets the desired error strategy for the participant.
void handleOption(const std::vector< std::string > &key, const std::string &value)
const EventProcessingStrategy & getEventSendingStrategy() const
std::map< std::string, Transport > transports
ParticipantConfig()
Constructs a new empty configuration using the default QoS settings and #LOG as error strategy...
std::set< Transport > getTransports(bool includeDisabled=false) const
Returns the set of desired transports for a participant.
std::set< std::pair< std::string, std::string > > ConverterNames
Messages are guaranteed to be delivered.
void setOptions(const rsc::runtime::Properties &options)
Sets the options for the transport.
void printContents(std::ostream &stream) const
Transport getTransport(const std::string &name) const
Returns an immutable copy of a single configured transport.