RSB  0.17.0
Plugin.cpp
Go to the documentation of this file.
1 /* ============================================================
2  *
3  * This file is part of the RSB project.
4  *
5  * Copyright (C) 2014, 2015, 2016 Jan Moringen <jmoringe@techfak.uni-bielefeld.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 <boost/thread/mutex.hpp>
28 
29 #include <rsc/logging/Logger.h>
30 #include <rsc/plugins/Provider.h>
31 
32 #include <../ParticipantConfig.h>
33 #include <../Factory.h>
34 
35 #include <../converter/Repository.h>
36 #include <../converter/VoidConverter.h>
37 #include <../converter/StringConverter.h>
38 #include <../converter/ProtocolBufferConverter.h>
39 
40 #include <rsb/protocol/introspection/Hello.pb.h>
41 #include <rsb/protocol/introspection/Bye.pb.h>
42 
43 #include "IntrospectionSender.h"
44 
45 // Plugin-level helper stuff
46 
47 namespace {
48 
49 template <typename WireType>
50 void addConverter(rsb::converter::UnambiguousConverterMap<WireType>& selection,
52  bool forSerialization) {
53  if (forSerialization) {
54  selection.addConverter(converter->getDataType(),
55  typename rsb::converter::Converter<WireType>::Ptr(converter));
56  } else {
57  selection.addConverter(converter->getWireSchema(),
58  typename rsb::converter::Converter<WireType>::Ptr(converter));
59  }
60 }
61 
62 rsb::ParticipantConfig createConfig(const rsb::ParticipantConfig& defaultConfig,
63  bool forSerialization) {
64  rsb::ParticipantConfig config = defaultConfig;
65 
66  boost::shared_ptr< rsb::converter::UnambiguousConverterMap<std::string> > converterSelection
68  addConverter(*converterSelection, new rsb::converter::VoidConverter(),
69  forSerialization);
70  addConverter(*converterSelection, new rsb::converter::StringConverter(),
71  forSerialization);
72  addConverter(*converterSelection,
74  forSerialization);
75  addConverter(*converterSelection,
77  forSerialization);
78 
79  std::set<rsb::ParticipantConfig::Transport> transports
80  = config.getTransports();
81  for (std::set<rsb::ParticipantConfig::Transport>::const_iterator it
82  = transports.begin(); it != transports.end(); ++it) {
84  = config.mutableTransport(it->getName());
85  rsc::runtime::Properties options = transport.getOptions();
86  options["converters"] = rsb::converter::ConverterSelectionStrategy<std::string>::Ptr(converterSelection);
87  transport.setOptions(options);
88  }
89 
90  return config;
91 }
92 
93 class IntrospectionParticipantObserver : public rsc::config::OptionHandler {
94 public:
95  IntrospectionParticipantObserver()
96  : logger(rsc::logging::Logger::getLogger(
97  "rsb.introspection.IntrospectionParticipantObserver")) {
98  }
99 
100  void handleOption(const std::vector<std::string>& key,
101  const std::string& value) {
102  if (key.size() == 2 && key[0] == "introspection"
103  && key[1] == "displayname") {
104  processDisplayName.reset(new std::string(value));
105  }
106  }
107 
108  void handleParticipantCreated(rsb::ParticipantPtr participant,
109  rsb::ParticipantPtr parent) {
110  // Do not print out the participant directly since parts of might not be
111  // constructed, which could be accessed by the participan's printing method
112  RSCDEBUG(logger,
113  "Was notified of created participant " << participant->getId() <<
114  " at scope " << *participant->getScope());
115 
116  if (participant->getScope()->isSubScopeOf("/__rsb/introspection")
117  || !participant->getConfig().isIntrospectionEnabled()) {
118  RSCDEBUG(logger, "Ignoring created participant " << participant);
119  return;
120  }
121 
122  {
123  boost::mutex::scoped_lock lock(senderMutex);
124 
125  if (!sender) {
126  RSCDEBUG(logger, "Creating introspection sender");
127  configSerialization = createConfig(rsb::getFactory().getDefaultParticipantConfig(), true);
128  configDeserialization = createConfig(rsb::getFactory().getDefaultParticipantConfig(), false);
129  sender.reset(
131  processDisplayName,
132  configDeserialization, configSerialization));
133  }
134 
135  sender->addParticipant(participant, parent);
136  }
137  }
138 
139  void handleParticipantDestroyed(rsb::Participant* participant) {
140  // Do not print out the participant directly since parts of it are already
141  // destroyed, which could be accessed by the participan's printing method
142  RSCDEBUG(logger,
143  "Was notified of destroyed participant " << participant->getId() <<
144  " at scope " << *participant->getScope());
145 
146  // Exit early for "uninteresting" participants (e.g. disabled
147  // introspection or internal to the introspection machinery).
148  if (participant->getScope()->isSubScopeOf("/__rsb/introspection")
149  || !participant->getConfig().isIntrospectionEnabled()) {
150  RSCDEBUG(logger, "Ignoring destroyed participant " << participant);
151  return;
152  }
153 
154  // "Ordinary" participant: not internal and introspection is
155  // enabled. Remove the participant from the introspection sender,
156  // but only if the sender exists.
157  //
158  // The following lock must not extend to the conditional exit
159  // above since otherwise sender.reset() would cause recursive
160  // entry into handleParticipantDestroyed and thus a recursive lock
161  // attempt.
162  {
163  boost::mutex::scoped_lock lock(senderMutex);
164 
165  if (!sender) {
166  RSCDEBUG(logger, "Ignoring destroyed participant " << participant);
167  return;
168  }
169 
170  if (!sender->removeParticipant(*participant)) {
171  sender.reset();
172  }
173  }
174  }
175 private:
176  rsc::logging::LoggerPtr logger;
177 
178  rsb::ParticipantConfig configSerialization;
179  rsb::ParticipantConfig configDeserialization;
180 
181  boost::shared_ptr<std::string> processDisplayName;
182 
184  boost::mutex senderMutex;
185 };
186 
187 typedef boost::shared_ptr<IntrospectionParticipantObserver> IntrospectionParticipantObserverPtr;
188 
189 IntrospectionParticipantObserverPtr observer;
190 
191 boost::signals2::connection participantCreatedConnection;
192 boost::signals2::connection participantDestroyedConnection;
193 
194 // External plugin interface
195 
196 extern "C" {
197 
198  RSC_PLUGIN_INIT_SIGNATURE() {
199  // Register converters.
200  rsc::logging::LoggerPtr logger = rsc::logging::Logger::getLogger("rsb.introspection");
201  RSCDEBUG(logger, "Registering converters for introspection types");
202 
203  rsb::converter::converterRepository<std::string>()
206  rsb::converter::converterRepository<std::string>()
209 
210  observer.reset(new IntrospectionParticipantObserver());
211 
212  // Process configuration to obtain value of the
213  // introspection.displayname option.
214  rsb::Factory::provideConfigOptions("RSB_", *observer);
215 
216  // Register participant creation hook.
217  RSCDEBUG(logger, "Registering participant creation and destruction hooks");
218 
219  participantCreatedConnection
221  ->connect(boost::bind(&IntrospectionParticipantObserver::handleParticipantCreated, observer, _1, _2));
222  participantDestroyedConnection
224  ->connect(boost::bind(&IntrospectionParticipantObserver::handleParticipantDestroyed, observer, _1));
225  }
226 
227  RSC_PLUGIN_SHUTDOWN_SIGNATURE() {
228  rsc::logging::LoggerPtr logger = rsc::logging::Logger::getLogger("rsb.introspection");
229 
230  RSCDEBUG(logger, "Unregistering participant creation and destruction hooks");
231 
232  participantCreatedConnection.disconnect();
233  participantDestroyedConnection.disconnect();
234 
235  RSCDEBUG(logger, "Destroying introspection sender");
236 
237  observer.reset();
238  }
239 
240 }
241 
242 }
rsc::runtime::Properties getOptions() const
Returns the specified options for the transport.
Objects of this class participate in the exchange of notifications on one channel of the bus...
Definition: Participant.h:65
Instances of this class publish information about the local host, the current process and its partici...
Converts any string into any string serializing content to a string.
boost::shared_ptr< IntrospectionSender > IntrospectionSenderPtr
SignalParticipantDestroyedPtr getSignalParticipantDestroyed()
Definition: Factory.cpp:311
A generic converter for data types based on Protocol Buffer messages.
virtual std::string getWireSchema() const
Returns the name of the wire schema this converter can (de)serialize from/to.
Definition: Converter.h:97
Objects this class store mappings of one of the followings forms.
ParticipantConfig getConfig() const
Returns a copy of the participant&#39;s configuration.
Definition: Participant.cpp:68
Factory & getFactory()
Returns a factory for client-level RSB objects.
Definition: Factory.cpp:163
static void provideConfigOptions(const std::string &environmentVariablePrefix, rsc::config::OptionHandler &handler, bool stripPrefix=true)
Provides the default configuration options for RSB to the specified handler.
Definition: Factory.cpp:299
bool isIntrospectionEnabled() const
Indicates whether introspection should be enabled for the participant.
boost::shared_ptr< Converter< WireType > > Ptr
Definition: Converter.h:101
boost::shared_ptr< Participant > ParticipantPtr
Definition: Participant.h:122
boost::shared_ptr< ConverterSelectionStrategy< WireType > > Ptr
Description of a desired transport.
Fulfill the interface...
Definition: VoidConverter.h:42
virtual std::string getDataType() const
Returns the name of the data type this converter is applicable for.
Definition: Converter.h:86
void addConverter(const std::string &key, ConverterPtr converter)
Stores converter in the map under the name key.
Transport & mutableTransport(const std::string &name)
Returns a single configured transport which can be modified in place.
A class describing the configuration of Participant instances.
SignalParticipantCreatedPtr getSignalParticipantCreated()
Definition: Factory.cpp:307
ScopePtr getScope() const
Returns the scope of this participant.
Definition: Participant.cpp:64
rsc::misc::UUID getId() const
Returns the unique id of the participant.
Definition: Participant.cpp:60
std::set< Transport > getTransports(bool includeDisabled=false) const
Returns the set of desired transports for a participant.
void setOptions(const rsc::runtime::Properties &options)
Sets the options for the transport.