pion  5.0.6
include/pion/plugin.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_HEADER__
00011 #define __PION_PLUGIN_HEADER__
00012 
00013 #include <vector>
00014 #include <string>
00015 #include <map>
00016 #include <list>
00017 #include <boost/noncopyable.hpp>
00018 #include <boost/thread/once.hpp>
00019 #include <boost/thread/mutex.hpp>
00020 #include <boost/filesystem/path.hpp>
00021 #include <pion/config.hpp>
00022 #include <pion/error.hpp>
00023 
00024 
00025 namespace pion {    // begin namespace pion
00026 
00030 class PION_API plugin {
00031 public:
00032 
00040     static inline bool find_plugin_file(std::string& path_to_file,
00041                                       const std::string& name)
00042     {
00043         return find_file(path_to_file, name, PION_PLUGIN_EXTENSION);
00044     }
00045 
00053     static inline bool find_config_file(std::string& path_to_file,
00054                                       const std::string& name)
00055     {
00056         return find_file(path_to_file, name, PION_CONFIG_EXTENSION);
00057     }
00058     
00067     static void add_static_entry_point(const std::string& plugin_name,
00068                                     void *create_func,
00069                                     void *destroy_func);
00070     
00079     static void check_cygwin_path(boost::filesystem::path& final_path,
00080                                 const std::string& path_string);
00081 
00083     static void add_plugin_directory(const std::string& dir);
00084     
00086     static void reset_plugin_directories(void);
00087     
00088 
00089     // default destructor
00090     virtual ~plugin() { release_data(); }
00091     
00093     inline bool is_open(void) const { return (m_plugin_data != NULL); }
00094     
00096     inline std::string get_plugin_name(void) const {
00097         return (is_open() ? m_plugin_data->m_plugin_name : std::string());
00098     }
00099 
00101     static void get_all_plugin_names(std::vector<std::string>& plugin_names);
00102 
00115     void open(const std::string& plugin_name);
00116 
00129     void open_file(const std::string& plugin_file);
00130 
00132     inline void close(void) { release_data(); }
00133 
00134 protected:
00135     
00139     struct data_type
00140     {
00142         data_type(void)
00143             : m_lib_handle(NULL), m_create_func(NULL), m_destroy_func(NULL),
00144             m_references(0)
00145         {}
00146         data_type(const std::string& plugin_name)
00147             : m_lib_handle(NULL), m_create_func(NULL), m_destroy_func(NULL),
00148             m_plugin_name(plugin_name), m_references(0)
00149         {}
00150         data_type(const data_type& p)
00151             : m_lib_handle(p.m_lib_handle), m_create_func(p.m_create_func),
00152             m_destroy_func(p.m_destroy_func), m_plugin_name(p.m_plugin_name),
00153             m_references(p.m_references)
00154         {}
00155         
00157         void *          m_lib_handle;
00158         
00160         void *          m_create_func;
00161         
00163         void *          m_destroy_func;
00164         
00166         std::string     m_plugin_name;
00167         
00169         unsigned long   m_references;
00170     };
00171 
00172     
00174     plugin(void) : m_plugin_data(NULL) {}
00175     
00177     plugin(const plugin& p) : m_plugin_data(NULL) { grab_data(p); }
00178 
00180     plugin& operator=(const plugin& p) { grab_data(p); return *this; }
00181 
00183     inline void *get_create_function(void) {
00184         return (is_open() ? m_plugin_data->m_create_func : NULL);
00185     }
00186 
00188     inline void *get_destroy_function(void) {
00189         return (is_open() ? m_plugin_data->m_destroy_func : NULL);
00190     }
00191 
00193     void release_data(void);
00194     
00196     void grab_data(const plugin& p);
00197 
00198     
00199 private:
00200 
00202     typedef std::map<std::string, data_type*>  map_type;
00203 
00205     struct config_type {
00207         std::vector<std::string>    m_plugin_dirs;
00208         
00210         map_type                    m_plugin_map;
00211         
00213         boost::mutex                m_plugin_mutex;
00214     };
00215 
00216     
00218     static inline config_type& get_plugin_config(void) {
00219         boost::call_once(plugin::create_plugin_config, m_instance_flag);
00220         return *m_config_ptr;
00221     }
00222     
00224     static void create_plugin_config(void);
00225 
00235     static bool find_file(std::string& path_to_file, const std::string& name,                             
00236                          const std::string& extension);
00237     
00248     static bool check_for_file(std::string& final_path, const std::string& start_path,
00249                              const std::string& name, const std::string& extension);
00250     
00257     static void open_plugin(const std::string& plugin_file,
00258                            data_type& plugin_data);
00259 
00261     static std::string get_plugin_name(const std::string& plugin_file);
00262     
00264     static void *load_dynamic_library(const std::string& plugin_file);
00265     
00267     static void close_dynamic_library(void *lib_handle);
00268     
00270     static void *get_library_symbol(void *lib_handle, const std::string& symbol);
00271     
00272     
00274     static const std::string            PION_PLUGIN_CREATE;
00275     
00277     static const std::string            PION_PLUGIN_DESTROY;
00278     
00280     static const std::string            PION_PLUGIN_EXTENSION;
00281     
00283     static const std::string            PION_CONFIG_EXTENSION;
00284     
00286     static boost::once_flag             m_instance_flag;
00287 
00289     static config_type *           m_config_ptr;
00290 
00292     data_type *                    m_plugin_data;
00293 };
00294 
00295 
00300 template <typename InterfaceClassType>
00301 class plugin_ptr :
00302     public plugin
00303 {
00304 protected:
00305     
00307     typedef InterfaceClassType* CreateObjectFunction(void);
00308     
00310     typedef void DestroyObjectFunction(InterfaceClassType*);
00311 
00312     
00313 public:
00314 
00316     plugin_ptr(void) : plugin() {}
00317     virtual ~plugin_ptr() {}
00318     
00320     plugin_ptr(const plugin_ptr& p) : plugin(p) {}
00321 
00323     plugin_ptr& operator=(const plugin_ptr& p) { grab_data(p); return *this; }
00324 
00326     inline InterfaceClassType *create(void) {
00327         CreateObjectFunction *create_func =
00328             (CreateObjectFunction*)(get_create_function());
00329         if (create_func == NULL)
00330             BOOST_THROW_EXCEPTION( error::plugin_undefined() );
00331         return create_func();
00332     }
00333     
00335     inline void destroy(InterfaceClassType *object_ptr) {
00336         // fix warning ISO C++ forbids casting from pointer-to-object
00337         // to pointer to function
00338         union {
00339             void* v_;
00340             DestroyObjectFunction* f_;
00341         } Cast;
00342         Cast.v_ = get_destroy_function();
00343         DestroyObjectFunction *destroy_func = Cast.f_;
00344         if (destroy_func == NULL)
00345             BOOST_THROW_EXCEPTION( error::plugin_undefined() );
00346         destroy_func(object_ptr);
00347     }
00348 };
00349 
00350 
00354 template <typename InterfaceClassType>
00355 class plugin_instance_ptr :
00356     private boost::noncopyable
00357 {
00358 public:
00359 
00361     plugin_instance_ptr(void) : m_instance_ptr(NULL) {}
00362     
00364     virtual ~plugin_instance_ptr() { reset(); }
00365     
00367     inline void reset(void) { 
00368         if (m_instance_ptr) {
00369             m_plugin_ptr.destroy(m_instance_ptr);
00370         }
00371     }
00372     
00374     inline void create(const std::string& plugin_type) {
00375         reset();
00376         m_plugin_ptr.open(plugin_type);
00377         m_instance_ptr = m_plugin_ptr.create();
00378     }
00379     
00381     inline bool empty(void) const { return m_instance_ptr==NULL; }
00382     
00384     inline InterfaceClassType *get(void) { return m_instance_ptr; }
00385     
00387     inline InterfaceClassType& operator*(void) { return *m_instance_ptr; }
00388 
00390     inline const InterfaceClassType& operator*(void) const { return *m_instance_ptr; }
00391 
00393     inline InterfaceClassType* operator->(void) { return m_instance_ptr; }
00394 
00396     inline const InterfaceClassType* operator->(void) const { return m_instance_ptr; }
00397     
00398     
00399 protected:
00400 
00402     plugin_ptr<InterfaceClassType>   m_plugin_ptr;
00403     
00405     InterfaceClassType  *               m_instance_ptr;
00406 };
00407 
00408 
00422 #ifdef PION_STATIC_LINKING
00423 
00424 #define PION_DECLARE_PLUGIN(plugin_name)    \
00425     class plugin_name;                      \
00426     extern "C" plugin_name *pion_create_##plugin_name(void); \
00427     extern "C" void pion_destroy_##plugin_name(plugin_name *plugin_ptr); \
00428     static pion::static_entry_point_helper helper_##plugin_name(#plugin_name, (void*) pion_create_##plugin_name, (void*) pion_destroy_##plugin_name);
00429 
00431 class static_entry_point_helper {
00432 public:
00433     static_entry_point_helper(const std::string& name, void *create, void *destroy)
00434     {
00435         pion::plugin::add_static_entry_point(name, create, destroy);
00436     }
00437 };
00438 
00439 #else
00440 
00441 #define PION_DECLARE_PLUGIN(plugin_name)
00442 
00443 #endif
00444 
00445 }   // end namespace pion
00446 
00447 #endif