pion-net  4.0.9
PluginManager.hpp
1 // -----------------------------------------------------------------------
2 // pion-common: a collection of common libraries used by the Pion Platform
3 // -----------------------------------------------------------------------
4 // Copyright (C) 2007-2008 Atomic Labs, Inc. (http://www.atomiclabs.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #ifndef __PION_PLUGINMANAGER_HEADER__
11 #define __PION_PLUGINMANAGER_HEADER__
12 
13 #include <map>
14 #include <string>
15 #include <boost/cstdint.hpp>
16 #include <boost/function.hpp>
17 #include <boost/function/function1.hpp>
18 #include <boost/thread/mutex.hpp>
19 #include <pion/PionConfig.hpp>
20 #include <pion/PionException.hpp>
21 #include <pion/PionPlugin.hpp>
22 
23 
24 namespace pion { // begin namespace pion
25 
29 template <typename PLUGIN_TYPE>
31 {
32 public:
33 
36  public:
37  PluginNotFoundException(const std::string& plugin_id)
38  : PionException("No plug-ins found for identifier: ", plugin_id) {}
39  };
40 
43  public:
44  DuplicatePluginException(const std::string& plugin_id)
45  : PionException("A plug-in already exists for identifier: ", plugin_id) {}
46  };
47 
49  typedef boost::function1<void, PLUGIN_TYPE*> PluginRunFunction;
50 
52  typedef boost::function1<boost::uint64_t, const PLUGIN_TYPE*> PluginStatFunction;
53 
54 
56  PluginManager(void) {}
57 
59  virtual ~PluginManager() {}
60 
62  inline void clear(void) {
63  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
64  m_plugin_map.clear();
65  }
66 
68  inline bool empty(void) const {
69  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
70  return m_plugin_map.empty();
71  }
72 
79  inline void add(const std::string& plugin_id, PLUGIN_TYPE *plugin_object_ptr);
80 
86  inline void remove(const std::string& plugin_id);
87 
94  inline void replace(const std::string& plugin_id, PLUGIN_TYPE *plugin_ptr);
95 
102  inline PLUGIN_TYPE *clone(const std::string& plugin_id);
103 
112  inline PLUGIN_TYPE *load(const std::string& plugin_id, const std::string& plugin_type);
113 
120  inline PLUGIN_TYPE *get(const std::string& plugin_id);
121 
128  inline const PLUGIN_TYPE *get(const std::string& plugin_id) const;
129 
136  inline PionPluginPtr<PLUGIN_TYPE> getLibPtr(const std::string& plugin_id) const;
137 
144  inline PLUGIN_TYPE *find(const std::string& resource);
145 
151  inline void run(PluginRunFunction run_func);
152 
159  inline void run(const std::string& plugin_id, PluginRunFunction run_func);
160 
166  inline boost::uint64_t getStatistic(PluginStatFunction stat_func) const;
167 
174  inline boost::uint64_t getStatistic(const std::string& plugin_id,
175  PluginStatFunction stat_func) const;
176 
177 
178 protected:
179 
181  class PluginMap
182  : public std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >
183  {
184  public:
185  inline void clear(void);
186  virtual ~PluginMap() { PluginMap::clear(); }
187  PluginMap(void) {}
188  };
189 
191  PluginMap m_plugin_map;
192 
194  mutable boost::mutex m_plugin_mutex;
195 };
196 
197 
198 // PluginManager member functions
199 
200 template <typename PLUGIN_TYPE>
201 inline void PluginManager<PLUGIN_TYPE>::add(const std::string& plugin_id,
202  PLUGIN_TYPE *plugin_object_ptr)
203 {
204  PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
205  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
206  m_plugin_map.insert(std::make_pair(plugin_id,
207  std::make_pair(plugin_object_ptr, plugin_ptr)));
208 }
209 
210 template <typename PLUGIN_TYPE>
211 inline void PluginManager<PLUGIN_TYPE>::remove(const std::string& plugin_id)
212 {
213  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
214  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
215  if (i == m_plugin_map.end())
216  throw PluginNotFoundException(plugin_id);
217  if (i->second.second.is_open()) {
218  i->second.second.destroy(i->second.first);
219  } else {
220  delete i->second.first;
221  }
222  m_plugin_map.erase(i);
223 }
224 
225 template <typename PLUGIN_TYPE>
226 inline void PluginManager<PLUGIN_TYPE>::replace(const std::string& plugin_id, PLUGIN_TYPE *plugin_ptr)
227 {
228  PION_ASSERT(plugin_ptr);
229  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
230  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
231  if (i == m_plugin_map.end())
232  throw PluginNotFoundException(plugin_id);
233  if (i->second.second.is_open()) {
234  i->second.second.destroy(i->second.first);
235  } else {
236  delete i->second.first;
237  }
238  i->second.first = plugin_ptr;
239 }
240 
241 template <typename PLUGIN_TYPE>
242 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::clone(const std::string& plugin_id)
243 {
244  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
245  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
246  if (i == m_plugin_map.end())
247  throw PluginNotFoundException(plugin_id);
248  return i->second.second.create();
249 }
250 
251 template <typename PLUGIN_TYPE>
252 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::load(const std::string& plugin_id,
253  const std::string& plugin_type)
254 {
255  // search for the plug-in file using the configured paths
256  bool is_static;
257  void *create_func;
258  void *destroy_func;
259 
260  if (m_plugin_map.find(plugin_id) != m_plugin_map.end())
261  throw DuplicatePluginException(plugin_id);
262 
263  // check if plug-in is statically linked, and if not, try to resolve for dynamic
264  is_static = PionPlugin::findStaticEntryPoint(plugin_type, &create_func, &destroy_func);
265 
266  // open up the plug-in's shared object library
267  PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
268  if (is_static) {
269  plugin_ptr.openStaticLinked(plugin_type, create_func, destroy_func); // may throw
270  } else {
271  plugin_ptr.open(plugin_type); // may throw
272  }
273 
274  // create a new object using the plug-in library
275  PLUGIN_TYPE *plugin_object_ptr(plugin_ptr.create());
276 
277  // add the new plug-in object to our map
278  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
279  m_plugin_map.insert(std::make_pair(plugin_id,
280  std::make_pair(plugin_object_ptr, plugin_ptr)));
281 
282  return plugin_object_ptr;
283 }
284 
285 template <typename PLUGIN_TYPE>
286 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::get(const std::string& plugin_id)
287 {
288  PLUGIN_TYPE *plugin_object_ptr = NULL;
289  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
290  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
291  if (i != m_plugin_map.end())
292  plugin_object_ptr = i->second.first;
293  return plugin_object_ptr;
294 }
295 
296 template <typename PLUGIN_TYPE>
297 inline const PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::get(const std::string& plugin_id) const
298 {
299  const PLUGIN_TYPE *plugin_object_ptr = NULL;
300  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
301  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.find(plugin_id);
302  if (i != m_plugin_map.end())
303  plugin_object_ptr = i->second.first;
304  return plugin_object_ptr;
305 }
306 
307 template <typename PLUGIN_TYPE>
308 inline PionPluginPtr<PLUGIN_TYPE> PluginManager<PLUGIN_TYPE>::getLibPtr(const std::string& plugin_id) const
309 {
310  PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
311  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
312  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.find(plugin_id);
313  if (i != m_plugin_map.end())
314  plugin_ptr = i->second.second;
315  return plugin_ptr;
316 }
317 
318 template <typename PLUGIN_TYPE>
319 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::find(const std::string& resource)
320 {
321  // will point to the matching plug-in object, if found
322  PLUGIN_TYPE *plugin_object_ptr = NULL;
323 
324  // lock mutex for thread safety (this should probably use ref counters)
325  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
326 
327  // check if no plug-ins are being managed
328  if (m_plugin_map.empty()) return plugin_object_ptr;
329 
330  // iterate through each plug-in whose identifier may match the resource
331  typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.upper_bound(resource);
332  while (i != m_plugin_map.begin()) {
333  --i;
334 
335  // keep checking while the first part of the strings match
336  if (resource.compare(0, i->first.size(), i->first) != 0) {
337  // the first part no longer matches
338  if (i != m_plugin_map.begin()) {
339  // continue to next plug-in in list if its size is < this one
341  --j;
342  if (j->first.size() < i->first.size())
343  continue;
344  }
345  // otherwise we've reached the end; stop looking for a match
346  break;
347  }
348 
349  // only if the resource matches the plug-in's identifier
350  // or if resource is followed first with a '/' character
351  if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
352  plugin_object_ptr = i->second.first;
353  break;
354  }
355  }
356 
357  return plugin_object_ptr;
358 }
359 
360 template <typename PLUGIN_TYPE>
362 {
363  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
364  for (typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.begin();
365  i != m_plugin_map.end(); ++i)
366  {
367  run_func(i->second.first);
368  }
369 }
370 
371 template <typename PLUGIN_TYPE>
372 inline void PluginManager<PLUGIN_TYPE>::run(const std::string& plugin_id,
373  PluginRunFunction run_func)
374 {
375  // no need to lock (handled by PluginManager::get())
376  PLUGIN_TYPE *plugin_object_ptr = get(plugin_id);
377  if (plugin_object_ptr == NULL)
378  throw PluginNotFoundException(plugin_id);
379  run_func(plugin_object_ptr);
380 }
381 
382 template <typename PLUGIN_TYPE>
383 inline boost::uint64_t PluginManager<PLUGIN_TYPE>::getStatistic(PluginStatFunction stat_func) const
384 {
385  boost::uint64_t stat_value = 0;
386  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
387  for (typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.begin();
388  i != m_plugin_map.end(); ++i)
389  {
390  stat_value += stat_func(i->second.first);
391  }
392  return stat_value;
393 }
394 
395 template <typename PLUGIN_TYPE>
396 inline boost::uint64_t PluginManager<PLUGIN_TYPE>::getStatistic(const std::string& plugin_id,
397  PluginStatFunction stat_func) const
398 {
399  // no need to lock (handled by PluginManager::get())
400  const PLUGIN_TYPE *plugin_object_ptr = const_cast<PluginManager<PLUGIN_TYPE>*>(this)->get(plugin_id);
401  if (plugin_object_ptr == NULL)
402  throw PluginNotFoundException(plugin_id);
403  return stat_func(plugin_object_ptr);
404 }
405 
406 
407 // PluginManager::PluginMap member functions
408 
409 template <typename PLUGIN_TYPE>
411 {
412  if (! std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::empty()) {
414  std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::begin();
415  i != std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::end(); ++i)
416  {
417  if (i->second.second.is_open()) {
418  i->second.second.destroy(i->second.first);
419  } else {
420  delete i->second.first;
421  }
422  }
423  this->erase(std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::begin(),
424  std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::end());
425  }
426 }
427 
428 
429 } // end namespace pion
430 
431 #endif
void add(const std::string &plugin_id, PLUGIN_TYPE *plugin_object_ptr)
void run(PluginRunFunction run_func)
exception thrown if a plug-in cannot be found
PLUGIN_TYPE * find(const std::string &resource)
PluginManager(void)
default constructor
static bool findStaticEntryPoint(const std::string &plugin_name, void **create_func, void **destroy_func)
Definition: PionPlugin.cpp:347
boost::uint64_t getStatistic(PluginStatFunction stat_func) const
PionPluginPtr< PLUGIN_TYPE > getLibPtr(const std::string &plugin_id) const
data type that maps identifiers to plug-in objects
void open(const std::string &plugin_name)
Definition: PionPlugin.cpp:70
void openStaticLinked(const std::string &plugin_name, void *create_func, void *destroy_func)
Definition: PionPlugin.cpp:109
boost::function1< void, PLUGIN_TYPE * > PluginRunFunction
data type for a function that may be called by the run() method
bool empty(void) const
returns true if there are no plug-in objects being managed
boost::function1< boost::uint64_t, const PLUGIN_TYPE * > PluginStatFunction
data type for a function that may be called by the getStat() method
void remove(const std::string &plugin_id)
virtual ~PluginManager()
default destructor
PluginMap m_plugin_map
collection of plug-in objects being managed
void replace(const std::string &plugin_id, PLUGIN_TYPE *plugin_ptr)
exception thrown if we try to add or load a duplicate plug-in
InterfaceClassType * create(void)
creates a new instance of the plug-in object
Definition: PionPlugin.hpp:389
the following enables use of the lock-free cache
PLUGIN_TYPE * load(const std::string &plugin_id, const std::string &plugin_type)
PLUGIN_TYPE * clone(const std::string &plugin_id)
void clear(void)
clears all the plug-in objects being managed
PLUGIN_TYPE * get(const std::string &plugin_id)
boost::mutex m_plugin_mutex
mutex to make class thread-safe