pion  5.0.6
include/pion/plugin_manager.hpp
00001 // ---------------------------------------------------------------------
00002 // pion:  a Boost C++ framework for building lightweight HTTP interfaces
00003 // ---------------------------------------------------------------------
00004 // Copyright (C) 2007-2014 Splunk Inc.  (https://github.com/splunk/pion)
00005 //
00006 // Distributed under the Boost Software License, Version 1.0.
00007 // See http://www.boost.org/LICENSE_1_0.txt
00008 //
00009 
00010 #ifndef __PION_PLUGIN_MANAGER_HEADER__
00011 #define __PION_PLUGIN_MANAGER_HEADER__
00012 
00013 #include <map>
00014 #include <string>
00015 #include <boost/cstdint.hpp>
00016 #include <boost/assert.hpp>
00017 #include <boost/function.hpp>
00018 #include <boost/function/function1.hpp>
00019 #include <boost/thread/mutex.hpp>
00020 #include <pion/config.hpp>
00021 #include <pion/error.hpp>
00022 #include <pion/plugin.hpp>
00023 
00024 
00025 namespace pion {    // begin namespace pion
00026 
00030 template <typename PluginType>
00031 class plugin_manager
00032 {
00033 public:
00034 
00036     typedef boost::function1<void, PluginType*>    PluginRunFunction;
00037 
00039     typedef boost::function1<boost::uint64_t, const PluginType*>   PluginStatFunction;
00040 
00041     
00043     plugin_manager(void) {}
00044 
00046     virtual ~plugin_manager() {}
00047 
00049     inline void clear(void) {
00050         boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00051         m_plugin_map.clear();
00052     }
00053     
00055     inline bool empty(void) const { 
00056         boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00057         return m_plugin_map.empty();
00058     }
00059     
00066     inline void add(const std::string& plugin_id, PluginType *plugin_object_ptr);
00067     
00073     inline void remove(const std::string& plugin_id);
00074     
00081     inline void replace(const std::string& plugin_id, PluginType *plugin_ptr);
00082     
00089     inline PluginType *clone(const std::string& plugin_id);
00090 
00099     inline PluginType *load(const std::string& plugin_id, const std::string& plugin_type);
00100     
00107     inline PluginType *get(const std::string& plugin_id);
00108     
00115     inline const PluginType *get(const std::string& plugin_id) const;
00116     
00123     inline plugin_ptr<PluginType> get_lib_ptr(const std::string& plugin_id) const;
00124     
00131     inline PluginType *find(const std::string& resource);
00132     
00138     inline void run(PluginRunFunction run_func);
00139     
00146     inline void run(const std::string& plugin_id, PluginRunFunction run_func);
00147     
00153     inline boost::uint64_t get_statistic(PluginStatFunction stat_func) const;
00154     
00161     inline boost::uint64_t get_statistic(const std::string& plugin_id,
00162                                         PluginStatFunction stat_func) const;
00163         
00164     
00165 protected:
00166     
00168     class map_type
00169         : public std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >
00170     {
00171     public:
00172         inline void clear(void);
00173         virtual ~map_type() { map_type::clear(); }
00174         map_type(void) {}
00175     };
00176     
00178     map_type                m_plugin_map;
00179 
00181     mutable boost::mutex    m_plugin_mutex;
00182 };
00183 
00184     
00185 // plugin_manager member functions
00186 
00187 template <typename PluginType>
00188 inline void plugin_manager<PluginType>::add(const std::string& plugin_id,
00189                                             PluginType *plugin_object_ptr)
00190 {
00191     plugin_ptr<PluginType> plugin_ptr;
00192     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00193     m_plugin_map.insert(std::make_pair(plugin_id,
00194                                        std::make_pair(plugin_object_ptr, plugin_ptr)));
00195 }
00196 
00197 template <typename PluginType>
00198 inline void plugin_manager<PluginType>::remove(const std::string& plugin_id)
00199 {
00200     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00201     typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
00202     if (i == m_plugin_map.end())
00203         BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
00204     if (i->second.second.is_open()) {
00205         i->second.second.destroy(i->second.first);
00206     } else {
00207         delete i->second.first;
00208     }
00209     m_plugin_map.erase(i);
00210 }
00211 
00212 template <typename PluginType>
00213 inline void plugin_manager<PluginType>::replace(const std::string& plugin_id, PluginType *plugin_ptr)
00214 {
00215     BOOST_ASSERT(plugin_ptr);
00216     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00217     typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
00218     if (i == m_plugin_map.end())
00219         BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
00220     if (i->second.second.is_open()) {
00221         i->second.second.destroy(i->second.first);
00222     } else {
00223         delete i->second.first;
00224     }
00225     i->second.first = plugin_ptr;
00226 }
00227 
00228 template <typename PluginType>
00229 inline PluginType *plugin_manager<PluginType>::clone(const std::string& plugin_id)
00230 {
00231     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00232     typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
00233     if (i == m_plugin_map.end())
00234         BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
00235     return i->second.second.create();
00236 }
00237 
00238 template <typename PluginType>
00239 inline PluginType *plugin_manager<PluginType>::load(const std::string& plugin_id,
00240                                                      const std::string& plugin_type)
00241 {
00242     // search for the plug-in file using the configured paths
00243     if (m_plugin_map.find(plugin_id) != m_plugin_map.end())
00244         BOOST_THROW_EXCEPTION( error::duplicate_plugin() << error::errinfo_plugin_name(plugin_id) );
00245     
00246     // open up the plug-in's shared object library
00247     plugin_ptr<PluginType> plugin_ptr;
00248     plugin_ptr.open(plugin_type);   // may throw
00249     
00250     // create a new object using the plug-in library
00251     PluginType *plugin_object_ptr(plugin_ptr.create());
00252     
00253     // add the new plug-in object to our map
00254     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00255     m_plugin_map.insert(std::make_pair(plugin_id,
00256                                        std::make_pair(plugin_object_ptr, plugin_ptr)));
00257 
00258     return plugin_object_ptr;
00259 }
00260 
00261 template <typename PluginType>
00262 inline PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id)
00263 {
00264     PluginType *plugin_object_ptr = NULL;
00265     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00266     typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.find(plugin_id);
00267     if (i != m_plugin_map.end())
00268         plugin_object_ptr = i->second.first;
00269     return plugin_object_ptr;
00270 }
00271     
00272 template <typename PluginType>
00273 inline const PluginType *plugin_manager<PluginType>::get(const std::string& plugin_id) const
00274 {
00275     const PluginType *plugin_object_ptr = NULL;
00276     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00277     typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
00278     if (i != m_plugin_map.end())
00279         plugin_object_ptr = i->second.first;
00280     return plugin_object_ptr;
00281 }
00282     
00283 template <typename PluginType>
00284 inline plugin_ptr<PluginType> plugin_manager<PluginType>::get_lib_ptr(const std::string& plugin_id) const
00285 {
00286     plugin_ptr<PluginType> plugin_ptr;
00287     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00288     typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.find(plugin_id);
00289     if (i != m_plugin_map.end())
00290         plugin_ptr = i->second.second;
00291     return plugin_ptr;
00292 }       
00293 
00294 template <typename PluginType>
00295 inline PluginType *plugin_manager<PluginType>::find(const std::string& resource)
00296 {
00297     // will point to the matching plug-in object, if found
00298     PluginType *plugin_object_ptr = NULL;
00299     
00300     // lock mutex for thread safety (this should probably use ref counters)
00301     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00302     
00303     // check if no plug-ins are being managed
00304     if (m_plugin_map.empty()) return plugin_object_ptr;
00305     
00306     // iterate through each plug-in whose identifier may match the resource
00307     typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.upper_bound(resource);
00308     while (i != m_plugin_map.begin()) {
00309         --i;
00310         
00311         // keep checking while the first part of the strings match
00312         if (resource.compare(0, i->first.size(), i->first) != 0) {
00313             // the first part no longer matches
00314             if (i != m_plugin_map.begin()) {
00315                 // continue to next plug-in in list if its size is < this one
00316                 typename pion::plugin_manager<PluginType>::map_type::iterator j=i;
00317                 --j;
00318                 if (j->first.size() < i->first.size())
00319                     continue;
00320             }
00321             // otherwise we've reached the end; stop looking for a match
00322             break;
00323         }
00324         
00325         // only if the resource matches the plug-in's identifier
00326         // or if resource is followed first with a '/' character
00327         if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
00328             plugin_object_ptr = i->second.first;
00329             break;
00330         }
00331     }
00332     
00333     return plugin_object_ptr;
00334 }
00335     
00336 template <typename PluginType>
00337 inline void plugin_manager<PluginType>::run(PluginRunFunction run_func)
00338 {
00339     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00340     for (typename pion::plugin_manager<PluginType>::map_type::iterator i = m_plugin_map.begin();
00341          i != m_plugin_map.end(); ++i)
00342     {
00343         run_func(i->second.first);
00344     }
00345 }
00346 
00347 template <typename PluginType>
00348 inline void plugin_manager<PluginType>::run(const std::string& plugin_id,
00349                                             PluginRunFunction run_func)
00350 {
00351     // no need to lock (handled by plugin_manager::get())
00352     PluginType *plugin_object_ptr = get(plugin_id);
00353     if (plugin_object_ptr == NULL)
00354         BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
00355     run_func(plugin_object_ptr);
00356 }
00357 
00358 template <typename PluginType>
00359 inline boost::uint64_t plugin_manager<PluginType>::get_statistic(PluginStatFunction stat_func) const
00360 {
00361     boost::uint64_t stat_value = 0;
00362     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
00363     for (typename pion::plugin_manager<PluginType>::map_type::const_iterator i = m_plugin_map.begin();
00364          i != m_plugin_map.end(); ++i)
00365     {
00366         stat_value += stat_func(i->second.first);
00367     }
00368     return stat_value;
00369 }
00370 
00371 template <typename PluginType>
00372 inline boost::uint64_t plugin_manager<PluginType>::get_statistic(const std::string& plugin_id,
00373                                                                 PluginStatFunction stat_func) const
00374 {
00375     // no need to lock (handled by plugin_manager::get())
00376     const PluginType *plugin_object_ptr = const_cast<plugin_manager<PluginType>*>(this)->get(plugin_id);
00377     if (plugin_object_ptr == NULL)
00378         BOOST_THROW_EXCEPTION( error::plugin_not_found() << error::errinfo_plugin_name(plugin_id) );
00379     return stat_func(plugin_object_ptr);
00380 }
00381 
00382 
00383 // plugin_manager::map_type member functions
00384 
00385 template <typename PluginType>
00386 inline void plugin_manager<PluginType>::map_type::clear(void)
00387 {
00388     if (! std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::empty()) {
00389         for (typename pion::plugin_manager<PluginType>::map_type::iterator i =
00390              std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin();
00391              i != std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end(); ++i)
00392         {
00393             if (i->second.second.is_open()) {
00394                 i->second.second.destroy(i->second.first);
00395             } else {
00396                 delete i->second.first;
00397             }
00398         }
00399         this->erase(std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::begin(),
00400               std::map<std::string, std::pair<PluginType *, plugin_ptr<PluginType> > >::end());
00401     }
00402 }
00403 
00404 
00405 }   // end namespace pion
00406 
00407 #endif