- Main Page
- Classes
- Files

- File List

# 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