pion  5.0.6
plugin_manager.hpp
1 // ---------------------------------------------------------------------
2 // pion: a Boost C++ framework for building lightweight HTTP interfaces
3 // ---------------------------------------------------------------------
4 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
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_PLUGIN_MANAGER_HEADER__
11 #define __PION_PLUGIN_MANAGER_HEADER__
12 
13 #include <map>
14 #include <string>
15 #include <boost/cstdint.hpp>
16 #include <boost/assert.hpp>
17 #include <boost/function.hpp>
18 #include <boost/function/function1.hpp>
19 #include <boost/thread/mutex.hpp>
20 #include <pion/config.hpp>
21 #include <pion/error.hpp>
22 #include <pion/plugin.hpp>
23 
24 
25 namespace pion { // begin namespace pion
26 
30 template <typename PluginType>
32 {
33 public:
34 
36  typedef boost::function1<void, PluginType*> PluginRunFunction;
37 
39  typedef boost::function1<boost::uint64_t, const PluginType*> PluginStatFunction;
40 
41 
43  plugin_manager(void) {}
44 
46  virtual ~plugin_manager() {}
47 
49  inline void clear(void) {
50  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
51  m_plugin_map.clear();
52  }
53 
55  inline bool empty(void) const {
56  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
57  return m_plugin_map.empty();
58  }
59 
66  inline void add(const std::string& plugin_id, PluginType *plugin_object_ptr);
67 
73  inline void remove(const std::string& plugin_id);
74 
81  inline void replace(const std::string& plugin_id, PluginType *plugin_ptr);
82 
89  inline PluginType *clone(const std::string& plugin_id);
90 
99  inline PluginType *load(const std::string& plugin_id, const std::string& plugin_type);
100 
107  inline PluginType *get(const std::string& plugin_id);
108 
115  inline const PluginType *get(const std::string& plugin_id) const;
116 
123  inline plugin_ptr<PluginType> get_lib_ptr(const std::string& plugin_id) const;
124 
131  inline PluginType *find(const std::string& resource);
132 
138  inline void run(PluginRunFunction run_func);
139 
146  inline void run(const std::string& plugin_id, PluginRunFunction run_func);
147 
153  inline boost::uint64_t get_statistic(PluginStatFunction stat_func) const;
154 
161  inline boost::uint64_t get_statistic(const std::string& plugin_id,
162  PluginStatFunction stat_func) const;
163 
164 
165 protected:
166 
168  class map_type
169  : public std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >
170  {
171  public:
172  inline void clear(void);
173  virtual ~map_type() { map_type::clear(); }
174  map_type(void) {}
175  };
176 
178  map_type m_plugin_map;
179 
181  mutable boost::mutex m_plugin_mutex;
182 };
183 
184 
185 // plugin_manager member functions
186 
187 template <typename PluginType>
188 inline void plugin_manager<PluginType>::add(const std::string& plugin_id,
189  PluginType *plugin_object_ptr)
190 {
192  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
193  m_plugin_map.insert(std::make_pair(plugin_id,
194  std::make_pair(plugin_object_ptr, plugin_ptr)));
195 }
196 
197 template <typename PluginType>
198 inline void plugin_manager<PluginType>::remove(const std::string& plugin_id)
199 {
200  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
201  typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
202  if (i == m_plugin_map.end())
203  BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
204  if (i->second.second.is_open()) {
205  i->second.second.destroy(i->second.first);
206  } else {
207  delete i->second.first;
208  }
209  m_plugin_map.erase(i);
210 }
211 
212 template <typename PluginType>
213 inline void plugin_manager<PluginType>::replace(const std::string& plugin_id, PluginType *plugin_ptr)
214 {
215  BOOST_ASSERT(plugin_ptr);
216  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
217  typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
218  if (i == m_plugin_map.end())
219  BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
220  if (i->second.second.is_open()) {
221  i->second.second.destroy(i->second.first);
222  } else {
223  delete i->second.first;
224  }
225  i->second.first = plugin_ptr;
226 }
227 
228 template <typename PluginType>
229 inline PluginType *plugin_manager<PluginType>::clone(const std::string& plugin_id)
230 {
231  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
232  typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
233  if (i == m_plugin_map.end())
234  BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
235  return i->second.second.create();
236 }
237 
238 template <typename PluginType>
239 inline PluginType *plugin_manager<PluginType>::load(const std::string& plugin_id,
240  const std::string& plugin_type)
241 {
242  // search for the plug-in file using the configured paths
243  if (m_plugin_map.find(plugin_id) != m_plugin_map.end())
244  BOOST_THROW_EXCEPTION( error::duplicate_plugin() << error::errinfo_plugin_name(plugin_id) );
245 
246  // open up the plug-in's shared object library
248  plugin_ptr.open(plugin_type); // may throw
249 
250  // create a new object using the plug-in library
251  PluginType *plugin_object_ptr(plugin_ptr.create());
252 
253  // add the new plug-in object to our map
254  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
255  m_plugin_map.insert(std::make_pair(plugin_id,
256  std::make_pair(plugin_object_ptr, plugin_ptr)));
257 
258  return plugin_object_ptr;
259 }
260 
261 template <typename PluginType>
262 inline PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id)
263 {
264  PluginType *plugin_object_ptr = NULL;
265  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
266  typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
267  if (i != m_plugin_map.end())
268  plugin_object_ptr = i->second.first;
269  return plugin_object_ptr;
270 }
271 
272 template <typename PluginType>
273 inline const PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id) const
274 {
275  const PluginType *plugin_object_ptr = NULL;
276  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
277  typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
278  if (i != m_plugin_map.end())
279  plugin_object_ptr = i->second.first;
280  return plugin_object_ptr;
281 }
282 
283 template <typename PluginType>
284 inline plugin_ptr<PluginType> plugin_manager<PluginType>::get_lib_ptr(const std::string& plugin_id) const
285 {
287  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
288  typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
289  if (i != m_plugin_map.end())
290  plugin_ptr = i->second.second;
291  return plugin_ptr;
292 }
293 
294 template <typename PluginType>
295 inline PluginType *plugin_manager<PluginType>::find(const std::string& resource)
296 {
297  // will point to the matching plug-in object, if found
298  PluginType *plugin_object_ptr = NULL;
299 
300  // lock mutex for thread safety (this should probably use ref counters)
301  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
302 
303  // check if no plug-ins are being managed
304  if (m_plugin_map.empty()) return plugin_object_ptr;
305 
306  // iterate through each plug-in whose identifier may match the resource
307  typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.upper_bound(resource);
308  while (i != m_plugin_map.begin()) {
309  --i;
310 
311  // keep checking while the first part of the strings match
312  if (resource.compare(0, i->first.size(), i->first) != 0) {
313  // the first part no longer matches
314  if (i != m_plugin_map.begin()) {
315  // continue to next plug-in in list if its size is < this one
317  --j;
318  if (j->first.size() < i->first.size())
319  continue;
320  }
321  // otherwise we've reached the end; stop looking for a match
322  break;
323  }
324 
325  // only if the resource matches the plug-in's identifier
326  // or if resource is followed first with a '/' character
327  if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
328  plugin_object_ptr = i->second.first;
329  break;
330  }
331  }
332 
333  return plugin_object_ptr;
334 }
335 
336 template <typename PluginType>
338 {
339  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
340  for (typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.begin();
341  i != m_plugin_map.end(); ++i)
342  {
343  run_func(i->second.first);
344  }
345 }
346 
347 template <typename PluginType>
348 inline void plugin_manager<PluginType>::run(const std::string& plugin_id,
349  PluginRunFunction run_func)
350 {
351  // no need to lock (handled by plugin_manager::get())
352  PluginType *plugin_object_ptr = get(plugin_id);
353  if (plugin_object_ptr == NULL)
354  BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
355  run_func(plugin_object_ptr);
356 }
357 
358 template <typename PluginType>
359 inline boost::uint64_t plugin_manager<PluginType>::get_statistic(PluginStatFunction stat_func) const
360 {
361  boost::uint64_t stat_value = 0;
362  boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
363  for (typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.begin();
364  i != m_plugin_map.end(); ++i)
365  {
366  stat_value += stat_func(i->second.first);
367  }
368  return stat_value;
369 }
370 
371 template <typename PluginType>
372 inline boost::uint64_t plugin_manager<PluginType>::get_statistic(const std::string& plugin_id,
373  PluginStatFunction stat_func) const
374 {
375  // no need to lock (handled by plugin_manager::get())
376  const PluginType *plugin_object_ptr = const_cast<plugin_manager<PluginType>*>(this)->get(plugin_id);
377  if (plugin_object_ptr == NULL)
378  BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
379  return stat_func(plugin_object_ptr);
380 }
381 
382 
383 // plugin_manager::map_type member functions
384 
385 template <typename PluginType>
387 {
388  if (! std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::empty()) {
390  std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin();
391  i != std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end(); ++i)
392  {
393  if (i->second.second.is_open()) {
394  i->second.second.destroy(i->second.first);
395  } else {
396  delete i->second.first;
397  }
398  }
399  this->erase(std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin(),
400  std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end());
401  }
402 }
403 
404 
405 } // end namespace pion
406 
407 #endif
virtual ~plugin_manager()
default destructor
void run(PluginRunFunction run_func)
boost::uint64_t get_statistic(PluginStatFunction stat_func) const
void add(const std::string &plugin_id, PluginType *plugin_object_ptr)
PluginType * load(const std::string &plugin_id, const std::string &plugin_type)
bool empty(void) const
returns true if there are no plug-in objects being managed
exception thrown if we try to add or load a duplicate plugin
Definition: error.hpp:188
PluginType * find(const std::string &resource)
plugin_manager(void)
default constructor
InterfaceClassType * create(void)
creates a new instance of the plug-in object
Definition: plugin.hpp:326
map_type m_plugin_map
collection of plug-in objects being managed
boost::function1< void, PluginType * > PluginRunFunction
data type for a function that may be called by the run() method
exception thrown if a plugin cannot be found
Definition: error.hpp:181
PluginType * clone(const std::string &plugin_id)
PluginType * get(const std::string &plugin_id)
void remove(const std::string &plugin_id)
void clear(void)
clears all the plug-in objects being managed
void open(const std::string &plugin_name)
Definition: plugin.cpp:82
data type that maps identifiers to plug-in objects
plugin_ptr< PluginType > get_lib_ptr(const std::string &plugin_id) const
boost::function1< boost::uint64_t, const PluginType * > PluginStatFunction
data type for a function that may be called by the getStat() method
boost::mutex m_plugin_mutex
mutex to make class thread-safe
void replace(const std::string &plugin_id, PluginType *plugin_ptr)