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 (! 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

Generated on Fri Apr 30 14:48:53 2010 for pion-net by  doxygen 1.4.7