RSB  0.7.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Factory.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 "Factory.h"
28 
29 #include <boost/filesystem/fstream.hpp>
30 
31 #include <rsc/config/ConfigFileSource.h>
32 #include <rsc/config/Environment.h>
33 #include <rsc/logging/OptionBasedConfigurator.h>
34 
36 
37 #include "converter/converters.h"
38 #include "converter/Repository.h"
40 
41 #include "transport/transports.h"
42 
43 #include "LocalService.h"
44 
45 using namespace std;
46 
47 using namespace rsc::config;
48 using namespace rsc::logging;
49 using namespace rsc::runtime;
50 
51 using namespace rsb::converter;
52 using namespace rsb::transport;
53 
54 namespace {
55 
56 template<unsigned int which, typename C>
57 std::map<typename C::value_type::first_type,
58  typename C::value_type::second_type> pairsToMap(const C& container) {
59  typedef typename C::value_type::first_type first_type;
60  typedef typename C::value_type::second_type second_type;
61 
62  typedef typename C::const_iterator const_iterator;
63 
64  std::map<first_type, second_type> result;
65  for (const_iterator it = container.begin(); it != container.end(); ++it) {
66  if (which == 1)
67  result[it->first] = it->second;
68  else
69  result[it->second] = it->first;
70  }
71  return result;
72 }
73 
74 }
75 
76 namespace rsb {
77 
78 Factory::Factory() :
79  logger(Logger::getLogger("rsb.Factory")) {
83 
84  // Setup default participant config
85  //
86  // Collect all available connector implementations from the
87  // connector factories:
88  // + In-push
89  // + In-pull
90  // + Out
91  // Disable discovered connectors with the exception of the
92  // inprocess transport.
93  set<string> availableTransports;
94  {
95  set<InPullFactory::ConnectorInfo> infos = getInPullFactory().getConnectorInfos();
96  for (set<InPullFactory::ConnectorInfo>::const_iterator it
97  = infos.begin(); it != infos.end(); ++it) {
98  availableTransports.insert(it->getName());
99  }
100  }{
101  set<InPushFactory::ConnectorInfo> infos = getInPushFactory().getConnectorInfos();
102  for (set<InPushFactory::ConnectorInfo>::const_iterator it
103  = infos.begin(); it != infos.end(); ++it) {
104  availableTransports.insert(it->getName());
105  }
106  }{
107  set<OutFactory::ConnectorInfo> infos = getOutFactory().getConnectorInfos();
108  for (set<OutFactory::ConnectorInfo>::const_iterator it
109  = infos.begin(); it != infos.end(); ++it) {
110  availableTransports.insert(it->getName());
111  }
112  }
113 
115  for (set<string>::const_iterator it = availableTransports.begin();
116  it != availableTransports.end(); ++it) {
117  this->defaultConfig.addTransport(ParticipantConfig::Transport(*it, *it == "socket"));
118  }
119 
120  // If there is only one transport, we can blindly enable it since
121  // the user could end up without any enabled transport otherwise.
122  if (this->defaultConfig.getTransports().size() == 1) {
123  string name = this->defaultConfig.getTransports().begin()->getName();
124  this->defaultConfig.mutableTransport(name).setEnabled(true);
125  }
126 
127  // Merge with user configuration (configuration files, environment
128  // variables)
129  this->defaultConfig
131 
132  // Issue a warning if the combination of available transport
133  // implementations and user configuration leads to no enabled
134  // transports.
135  if (this->defaultConfig.getTransports().empty()) {
136  RSCWARN(logger, "No transports are enabled. This is probably a configuration error or an internal RSB error.");
137  }
138 
139  RSCDEBUG(logger, "Default config " << defaultConfig);
140 
142 
143 }
144 
146 }
147 
149 
150  // TODO the cascade is basically duplicated from ParticipantConfig. We
151  // should refactor this
152 
153  OptionBasedConfigurator loggingConfigurator;
154 
155  try {
156  boost::filesystem::ifstream stream(
157  systemConfigDirectory() / "rsb.conf");
158  if (stream) {
159  ConfigFileSource source(stream);
160  source.provideOptions(loggingConfigurator);
161  }
162  } catch (const runtime_error& e) {
163  RSCWARN(this->logger,
164  "Could not find a system-wide configuration file ("
165  << e.what()
166  << ").");
167  }
168 
169  try {
170  boost::filesystem::ifstream stream(userConfigDirectory() / "rsb.conf");
171  if (stream) {
172  ConfigFileSource source(stream);
173  source.provideOptions(loggingConfigurator);
174  }
175  } catch (const runtime_error& e) {
176  RSCWARN(logger,
177  "Could not find a user-specific configuration file ("
178  << e.what()
179  << ").");
180  }
181 
182  {
183  boost::filesystem::ifstream stream("rsb.conf");
184  if (stream) {
185  ConfigFileSource source(stream);
186  source.provideOptions(loggingConfigurator);
187  }
188  }
189 
190  {
191  EnvironmentVariableSource source("RSC_");
192  source.provideOptions(loggingConfigurator);
193  }
194 
195 }
196 
198  return transport::OutFactory::getInstance();
199 }
200 
202  const string& dataType,
203  const ParticipantConfig& config) {
204  return InformerBasePtr(new InformerBase(createOutConnectors(config), scope, config, dataType));
205 }
206 
207 
209  const ParticipantConfig& config) {
210  return ListenerPtr(new Listener(createInPushConnectors(config), scope, config));
211 }
212 
214  const ParticipantConfig& config) {
215  return ReaderPtr(new Reader(createInPullConnectors(config), scope, config));
216 }
217 
219  const ParticipantConfig &listenerConfig,
220  const ParticipantConfig &informerConfig) {
221  return patterns::ServerPtr(
222  new patterns::Server(scope, listenerConfig, informerConfig));
223 }
224 
226  const ParticipantConfig &listenerConfig,
227  const ParticipantConfig &informerConfig) {
229  new patterns::RemoteServer(scope, listenerConfig, informerConfig));
230 }
231 
233  boost::recursive_mutex::scoped_lock lock(configMutex);
234  return defaultConfig;
235 }
236 
238  boost::recursive_mutex::scoped_lock lock(configMutex);
239  this->defaultConfig = config;
240 }
241 
243  return ServicePtr(new LocalService(scope));
244 }
245 
246 vector<InPullConnectorPtr>
248  // Note: getTransports() only returns *enabled* transports.
249  vector<InPullConnectorPtr> connectors;
250  set<ParticipantConfig::Transport> configuredTransports = config.getTransports();
251  for (set<ParticipantConfig::Transport>::const_iterator transportIt =
252  configuredTransports.begin(); transportIt
253  != configuredTransports.end(); ++transportIt) {
254  RSCDEBUG(logger, "Trying to add connector " << *transportIt);
255  Properties options = transportIt->getOptions();
256  RSCDEBUG(logger, "Supplied connector options " << transportIt->getOptions());
257 
258  // Take care of converters
259  if (!options.has("converters")) {
260  RSCDEBUG(logger, "Converter configuration for transport `"
261  << transportIt->getName() << "': " << transportIt->getConverters());
262  // TODO we should not have to know the transport's wire-type here
264  = converterRepository<string>()
265  ->getConvertersForDeserialization(pairsToMap<1> (transportIt->getConverters()));
266  RSCDEBUG(logger, "Selected converters for transport `"
267  << transportIt->getName() << "': " << converters);
268  options["converters"] = converters;
269  }
270  connectors.push_back(InPullConnectorPtr(getInPullFactory().createInst(transportIt->getName(), options)));
271  }
272  return connectors;
273 }
274 
275 vector<InPushConnectorPtr>
277  // Note: getTransports() only returns *enabled* transports.
278  vector<InPushConnectorPtr> connectors;
279  set<ParticipantConfig::Transport> configuredTransports = config.getTransports();
280  for (set<ParticipantConfig::Transport>::const_iterator transportIt =
281  configuredTransports.begin(); transportIt
282  != configuredTransports.end(); ++transportIt) {
283  RSCDEBUG(logger, "Trying to add connector " << *transportIt);
284  Properties options = transportIt->getOptions();
285  RSCDEBUG(logger, "Supplied connector options " << transportIt->getOptions());
286 
287  // Take care of converters
288  if (!options.has("converters")) {
289  RSCDEBUG(logger, "Converter configuration for transport `"
290  << transportIt->getName() << "': " << transportIt->getConverters());
291  // TODO we should not have to know the transport's wire-type here
293  = converterRepository<string>()
294  ->getConvertersForDeserialization(pairsToMap<1> (transportIt->getConverters()));
295  RSCDEBUG(logger, "Selected converters for transport `"
296  << transportIt->getName() << "': " << converters);
297  options["converters"] = converters;
298  }
299  connectors.push_back(InPushConnectorPtr(getInPushFactory().createInst(transportIt->getName(), options)));
300  }
301  return connectors;
302 }
303 
304 vector<OutConnectorPtr>
306  // Note: getTransports() only returns *enabled* transports.
307  vector<OutConnectorPtr> connectors;
308  set<ParticipantConfig::Transport> configuredTransports = config.getTransports();
309  for (set<ParticipantConfig::Transport>::const_iterator transportIt =
310  configuredTransports.begin(); transportIt
311  != configuredTransports.end(); ++transportIt) {
312  RSCDEBUG(logger, "Trying to add connector " << *transportIt);
313  Properties options = transportIt->getOptions();
314  RSCDEBUG(logger, "Supplied connector options " << transportIt->getOptions());
315 
316  // Take care of converters
317  if (!options.has("converters")) {
318  RSCDEBUG(logger, "Converter configuration for transport `"
319  << transportIt->getName() << "': " << transportIt->getConverters());
320  // TODO we should not have to know the transport's wire-type here
322  = converterRepository<string>()
323  ->getConvertersForSerialization(pairsToMap<2> (transportIt->getConverters()));
324  RSCDEBUG(logger, "Selected converters for transport `"
325  << transportIt->getName() << "': " << converters);
326  options["converters"] = converters;
327  }
328  connectors.push_back(OutConnectorPtr(getOutFactory().createInst(transportIt->getName(), options)));
329  }
330  return connectors;
331 }
332 
333 }