pion-net
4.0.9
|
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 this->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