pion
5.0.6
|
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