# common/include/pion/PluginManager.hpp

    00001 // -----------------------------------------------------------------------
    00002 // pion-common: a collection of common libraries used by the Pion Platform
    00003 // -----------------------------------------------------------------------
    00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
    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_PLUGINMANAGER_HEADER__
    00011 #define __PION_PLUGINMANAGER_HEADER__
    00012
    00013 #include <map>
    00014 #include <string>
    00015 #include <boost/cstdint.hpp>
    00016 #include <boost/function.hpp>
    00017 #include <boost/function/function1.hpp>
    00018 #include <boost/thread/mutex.hpp>
    00019 #include <pion/PionConfig.hpp>
    00020 #include <pion/PionException.hpp>
    00021 #include <pion/PionPlugin.hpp>
    00022
    00023
    00024 namespace pion {    // begin namespace pion
    00025
    00029 template <typename PLUGIN_TYPE>
    00030 class PluginManager
    00031 {
    00032 public:
    00033
    00035     class PluginNotFoundException : public PionException {
    00036     public:
    00037         PluginNotFoundException(const std::string& plugin_id)
    00038             : PionException("No plug-ins found for identifier: ", plugin_id) {}
    00039     };
    00040
    00042     class DuplicatePluginException : public PionException {
    00043     public:
    00044         DuplicatePluginException(const std::string& plugin_id)
    00045             : PionException("A plug-in already exists for identifier: ", plugin_id) {}
    00046     };
    00047
    00049     typedef boost::function1<void, PLUGIN_TYPE*>    PluginRunFunction;
    00050
    00052     typedef boost::function1<boost::uint64_t, const PLUGIN_TYPE*>   PluginStatFunction;
    00053
    00054
    00056     PluginManager(void) {}
    00057
    00059     virtual ~PluginManager() {}
    00060
    00062     inline void clear(void) {
    00063         boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00064         m_plugin_map.clear();
    00065     }
    00066
    00068     inline bool empty(void) const {
    00069         boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00070         return m_plugin_map.empty();
    00071     }
    00072
    00079     inline void add(const std::string& plugin_id, PLUGIN_TYPE *plugin_object_ptr);
    00080
    00086     inline void remove(const std::string& plugin_id);
    00087
    00094     inline void replace(const std::string& plugin_id, PLUGIN_TYPE *plugin_ptr);
    00095
    00102     inline PLUGIN_TYPE *clone(const std::string& plugin_id);
    00103
    00112     inline PLUGIN_TYPE *load(const std::string& plugin_id, const std::string& plugin_type);
    00113
    00120     inline PLUGIN_TYPE *get(const std::string& plugin_id);
    00121
    00128     inline const PLUGIN_TYPE *get(const std::string& plugin_id) const;
    00129
    00136     inline PionPluginPtr<PLUGIN_TYPE> getLibPtr(const std::string& plugin_id) const;
    00137
    00144     inline PLUGIN_TYPE *find(const std::string& resource);
    00145
    00151     inline void run(PluginRunFunction run_func);
    00152
    00159     inline void run(const std::string& plugin_id, PluginRunFunction run_func);
    00160
    00166     inline boost::uint64_t getStatistic(PluginStatFunction stat_func) const;
    00167
    00174     inline boost::uint64_t getStatistic(const std::string& plugin_id,
    00175                                         PluginStatFunction stat_func) const;
    00176
    00177
    00178 protected:
    00179
    00181     class PluginMap
    00182         : public std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >
    00183     {
    00184     public:
    00185         inline void clear(void);
    00186         virtual ~PluginMap() { PluginMap::clear(); }
    00187         PluginMap(void) {}
    00188     };
    00189
    00191     PluginMap                       m_plugin_map;
    00192
    00194     mutable boost::mutex            m_plugin_mutex;
    00195 };
    00196
    00197
    00198 // PluginManager member functions
    00199
    00200 template <typename PLUGIN_TYPE>
    00201 inline void PluginManager<PLUGIN_TYPE>::add(const std::string& plugin_id,
    00202                                             PLUGIN_TYPE *plugin_object_ptr)
    00203 {
    00204     PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
    00205     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00206     m_plugin_map.insert(std::make_pair(plugin_id,
    00207                                        std::make_pair(plugin_object_ptr, plugin_ptr)));
    00208 }
    00209
    00210 template <typename PLUGIN_TYPE>
    00211 inline void PluginManager<PLUGIN_TYPE>::remove(const std::string& plugin_id)
    00212 {
    00213     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00214     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
    00215     if (i == m_plugin_map.end())
    00216         throw PluginNotFoundException(plugin_id);
    00217     if (i->second.second.is_open()) {
    00218         i->second.second.destroy(i->second.first);
    00219     } else {
    00220         delete i->second.first;
    00221     }
    00222     m_plugin_map.erase(i);
    00223 }
    00224
    00225 template <typename PLUGIN_TYPE>
    00226 inline void PluginManager<PLUGIN_TYPE>::replace(const std::string& plugin_id, PLUGIN_TYPE *plugin_ptr)
    00227 {
    00228     PION_ASSERT(plugin_ptr);
    00229     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00230     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
    00231     if (i == m_plugin_map.end())
    00232         throw PluginNotFoundException(plugin_id);
    00233     if (i->second.second.is_open()) {
    00234         i->second.second.destroy(i->second.first);
    00235     } else {
    00236         delete i->second.first;
    00237     }
    00238     i->second.first = plugin_ptr;
    00239 }
    00240
    00241 template <typename PLUGIN_TYPE>
    00242 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::clone(const std::string& plugin_id)
    00243 {
    00244     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00245     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
    00246     if (i == m_plugin_map.end())
    00247         throw PluginNotFoundException(plugin_id);
    00248     return i->second.second.create();
    00249 }
    00250
    00251 template <typename PLUGIN_TYPE>
    00252 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::load(const std::string& plugin_id,
    00253                                                      const std::string& plugin_type)
    00254 {
    00255     // search for the plug-in file using the configured paths
    00256     bool is_static;
    00257     void *create_func;
    00258     void *destroy_func;
    00259
    00260     if (m_plugin_map.find(plugin_id) != m_plugin_map.end())
    00261         throw DuplicatePluginException(plugin_id);
    00262
    00263     // check if plug-in is statically linked, and if not, try to resolve for dynamic
    00264     is_static = PionPlugin::findStaticEntryPoint(plugin_type, &create_func, &destroy_func);
    00265
    00266     // open up the plug-in's shared object library
    00267     PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
    00268     if (is_static) {
    00269         plugin_ptr.openStaticLinked(plugin_type, create_func, destroy_func);    // may throw
    00270     } else {
    00271         plugin_ptr.open(plugin_type);   // may throw
    00272     }
    00273
    00274     // create a new object using the plug-in library
    00275     PLUGIN_TYPE *plugin_object_ptr(plugin_ptr.create());
    00276
    00277     // add the new plug-in object to our map
    00278     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00279     m_plugin_map.insert(std::make_pair(plugin_id,
    00280                                        std::make_pair(plugin_object_ptr, plugin_ptr)));
    00281
    00282     return plugin_object_ptr;
    00283 }
    00284
    00285 template <typename PLUGIN_TYPE>
    00286 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::get(const std::string& plugin_id)
    00287 {
    00288     PLUGIN_TYPE *plugin_object_ptr = NULL;
    00289     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00290     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.find(plugin_id);
    00291     if (i != m_plugin_map.end())
    00292         plugin_object_ptr = i->second.first;
    00293     return plugin_object_ptr;
    00294 }
    00295
    00296 template <typename PLUGIN_TYPE>
    00297 inline const PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::get(const std::string& plugin_id) const
    00298 {
    00299     const PLUGIN_TYPE *plugin_object_ptr = NULL;
    00300     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00301     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.find(plugin_id);
    00302     if (i != m_plugin_map.end())
    00303         plugin_object_ptr = i->second.first;
    00304     return plugin_object_ptr;
    00305 }
    00306
    00307 template <typename PLUGIN_TYPE>
    00308 inline PionPluginPtr<PLUGIN_TYPE> PluginManager<PLUGIN_TYPE>::getLibPtr(const std::string& plugin_id) const
    00309 {
    00310     PionPluginPtr<PLUGIN_TYPE> plugin_ptr;
    00311     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00312     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.find(plugin_id);
    00313     if (i != m_plugin_map.end())
    00314         plugin_ptr = i->second.second;
    00315     return plugin_ptr;
    00316 }
    00317
    00318 template <typename PLUGIN_TYPE>
    00319 inline PLUGIN_TYPE *PluginManager<PLUGIN_TYPE>::find(const std::string& resource)
    00320 {
    00321     // will point to the matching plug-in object, if found
    00322     PLUGIN_TYPE *plugin_object_ptr = NULL;
    00323
    00324     // lock mutex for thread safety (this should probably use ref counters)
    00325     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00326
    00327     // check if no plug-ins are being managed
    00328     if (m_plugin_map.empty()) return plugin_object_ptr;
    00329
    00330     // iterate through each plug-in whose identifier may match the resource
    00331     typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.upper_bound(resource);
    00332     while (i != m_plugin_map.begin()) {
    00333         --i;
    00334
    00335         // keep checking while the first part of the strings match
    00336         if (resource.compare(0, i->first.size(), i->first) != 0) {
    00337             // the first part no longer matches
    00338             if (i != m_plugin_map.begin()) {
    00339                 // continue to next plug-in in list if its size is < this one
    00340                 typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator j=i;
    00341                 --j;
    00342                 if (j->first.size() < i->first.size())
    00343                     continue;
    00344             }
    00345             // otherwise we've reached the end; stop looking for a match
    00346             break;
    00347         }
    00348
    00349         // only if the resource matches the plug-in's identifier
    00350         // or if resource is followed first with a '/' character
    00351         if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
    00352             plugin_object_ptr = i->second.first;
    00353             break;
    00354         }
    00355     }
    00356
    00357     return plugin_object_ptr;
    00358 }
    00359
    00360 template <typename PLUGIN_TYPE>
    00361 inline void PluginManager<PLUGIN_TYPE>::run(PluginRunFunction run_func)
    00362 {
    00363     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00364     for (typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i = m_plugin_map.begin();
    00365          i != m_plugin_map.end(); ++i)
    00366     {
    00367         run_func(i->second.first);
    00368     }
    00369 }
    00370
    00371 template <typename PLUGIN_TYPE>
    00372 inline void PluginManager<PLUGIN_TYPE>::run(const std::string& plugin_id,
    00373                                             PluginRunFunction run_func)
    00374 {
    00375     // no need to lock (handled by PluginManager::get())
    00376     PLUGIN_TYPE *plugin_object_ptr = get(plugin_id);
    00377     if (plugin_object_ptr == NULL)
    00378         throw PluginNotFoundException(plugin_id);
    00379     run_func(plugin_object_ptr);
    00380 }
    00381
    00382 template <typename PLUGIN_TYPE>
    00383 inline boost::uint64_t PluginManager<PLUGIN_TYPE>::getStatistic(PluginStatFunction stat_func) const
    00384 {
    00385     boost::uint64_t stat_value = 0;
    00386     boost::mutex::scoped_lock plugins_lock(m_plugin_mutex);
    00387     for (typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::const_iterator i = m_plugin_map.begin();
    00388          i != m_plugin_map.end(); ++i)
    00389     {
    00390         stat_value += stat_func(i->second.first);
    00391     }
    00392     return stat_value;
    00393 }
    00394
    00395 template <typename PLUGIN_TYPE>
    00396 inline boost::uint64_t PluginManager<PLUGIN_TYPE>::getStatistic(const std::string& plugin_id,
    00397                                                                 PluginStatFunction stat_func) const
    00398 {
    00399     // no need to lock (handled by PluginManager::get())
    00400     const PLUGIN_TYPE *plugin_object_ptr = const_cast<PluginManager<PLUGIN_TYPE>*>(this)->get(plugin_id);
    00401     if (plugin_object_ptr == NULL)
    00402         throw PluginNotFoundException(plugin_id);
    00403     return stat_func(plugin_object_ptr);
    00404 }
    00405
    00406
    00407 // PluginManager::PluginMap member functions
    00408
    00409 template <typename PLUGIN_TYPE>
    00410 inline void PluginManager<PLUGIN_TYPE>::PluginMap::clear(void)
    00411 {
    00412     if (! std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::empty()) {
    00413         for (typename pion::PluginManager<PLUGIN_TYPE>::PluginMap::iterator i =
    00414              std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::begin();
    00415              i != std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::end(); ++i)
    00416         {
    00417             if (i->second.second.is_open()) {
    00418                 i->second.second.destroy(i->second.first);
    00419             } else {
    00420                 delete i->second.first;
    00421             }
    00422         }
    00423         erase(std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::begin(),
    00424               std::map<std::string, std::pair<PLUGIN_TYPE *, PionPluginPtr<PLUGIN_TYPE> > >::end());
    00425     }
    00426 }
    00427
    00428
    00429 }   // end namespace pion
    00430
    00431 #endif