RSB  0.7.0
 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/config/ConfigFileSource.h>
37 #include <rsc/config/Environment.h>
38 #include <rsc/logging/Logger.h>
39 
40 using namespace std;
41 
42 using namespace boost;
43 using namespace boost::filesystem;
44 
45 using namespace rsc::config;
46 using namespace rsc::logging;
47 using namespace rsc::runtime;
48 
49 namespace rsb {
50 
51 ParticipantConfig::Transport::Transport(const string& name,
52  bool enabled) :
53  name(name) {
54  if (name.empty()) {
55  throw invalid_argument(
56  "The name of a transport configuration cannot be empty.");
57  }
58  if (!enabled) {
59  setEnabled(false);
60  }
61 }
62 
64 }
65 
67  return name;
68 }
69 
71  return this->converters;
72 }
73 
74 rsc::runtime::Properties ParticipantConfig::Transport::getOptions() const {
75  return this->options;
76 }
77 
78 rsc::runtime::Properties& ParticipantConfig::Transport::mutableOptions() {
79  return this->options;
80 }
81 
82 
84  this->options = options;
85 }
86 
88  return this->getOptions().getAs<bool> ("enabled", true);
89 }
90 
92  Properties options = this->getOptions();
93  options["enabled"] = lexical_cast<string>(value);
94  setOptions(options);
95 }
96 
97 void ParticipantConfig::Transport::handleOption(const vector<string>& key,
98  const string& value) {
99  if ((key.size() >= 2)
100  && (key[0] == "converter")
101  && (key[1] == "cpp")) {
102  if (key.size() != 3) {
103  throw invalid_argument(
104  str(
105  format(
106  "Option key `%1%' has invalid number of components; converter-related keys for transports has to have three components")
107  % key));
108  }
109  this->converters.insert(make_pair(key[2], value));
110  } else if ((key.size() >= 2) && (key[0] == "converter")) {
111  // ignore converters for other languages
112  } else {
113  if (key.size() != 1) {
114  throw invalid_argument(
115  str(
116  format(
117  "Key `%1%' has invalid number of components; transport option keys have to have one component.")
118  % key));
119  }
120  this->options[key[0]] = value;
121  }
122 }
123 
125  return name == other.name;
126 }
127 
129  return name < other.name;
130 }
131 
133  return "Transport";
134 }
135 
136 void ParticipantConfig::Transport::printContents(ostream& stream) const {
137  stream << "name = " << this->name
138  << ", converters = " << this->converters
139  << ", options = " << this->options;
140 }
141 
143  name(name) {
144 }
145 
147  return this->name;
148 }
149 
151  this->name = name;
152 }
153 
155  return this->options;
156 }
157 
159  return this->options;
160 }
161 
163  this->options = options;
164 }
165 
167  const string& value) {
168  if (key.size() != 1) {
169  throw invalid_argument(str(format("Key `%1%' has invalid number of components; transport option keys have to have one component.")
170  % key));
171  }
172 
173  this->options.set<string>(key.front(), value);
174 }
175 
177  stream << "name = " << this->name
178  << ", options = " << this->options;
179 }
180 
182  logger(Logger::getLogger("rsb.ParticipantConfig")),
184  eventReceivingStrategy("parallel"),
185  eventSendingStrategy("direct") {
186 }
187 
189 }
190 
192  return qosSpec;
193 }
194 
196  return qosSpec;
197 }
198 
200  const QualityOfServiceSpec& spec) {
201  this->qosSpec = spec;
202 }
203 
205  return errorStrategy;
206 }
207 
209  this->errorStrategy = strategy;
210 }
211 
213  map<string, Transport>::const_iterator it = this->transports.find(name);
214  if (it == this->transports.end()) {
215  throw rsc::runtime::NoSuchObject(name);
216  }
217  return it->second;
218 }
219 
221  map<string, Transport>::iterator it = this->transports.find(name);
222  if (it == this->transports.end()) {
223  throw rsc::runtime::NoSuchObject(name);
224  }
225  return it->second;
226 }
227 
228 set<ParticipantConfig::Transport> ParticipantConfig::getTransports(
229  bool includeDisabled) const {
230  set<Transport> result;
231  for (map<string, Transport>::const_iterator it = this->transports.begin(); it
232  != this->transports.end(); ++it) {
233  if (it->second.isEnabled() || includeDisabled) {
234  result.insert(it->second);
235  } else {
236  RSCDEBUG(logger, "Skipping disabled transport " << it->second);
237  }
238  }
239  return result;
240 }
241 
243  transports.erase(transport.getName());
244  transports.insert(make_pair(transport.getName(), transport));
245 }
246 
248  transports.erase(transport.getName());
249 }
250 
251 void ParticipantConfig::setTransports(const set<Transport>& transports) {
252  for (set<Transport>::const_iterator it = transports.begin(); it
253  != transports.end(); ++it) {
254  this->transports.insert(make_pair(it->getName(), *it));
255  }
256 }
257 
259  return this->eventReceivingStrategy;
260 }
261 
263  return this->eventReceivingStrategy;
264 }
265 
267  return this->eventSendingStrategy;
268 }
269 
270 rsc::runtime::Properties ParticipantConfig::getOptions() const {
271  return options;
272 }
273 
274 rsc::runtime::Properties& ParticipantConfig::mutableOptions() {
275  return options;
276 }
277 
278 void ParticipantConfig::setOptions(const Properties& options) {
279  this->options = options;
280 }
281 
283  const ParticipantConfig& defaults) {
284  LoggerPtr logger = Logger::getLogger("rsb.ParticipantConfig");
285  RSCDEBUG(logger, "Trying to load config from file " << path);
286 
287  ParticipantConfig result = defaults;
288 
289  boost::filesystem::ifstream stream(path);
290  if (stream) {
291  RSCDEBUG(logger, "Stream is open; proceeding");
292  ConfigFileSource(stream).provideOptions(result);
293  } else {
294  RSCDEBUG(logger, "Could not open file");
295  }
296 
297  return result;
298 }
299 
301  const ParticipantConfig& defaults) {
302  ParticipantConfig result = defaults;
303  EnvironmentVariableSource("RSB_").provideOptions(result);
304  return result;
305 }
306 
308  const ParticipantConfig& defaults) {
309  ParticipantConfig result = defaults;
310  try {
311  result = fromFile(systemConfigDirectory() / "rsb.conf", result);
312  } catch (const runtime_error& e) {
313  RSCWARN(Logger::getLogger("rsb.ParticipantConfig"),
314  "Could not find a system-wide configuration file ("
315  << e.what()
316  << ").");
317  }
318  try {
319  result = fromFile(userConfigDirectory() / "rsb.conf", result);
320  } catch (const runtime_error& e) {
321  RSCWARN(Logger::getLogger("rsb.ParticipantConfig"),
322  "Could not find a user-specific configuration file ("
323  << e.what()
324  << ").");
325  }
326  result = fromFile("rsb.conf", result);
327  result = fromEnvironment(result);
328  return result;
329 }
330 
331 void ParticipantConfig::handleOption(const vector<string>& key,
332  const string& value) {
333  // Quality of Service
334  if (key[0] == "qualityofservice") {
335  if (key.size() != 2) {
336  throw invalid_argument(
337  str(
338  format(
339  "Option key `%1%' has invalid number of components; options related to quality of service have to have two components.")
340  % key));
341  }
342  if (key[1] == "reliability") {
343  if (value == "UNRELIABLE") {
345  } else if (value == "RELIABLE") {
347  } else
348  throw invalid_argument(str(format(
349  "The value `%1%' is invalid for the key `%2%'.")
350  % value % key));
351  } else if (key[1] == "ordering") {
352  if (value == "UNORDERED") {
354  } else if (value == "ORDERED") {
356  } else
357  throw invalid_argument(str(format(
358  "The value `%1%' is invalid for the key `%2%'.")
359  % value % key));
360  } else {
361  throw invalid_argument(
362  str(format("`%2%' is not a valid sub-key of `%1%'.")
363  % key[0] % key[1]));
364  }
365  // Error handling
366  } else if (key[0] == "errorhandling") {
367  if (key[1] == "onhandlererror") {
368  if (value == "LOG") {
369  this->errorStrategy = LOG;
370  } else if (value == "PRINT") {
371  this->errorStrategy = PRINT;
372  } else if (value == "EXIT") {
373  this->errorStrategy = EXIT;
374  } else {
375  throw invalid_argument(str(format(
376  "The value `%1%' is invalid for the key `%2%'.")
377  % value % key));
378  }
379  } else {
380  throw invalid_argument(
381  str(format("`%2%' is not a valid sub-key of `%1%'.")
382  % key[0] % key[1]));
383  }
384  // Event processing
385  } else if (key[0] == "eventprocessing") {
386  EventProcessingStrategy* strategy;
387  if (key[1] == "receivingstrategy") {
388  strategy = &this->eventReceivingStrategy;
389  } else if (key[1] == "sendingstrategy") {
390  strategy = &this->eventSendingStrategy;
391  } else {
392  throw invalid_argument(
393  str(format("`%2%' is not a valid sub-key of `%1%'.")
394  % key[0] % key[1]));
395  }
396  if (key.size() == 2) {
397  strategy->setName(value);
398  } else {
399  vector<string> subKey;
400  copy(key.begin() + 2, key.end(), back_inserter(subKey));
401  strategy->handleOption(subKey, value);
402  }
403  // Transports
404  } else if (key[0] == "transport") {
405  if (key.size() < 3) {
406  throw invalid_argument(
407  str(
408  format(
409  "Option key `%1%' has invalid number of components; transport-related keys have to have at least three components.")
410  % key));
411  }
412  map<string, Transport>::iterator it = this->transports.find(key[1]);
413  if (it == this->transports.end()) {
414  addTransport(Transport(key[1]));
415  it = this->transports.find(key[1]);
416  }
417  Transport& transport = it->second;
418  vector<string> subKey;
419  copy(key.begin() + 2, key.end(), back_inserter(subKey));
420  transport.handleOption(subKey, value);
421  // Global (participant-wide) options
422  } else {
423  if (key.size() == 1) {
424  this->options[key[0]] = parseTypedValue(value);
425  }
426  }
427 }
428 
429 void ParticipantConfig::printContents(std::ostream& stream) const {
430  stream << "qosSpec = " << this->qosSpec
431  << ", errorStrategy = " << this->errorStrategy
432  << ", transports = " << this->getTransports(true)
433  << ", eventReceivingStrategy = " << this->eventReceivingStrategy
434  << ", eventSendingStrategy = " << this->eventSendingStrategy
435  << ", options = " << this->options << "]";
436 }
437 
438 }