RSB  0.9.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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/config/TypedValue.h>
36 #include <rsc/logging/Logger.h>
37 
38 using namespace std;
39 
40 using namespace boost;
41 using namespace boost::filesystem;
42 
43 using namespace rsc::config;
44 using namespace rsc::logging;
45 using namespace rsc::runtime;
46 
47 namespace rsb {
48 
49 ParticipantConfig::Transport::Transport(const string& name,
50  bool enabled) :
51  name(name) {
52  if (name.empty()) {
53  throw invalid_argument(
54  "The name of a transport configuration cannot be empty.");
55  }
56  if (!enabled) {
57  setEnabled(false);
58  }
59 }
60 
62 }
63 
65  return name;
66 }
67 
69  return this->converters;
70 }
71 
72 rsc::runtime::Properties ParticipantConfig::Transport::getOptions() const {
73  return this->options;
74 }
75 
76 rsc::runtime::Properties& ParticipantConfig::Transport::mutableOptions() {
77  return this->options;
78 }
79 
80 
82  this->options = options;
83 }
84 
86  return this->getOptions().getAs<bool> ("enabled", true);
87 }
88 
90  Properties options = this->getOptions();
91  options["enabled"] = lexical_cast<string>(value);
92  setOptions(options);
93 }
94 
95 void ParticipantConfig::Transport::handleOption(const vector<string>& key,
96  const string& value) {
97  if ((key.size() >= 2)
98  && (key[0] == "converter")
99  && (key[1] == "cpp")) {
100  if (key.size() != 3) {
101  throw invalid_argument(
102  str(
103  format(
104  "Option key `%1%' has invalid number of components; converter-related keys for transports has to have three components")
105  % key));
106  }
107  this->converters.insert(make_pair(key[2], value));
108  } else if ((key.size() >= 2) && (key[0] == "converter")) {
109  // ignore converters for other languages
110  } else {
111  if (key.size() != 1) {
112  throw invalid_argument(
113  str(
114  format(
115  "Key `%1%' has invalid number of components; transport option keys have to have one component.")
116  % key));
117  }
118  this->options[key[0]] = value;
119  }
120 }
121 
123  return name == other.name;
124 }
125 
127  return name < other.name;
128 }
129 
131  return "Transport";
132 }
133 
134 void ParticipantConfig::Transport::printContents(ostream& stream) const {
135  stream << "name = " << this->name
136  << ", converters = " << this->converters
137  << ", options = " << this->options;
138 }
139 
141  name(name) {
142 }
143 
145  return this->name;
146 }
147 
149  this->name = name;
150 }
151 
153  return this->options;
154 }
155 
157  return this->options;
158 }
159 
161  this->options = options;
162 }
163 
165  const string& value) {
166  if (key.size() != 1) {
167  throw invalid_argument(str(format("Key `%1%' has invalid number of components; transport option keys have to have one component.")
168  % key));
169  }
170 
171  this->options.set<string>(key.front(), value);
172 }
173 
175  stream << "name = " << this->name
176  << ", options = " << this->options;
177 }
178 
180  logger(Logger::getLogger("rsb.ParticipantConfig")),
182  eventReceivingStrategy("parallel"),
183  eventSendingStrategy("direct") {
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  for (set<Transport>::const_iterator it = transports.begin(); it
251  != transports.end(); ++it) {
252  this->transports.insert(make_pair(it->getName(), *it));
253  }
254 }
255 
257  return this->eventReceivingStrategy;
258 }
259 
261  return this->eventReceivingStrategy;
262 }
263 
265  return this->eventSendingStrategy;
266 }
267 
268 rsc::runtime::Properties ParticipantConfig::getOptions() const {
269  return options;
270 }
271 
272 rsc::runtime::Properties& ParticipantConfig::mutableOptions() {
273  return options;
274 }
275 
276 void ParticipantConfig::setOptions(const Properties& options) {
277  this->options = options;
278 }
279 
280 void ParticipantConfig::handleOption(const vector<string>& key,
281  const string& value) {
282  // Quality of Service
283  if (key[0] == "qualityofservice") {
284  if (key.size() != 2) {
285  throw invalid_argument(
286  str(
287  format(
288  "Option key `%1%' has invalid number of components; options related to quality of service have to have two components.")
289  % key));
290  }
291  if (key[1] == "reliability") {
292  if (value == "UNRELIABLE") {
294  } else if (value == "RELIABLE") {
296  } else
297  throw invalid_argument(str(format(
298  "The value `%1%' is invalid for the key `%2%'.")
299  % value % key));
300  } else if (key[1] == "ordering") {
301  if (value == "UNORDERED") {
303  } else if (value == "ORDERED") {
305  } else
306  throw invalid_argument(str(format(
307  "The value `%1%' is invalid for the key `%2%'.")
308  % value % key));
309  } else {
310  throw invalid_argument(
311  str(format("`%2%' is not a valid sub-key of `%1%'.")
312  % key[0] % key[1]));
313  }
314  // Error handling
315  } else if (key[0] == "errorhandling") {
316  if (key[1] == "onhandlererror") {
317  if (value == "LOG") {
319  } else if (value == "PRINT") {
321  } else if (value == "EXIT") {
323  } else {
324  throw invalid_argument(str(format(
325  "The value `%1%' is invalid for the key `%2%'.")
326  % value % key));
327  }
328  } else {
329  throw invalid_argument(
330  str(format("`%2%' is not a valid sub-key of `%1%'.")
331  % key[0] % key[1]));
332  }
333  // Event processing
334  } else if (key[0] == "eventprocessing") {
335  EventProcessingStrategy* strategy;
336  if (key[1] == "receivingstrategy") {
337  strategy = &this->eventReceivingStrategy;
338  } else if (key[1] == "sendingstrategy") {
339  strategy = &this->eventSendingStrategy;
340  } else {
341  throw invalid_argument(
342  str(format("`%2%' is not a valid sub-key of `%1%'.")
343  % key[0] % key[1]));
344  }
345  if (key.size() == 2) {
346  strategy->setName(value);
347  } else {
348  vector<string> subKey;
349  copy(key.begin() + 2, key.end(), back_inserter(subKey));
350  strategy->handleOption(subKey, value);
351  }
352  // Transports
353  } else if (key[0] == "transport") {
354  if (key.size() < 3) {
355  throw invalid_argument(
356  str(
357  format(
358  "Option key `%1%' has invalid number of components; transport-related keys have to have at least three components.")
359  % key));
360  }
361  map<string, Transport>::iterator it = this->transports.find(key[1]);
362  if (it == this->transports.end()) {
363  addTransport(Transport(key[1]));
364  it = this->transports.find(key[1]);
365  }
366  Transport& transport = it->second;
367  vector<string> subKey;
368  copy(key.begin() + 2, key.end(), back_inserter(subKey));
369  transport.handleOption(subKey, value);
370  // Global (participant-wide) options
371  } else {
372  if (key.size() == 1) {
373  this->options[key[0]] = parseTypedValue(value);
374  }
375  }
376 }
377 
378 void ParticipantConfig::printContents(std::ostream& stream) const {
379  stream << "qosSpec = " << this->qosSpec
380  << ", errorStrategy = " << this->errorStrategy
381  << ", transports = " << this->getTransports(true)
382  << ", eventReceivingStrategy = " << this->eventReceivingStrategy
383  << ", eventSendingStrategy = " << this->eventSendingStrategy
384  << ", options = " << this->options << "]";
385 }
386 
387 }
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
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 & 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)
Sets all desired transports in this configuration.
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 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.