plugin_manager.hpp
// ---------------------------------------------------------------------
// pion: a Boost C++ framework for building lightweight HTTP interfaces
// ---------------------------------------------------------------------
// Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//
#ifndef __PION_PLUGIN_MANAGER_HEADER__
#define __PION_PLUGIN_MANAGER_HEADER__
#include <map>
#include <string>
#include <boost/cstdint.hpp>
#include <boost/assert.hpp>
#include <boost/function.hpp>
#include <boost/function/function1.hpp>
#include <boost/thread/mutex.hpp>
#include <pion/config.hpp>
#include <pion/error.hpp>
#include <pion/plugin.hpp>
namespace pion { // begin namespace pion
template <typename PluginType>
class plugin_manager
{
public:
typedef boost::function1<void, PluginType*> PluginRunFunction;
typedef boost::function1<boost::uint64_t, const PluginType*> PluginStatFunction;
plugin_manager(void) {}
virtual ~plugin_manager() {}
inline void clear(void) {
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
m_plugin_map.clear();
}
inline bool empty(void) const {
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
return m_plugin_map.empty();
}
inline void add(const std::string& plugin_id, PluginType *plugin_object_ptr);
inline void remove(const std::string& plugin_id);
inline void replace(const std::string& plugin_id, PluginType *plugin_ptr);
inline PluginType *clone(const std::string& plugin_id);
inline PluginType *load(const std::string& plugin_id, const std::string& plugin_type);
inline PluginType *get(const std::string& plugin_id);
inline const PluginType *get(const std::string& plugin_id) const;
inline plugin_ptr<PluginType> get_lib_ptr(const std::string& plugin_id) const;
inline PluginType *find(const std::string& resource);
inline void run(PluginRunFunction run_func);
inline void run(const std::string& plugin_id, PluginRunFunction run_func);
inline boost::uint64_t get_statistic(PluginStatFunction stat_func) const;
inline boost::uint64_t get_statistic(const std::string& plugin_id,
PluginStatFunction stat_func) const;
protected:
class map_type
: public std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >
{
public:
inline void clear(void);
virtual ~map_type() { map_type::clear(); }
map_type(void) {}
};
map_type m_plugin_map;
mutable boost::mutex m_plugin_mutex;
};
// plugin_manager member functions
template <typename PluginType>
inline void plugin_manager<PluginType>::add(const std::string& plugin_id,
PluginType *plugin_object_ptr)
{
plugin_ptr<PluginType> plugin_ptr;
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
m_plugin_map.insert(std::make_pair(plugin_id,
std::make_pair(plugin_object_ptr, plugin_ptr)));
}
template <typename PluginType>
inline void plugin_manager<PluginType>::remove(const std::string& plugin_id)
{
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
if (i == m_plugin_map.end())
BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
if (i->second.second.is_open()) {
i->second.second.destroy(i->second.first);
} else {
delete i->second.first;
}
m_plugin_map.erase(i);
}
template <typename PluginType>
inline void plugin_manager<PluginType>::replace(const std::string& plugin_id, PluginType *plugin_ptr)
{
BOOST_ASSERT(plugin_ptr);
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
if (i == m_plugin_map.end())
BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
if (i->second.second.is_open()) {
i->second.second.destroy(i->second.first);
} else {
delete i->second.first;
}
i->second.first = plugin_ptr;
}
template <typename PluginType>
inline PluginType *plugin_manager<PluginType>::clone(const std::string& plugin_id)
{
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
if (i == m_plugin_map.end())
BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
return i->second.second.create();
}
template <typename PluginType>
inline PluginType *plugin_manager<PluginType>::load(const std::string& plugin_id,
const std::string& plugin_type)
{
// search for the plug-in file using the configured paths
if (m_plugin_map.find(plugin_id) != m_plugin_map.end())
BOOST_THROW_EXCEPTION( error::duplicate_plugin() << error::errinfo_plugin_name(plugin_id) );
// open up the plug-in's shared object library
plugin_ptr<PluginType> plugin_ptr;
plugin_ptr.open(plugin_type); // may throw
// create a new object using the plug-in library
PluginType *plugin_object_ptr(plugin_ptr.create());
// add the new plug-in object to our map
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
m_plugin_map.insert(std::make_pair(plugin_id,
std::make_pair(plugin_object_ptr, plugin_ptr)));
return plugin_object_ptr;
}
template <typename PluginType>
inline PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id)
{
PluginType *plugin_object_ptr = NULL;
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
if (i != m_plugin_map.end())
plugin_object_ptr = i->second.first;
return plugin_object_ptr;
}
template <typename PluginType>
inline const PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id) const
{
const PluginType *plugin_object_ptr = NULL;
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
if (i != m_plugin_map.end())
plugin_object_ptr = i->second.first;
return plugin_object_ptr;
}
template <typename PluginType>
inline plugin_ptr<PluginType> plugin_manager<PluginType>::get_lib_ptr(const std::string& plugin_id) const
{
plugin_ptr<PluginType> plugin_ptr;
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
if (i != m_plugin_map.end())
plugin_ptr = i->second.second;
return plugin_ptr;
}
template <typename PluginType>
inline PluginType *plugin_manager<PluginType>::find(const std::string& resource)
{
// will point to the matching plug-in object, if found
PluginType *plugin_object_ptr = NULL;
// lock mutex for thread safety (this should probably use ref counters)
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
// check if no plug-ins are being managed
if (m_plugin_map.empty()) return plugin_object_ptr;
// iterate through each plug-in whose identifier may match the resource
typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.upper_bound(resource);
while (i != m_plugin_map.begin()) {
--i;
// keep checking while the first part of the strings match
if (resource.compare(0, i->first.size(), i->first) != 0) {
// the first part no longer matches
if (i != m_plugin_map.begin()) {
// continue to next plug-in in list if its size is < this one
typename pion::plugin_manager<PluginType>::map_type::iterator j=i;
--j;
if (j->first.size() < i->first.size())
continue;
}
// otherwise we've reached the end; stop looking for a match
break;
}
// only if the resource matches the plug-in's identifier
// or if resource is followed first with a '/' character
if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
plugin_object_ptr = i->second.first;
break;
}
}
return plugin_object_ptr;
}
template <typename PluginType>
inline void plugin_manager<PluginType>::run(PluginRunFunction run_func)
{
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
for (typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.begin();
i != m_plugin_map.end(); ++i)
{
run_func(i->second.first);
}
}
template <typename PluginType>
inline void plugin_manager<PluginType>::run(const std::string& plugin_id,
PluginRunFunction run_func)
{
// no need to lock (handled by plugin_manager::get())
PluginType *plugin_object_ptr = get(plugin_id);
if (plugin_object_ptr == NULL)
BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
run_func(plugin_object_ptr);
}
template <typename PluginType>
inline boost::uint64_t plugin_manager<PluginType>::get_statistic(PluginStatFunction stat_func) const
{
boost::uint64_t stat_value = 0;
boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
for (typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.begin();
i != m_plugin_map.end(); ++i)
{
stat_value += stat_func(i->second.first);
}
return stat_value;
}
template <typename PluginType>
inline boost::uint64_t plugin_manager<PluginType>::get_statistic(const std::string& plugin_id,
PluginStatFunction stat_func) const
{
// no need to lock (handled by plugin_manager::get())
const PluginType *plugin_object_ptr = const_cast<plugin_manager<PluginType>*>(this)->get(plugin_id);
if (plugin_object_ptr == NULL)
BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
return stat_func(plugin_object_ptr);
}
// plugin_manager::map_type member functions
template <typename PluginType>
inline void plugin_manager<PluginType>::map_type::clear(void)
{
if (! std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::empty()) {
for (typename pion::plugin_manager<PluginType>::map_type::iterator i =
std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin();
i != std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end(); ++i)
{
if (i->second.second.is_open()) {
i->second.second.destroy(i->second.first);
} else {
delete i->second.first;
}
}
this->erase(std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin(),
std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end());
}
}
} // end namespace pion
#endif
pion::plugin_manager::~plugin_manager
virtual ~plugin_manager()
default destructor
Definition: plugin_manager.hpp:46
pion::plugin_manager::run
void run(PluginRunFunction run_func)
Definition: plugin_manager.hpp:337
pion::plugin_ptr
Definition: plugin.hpp:301
pion::plugin_manager::add
void add(const std::string &plugin_id, PluginType *plugin_object_ptr)
Definition: plugin_manager.hpp:188
pion::plugin_manager::load
PluginType * load(const std::string &plugin_id, const std::string &plugin_type)
Definition: plugin_manager.hpp:239
pion::error::duplicate_plugin
exception thrown if we try to add or load a duplicate plugin
Definition: error.hpp:188
pion::plugin_manager
Definition: plugin_manager.hpp:31
pion::plugin_manager::find
PluginType * find(const std::string &resource)
Definition: plugin_manager.hpp:295
pion::plugin_manager::plugin_manager
plugin_manager(void)
default constructor
Definition: plugin_manager.hpp:43
pion::plugin_ptr::create
InterfaceClassType * create(void)
creates a new instance of the plug-in object
Definition: plugin.hpp:326
pion::plugin_manager::get_lib_ptr
plugin_ptr< PluginType > get_lib_ptr(const std::string &plugin_id) const
Definition: plugin_manager.hpp:284
pion::plugin_manager::m_plugin_map
map_type m_plugin_map
collection of plug-in objects being managed
Definition: plugin_manager.hpp:178
pion::plugin_manager::PluginRunFunction
boost::function1< void, PluginType * > PluginRunFunction
data type for a function that may be called by the run() method
Definition: plugin_manager.hpp:36
pion::error::plugin_not_found
exception thrown if a plugin cannot be found
Definition: error.hpp:181
pion::plugin_manager::clone
PluginType * clone(const std::string &plugin_id)
Definition: plugin_manager.hpp:229
pion::plugin_manager::get
PluginType * get(const std::string &plugin_id)
Definition: plugin_manager.hpp:262
pion::plugin_manager::remove
void remove(const std::string &plugin_id)
Definition: plugin_manager.hpp:198
pion::plugin_manager::clear
void clear(void)
clears all the plug-in objects being managed
Definition: plugin_manager.hpp:49
pion::plugin::open
void open(const std::string &plugin_name)
Definition: plugin.cpp:82
pion::plugin_manager::map_type
data type that maps identifiers to plug-in objects
Definition: plugin_manager.hpp:168
pion
Definition: admin_rights.hpp:19
pion::plugin_manager::PluginStatFunction
boost::function1< boost::uint64_t, const PluginType * > PluginStatFunction
data type for a function that may be called by the getStat() method
Definition: plugin_manager.hpp:39
pion::plugin_manager::get_statistic
boost::uint64_t get_statistic(PluginStatFunction stat_func) const
Definition: plugin_manager.hpp:359
pion::plugin_manager::empty
bool empty(void) const
returns true if there are no plug-in objects being managed
Definition: plugin_manager.hpp:55
pion::plugin_manager::m_plugin_mutex
boost::mutex m_plugin_mutex
mutex to make class thread-safe
Definition: plugin_manager.hpp:181
pion::plugin_manager::replace
void replace(const std::string &plugin_id, PluginType *plugin_ptr)
Definition: plugin_manager.hpp:213