PluginManager.h
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00027 //----------------------------------------------------------------------
00028 #ifndef ICL_CORE_PLUGIN_PLUGIN_MANAGER_H_INCLUDED
00029 #define ICL_CORE_PLUGIN_PLUGIN_MANAGER_H_INCLUDED
00030 
00031 #include "icl_core_plugin/ImportExport.h"
00032 #include "icl_core_plugin/Logging.h"
00033 #include "icl_core_plugin/PluginManagerBase.h"
00034 
00035 #include <boost/filesystem.hpp>
00036 #include <boost/algorithm/string/predicate.hpp>
00037 
00038 #include <cassert>
00039 #include <string>
00040 #include <list>
00041 #include <map>
00042 #include <iostream>
00043 #include <sstream>
00044 
00045 #include <dlfcn.h>
00046 
00047 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00048 # include "icl_core/Deprecate.h"
00049 #endif
00050 
00051 namespace icl_core {
00053 namespace plugin {
00054 
00055 typedef void* PluginHandle;
00056 
00059 template <class T, const char* const plugin_dir>
00060 class PluginManager: public PluginManagerBase
00061 {
00062 public:
00063   ~PluginManager()
00064   {
00065     while (!m_plugin_handles.empty() && !m_loaded_plugins.empty())
00066     {
00067       closePluginHandle(m_loaded_plugins.begin()->first);
00068     }
00069 
00070     static PluginManager<T, plugin_dir>* m_instance;
00071     m_instance = 0;
00072     (void) m_instance;
00073   }
00074 
00076   static PluginManager<T, plugin_dir> *instance()
00077   {
00079     static PluginManager<T, plugin_dir> *m_instance = 0;
00080 
00081     if (!m_instance)
00082     {
00083       m_instance = new PluginManager<T, plugin_dir>();
00084     }
00085 
00086     assert(m_instance);
00087     return m_instance;
00088   }
00089 
00091   bool initialize(bool load_lazy = true, bool recursive_search = false)
00092   {
00093     if (isInitialized() && loadLazy() && !load_lazy)
00094     {
00095       loadPlugins();
00096       return true;
00097     }
00098 
00099     if (isInitialized())
00100     {
00101       LOGGING_WARNING(Plugin, "The plugin framework is already initialized!" << icl_core::logging::endl);
00102       return true;
00103     }
00104 
00105     initializePlugins(recursive_search);
00106 
00107     if (!load_lazy)
00108     {
00109       loadPlugins();
00110     }
00111     else
00112     {
00113       m_lazy_loading = true;
00114     }
00115 
00116     return true;
00117   }
00118 
00119   bool isInitialized() const
00120   {
00121     return m_initialized;
00122   }
00123 
00124   bool loadLazy() const
00125   {
00126     return m_lazy_loading;
00127   }
00128 
00131   std::list<std::string> availablePlugins()
00132   {
00133     if (!isInitialized())
00134     {
00135       initialize(false);
00136     }
00137 
00138     if (loadLazy())
00139     {
00140       loadPlugins();
00141     }
00142 
00143     std::list<std::string> result;
00144     typename std::map<std::string, PluginHandle>::const_iterator iter;
00145     for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
00146     {
00147       result.push_back(iter->first);
00148     }
00149 
00150     typename std::map<std::string, T*>::const_iterator siter;
00151     for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
00152     {
00153       result.push_back(siter->first);
00154     }
00155 
00156     return result;
00157   }
00158 
00161   std::list<T*> plugins()
00162   {
00163     if (!isInitialized())
00164     {
00165       initialize(false);
00166     }
00167 
00168     if (loadLazy())
00169     {
00170       loadPlugins();
00171     }
00172 
00173     std::list<T*> result;
00174     typename std::map<std::string, T*>::const_iterator iter;
00175     for (iter = m_loaded_plugins.begin(); iter != m_loaded_plugins.end(); ++iter)
00176     {
00177       result.push_back(iter->second);
00178     }
00179 
00180     typename std::map<std::string, T*>::const_iterator siter;
00181     for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
00182     {
00183       result.push_back(siter->second);
00184     }
00185 
00186     return result;
00187   }
00188 
00192   T* plugin(const std::string &identifier)
00193   {
00194     if (!isInitialized())
00195     {
00196       initialize(false);
00197     }
00198 
00199     if (loadLazy())
00200     {
00201       loadPlugins();
00202     }
00203 
00204     if (m_static_plugins.find(identifier) != m_static_plugins.end())
00205     {
00206       return m_static_plugins[identifier];
00207     }
00208 
00209     return m_loaded_plugins[identifier];
00210   }
00211 
00215   T* createPluginInstance(const std::string &identifier)
00216   {
00217     if (!isInitialized())
00218     {
00219       initialize(false);
00220     }
00221 
00222     if (loadLazy())
00223     {
00224       loadPlugins();
00225     }
00226 
00227     PluginHandle plugin_handle = m_plugin_handles[identifier];
00228     return loadPluginInstance(plugin_handle, identifier);
00229   }
00230 
00239   void addStaticPlugin(T* instance)
00240   {
00241     removeStaticPlugin(instance->Identifier());
00242     m_static_plugins[instance->Identifier()] = instance;
00243     LOGGING_DEBUG(Plugin, "Static plugin " << instance->Identifier() << " added." << icl_core::logging::endl);
00244   }
00245 
00249   void removeStaticPlugin(const std::string &identifier)
00250   {
00251     m_static_plugins.erase(identifier);
00252     LOGGING_DEBUG(Plugin, "Static plugin " << identifier << " removed."
00253                   << icl_core::logging::endl);
00254   }
00255 
00260   bool isStaticPlugin(const std::string &identifier) const
00261   {
00262     return m_static_plugins.find(identifier) != m_static_plugins.end();
00263   }
00264 
00266 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00267 
00271   static ICL_CORE_VC_DEPRECATE_STYLE PluginManager<T, plugin_dir> *Instance()
00272     ICL_CORE_GCC_DEPRECATE_STYLE
00273   { return instance(); }
00274 
00278   ICL_CORE_VC_DEPRECATE_STYLE bool Initialize(bool load_lazy = true,
00279                                               bool recursive_search = false)
00280     ICL_CORE_GCC_DEPRECATE_STYLE
00281   { return initialize(load_lazy, recursive_search); }
00282 
00283   ICL_CORE_VC_DEPRECATE_STYLE bool IsInitialized() const
00284     ICL_CORE_GCC_DEPRECATE_STYLE
00285   { return isInitialized(); }
00286 
00287   ICL_CORE_VC_DEPRECATE_STYLE bool LoadLazy() const
00288     ICL_CORE_GCC_DEPRECATE_STYLE
00289   { return loadLazy(); }
00290 
00294   ICL_CORE_VC_DEPRECATE_STYLE std::list<std::string> AvailablePlugins()
00295     ICL_CORE_GCC_DEPRECATE_STYLE
00296   { return availablePlugins(); }
00297 
00301   ICL_CORE_VC_DEPRECATE_STYLE std::list<T*> Plugins()
00302     ICL_CORE_GCC_DEPRECATE_STYLE
00303   { return plugins(); }
00304 
00308   ICL_CORE_VC_DEPRECATE_STYLE T* Plugin(const std::string &identifier)
00309     ICL_CORE_GCC_DEPRECATE_STYLE
00310   { return plugin(identifier); }
00311 
00315   ICL_CORE_VC_DEPRECATE_STYLE T* CreatePluginInstance(const std::string &identifier)
00316     ICL_CORE_GCC_DEPRECATE_STYLE
00317   { return createPluginInstance(identifier); }
00318 
00322   ICL_CORE_VC_DEPRECATE_STYLE void AddStaticPlugin(T* instance)
00323     ICL_CORE_GCC_DEPRECATE_STYLE
00324   { addStaticPlugin(instance); }
00325 
00329   ICL_CORE_VC_DEPRECATE_STYLE void RemoveStaticPlugin(const std::string &identifier)
00330     ICL_CORE_GCC_DEPRECATE_STYLE
00331   { removeStaticPlugin(identifier); }
00332 
00337   ICL_CORE_VC_DEPRECATE_STYLE bool IsStaticPlugin(const std::string &identifier) const
00338     ICL_CORE_GCC_DEPRECATE_STYLE
00339   { return isStaticPlugin(identifier); }
00340 
00341 #endif
00342 
00343 
00344 protected:
00346   PluginManager()
00347     : PluginManagerBase(plugin_dir),
00348       m_initialized(false),
00349       m_lazy_loading(false)
00350   {
00351     // nothing to do
00352   }
00353 
00357   void initializePlugins(bool recursive_search)
00358   {
00359     assert(!isInitialized());
00360     clearErrorMessages();
00361     m_initialized = true;
00362 
00363     StringList paths = pluginPaths();
00364     for (StringList::const_iterator iter = paths.begin(); iter != paths.end(); ++iter)
00365     {
00366       std::string path = *iter;
00367       boost::filesystem::path bpath(path);
00368       LOGGING_TRACE(Plugin, "Loading plugins from " << path << icl_core::logging::endl);
00369 
00370       bool found = false;
00371       try
00372       {
00373         found = exists(bpath);
00374       }
00375       catch (const boost::filesystem::filesystem_error &e)
00376       {
00377         LOGGING_DEBUG(Plugin, "Exception when examining directory " << path
00378                       << ": " << e.what() << icl_core::logging::endl);
00379         // Ignored
00380       }
00381 
00382       if (!found)
00383       {
00384         LOGGING_DEBUG(Plugin, "Ignoring non-existing plugin path " << path << icl_core::logging::endl);
00385         continue;
00386       }
00387 
00388       if (!recursive_search)
00389       {
00390         boost::filesystem::directory_iterator end_iter;
00391         for (boost::filesystem::directory_iterator dir_iter(bpath); dir_iter != end_iter; ++dir_iter)
00392         {
00393           if (boost::filesystem::is_regular_file(dir_iter->status()))
00394           {
00395 #if BOOST_FILESYSTEM_VERSION == 2
00396             loadHandle(dir_iter->string());
00397 #else
00398             loadHandle(dir_iter->path().string());
00399 #endif
00400           }
00401         }
00402       }
00403       else
00404       {
00405         boost::filesystem::recursive_directory_iterator end_iter;
00406         for (boost::filesystem::recursive_directory_iterator dir_iter(bpath);
00407              dir_iter != end_iter; ++dir_iter)
00408         {
00409           if (boost::filesystem::is_regular_file(dir_iter->status()))
00410           {
00411 #if BOOST_FILESYSTEM_VERSION == 2
00412             loadHandle(dir_iter->string());
00413 #else
00414             loadHandle(dir_iter->path().string());
00415 #endif
00416           }
00417         }
00418       }
00419     }
00420 
00421     LOGGING_DEBUG(Plugin, "Initialized " << m_plugin_handles.size() << " plugins."
00422                   << icl_core::logging::endl);
00423   }
00424 
00427   void loadHandle(std::string plugin)
00428   {
00429 #ifdef _WIN32
00430     if (boost::algorithm::ends_with(plugin, ".lib")) {
00431         LOGGING_DEBUG(Plugin, "Ignoring .lib file in plugin directory: " << plugin << icl_core::logging::endl);
00432         return;
00433     }
00434 #endif
00435 
00436     PluginHandle plugin_handle = dlopen(plugin.c_str(), RTLD_LAZY);
00437 
00438     dlerror(); // Clear any previous errors.
00439     typename T::identifier* get_identifier
00440       = (typename T::identifier*) dlsym(plugin_handle, "identifier");
00441 
00442     typename T::basetype* get_basetype
00443       = (typename T::basetype*) dlsym(plugin_handle, "basetype");
00444 
00445     const char* dlsym_error = dlerror();
00446     if (dlsym_error)
00447     {
00448 #ifdef _WIN32
00449       LPVOID msg_buffer;
00450       unsigned error_code = GetLastError();
00451 
00452       FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
00453                     | FORMAT_MESSAGE_FROM_SYSTEM,
00454                     NULL,
00455                     error_code,
00456                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00457                     (LPTSTR) &msg_buffer,
00458                     0, NULL);
00459 
00460       std::ostringstream error;
00461       error << "Could not open dll: (" << error_code << ") " << msg_buffer;
00462       addErrorMessage(error.str());
00464       //LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00465       printf("could not open dll: (%d) %s\n", error_code, msg_buffer);
00466       LocalFree(msg_buffer);
00467 #else // _WIN32
00468       std::ostringstream error;
00469       error << "Cannot load plugin " << plugin << ": " << dlsym_error;
00470       addErrorMessage(error.str());
00471       LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00472       // cannot find symbol
00473 #endif // _WIN32
00474     }
00475     else
00476     {
00477       if (!get_identifier || !get_basetype)
00478       {
00479         std::ostringstream error;
00480         error << "Identifier or basetype method missing in plugin " << plugin;
00481         addErrorMessage(error.str());
00482         LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00483       }
00484       else if (strcmp(get_basetype(), typeid(T).name()) != 0)
00485       {
00486         LOGGING_WARNING(Plugin, "Plugin type mismatch: Exptected " << typeid(T).name()
00487                         << ", got " << get_basetype() << icl_core::logging::endl);
00488       }
00489       else
00490       {
00491         m_plugin_handles[get_identifier()] = plugin_handle;
00492         LOGGING_DEBUG(Plugin, "Initialized plugin " << get_identifier() << " of basetype "
00493                       << get_basetype() << icl_core::logging::endl);
00494       }
00495     }
00496   }
00497 
00501   void loadPlugins()
00502   {
00503     m_lazy_loading = false;
00504 
00505     typename std::map<std::string, PluginHandle>::const_iterator iter;
00506     for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
00507     {
00508       if (m_loaded_plugins.find(iter->first) == m_loaded_plugins.end())
00509       {
00510         m_loaded_plugins[iter->first] = createPluginInstance(iter->first);
00511       }
00512     }
00513 
00514     LOGGING_DEBUG(Plugin, "Loaded " << m_loaded_plugins.size() << " plugins." << icl_core::logging::endl);
00515   }
00516 
00519   void unloadPlugin(const std::string &identifier)
00520   {
00521     delete m_loaded_plugins[identifier];
00522     m_loaded_plugins.erase(identifier);
00523   }
00524 
00527   void closePluginHandle(const std::string &identifier)
00528   {
00529     PluginHandle plugin_handle = m_plugin_handles[identifier];
00530     if (plugin_handle)
00531     {
00532       LOGGING_DEBUG(Plugin, "Close plugin " << identifier << icl_core::logging::endl);
00533 
00534       if (m_loaded_plugins.find(identifier) != m_loaded_plugins.end())
00535       {
00536         T* plugin_instance = m_loaded_plugins[identifier];
00537         delete plugin_instance;
00538         m_loaded_plugins.erase(identifier);
00539       }
00540 
00541       dlclose(plugin_handle);
00542     }
00543     m_plugin_handles.erase(identifier);
00544   }
00545 
00548   T* loadPluginInstance(PluginHandle plugin_handle, const std::string &identifier)
00549   {
00550     if (plugin_handle)
00551     {
00552       // clear errors
00553       dlerror();
00554 
00555       typename T::load_plugin* create_instance
00556         = (typename T::load_plugin*) dlsym(plugin_handle,
00557                                               "load_plugin");
00558       const char* dlsym_error = dlerror();
00559       if (dlsym_error)
00560       {
00561 #ifdef _WIN32
00562         LPVOID msg_buffer;
00563         unsigned error_code = GetLastError();
00564 
00565         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
00566                       | FORMAT_MESSAGE_FROM_SYSTEM,
00567                       NULL,
00568                       error_code,
00569                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00570                       (LPTSTR) &msg_buffer,
00571                       0, NULL);
00572 
00573         std::ostringstream error;
00574         error << "Could not open dll: (" << error_code << ") " << msg_buffer;
00575         addErrorMessage(error.str());
00576         LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00577         LocalFree(msg_buffer);
00578 #else // _WIN32
00579         std::ostringstream error;
00580         error << "Cannot load plugin " << identifier << ": " << dlsym_error;
00581         addErrorMessage(error.str());
00582         LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00583         // cannot find symbol
00584 #endif // _WIN32
00585       }
00586       else
00587       {
00588         T* plugin_instance = create_instance();
00589         if (!plugin_instance)
00590         {
00591           std::ostringstream error;
00592           error << "Cannot cast plugin " << identifier;
00593           addErrorMessage(error.str());
00594           LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00595         }
00596         else
00597         {
00598           LOGGING_DEBUG(Plugin, "Loaded plugin " << plugin_instance->Identifier() << icl_core::logging::endl);
00599         }
00600         return plugin_instance;
00601       }
00602     }
00603     LOGGING_ERROR(Plugin, "No valid plugin handle available for " << identifier << icl_core::logging::endl);
00604     return NULL;
00605   }
00606 
00608 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00609 
00614   ICL_CORE_VC_DEPRECATE_STYLE void InitializePlugins(bool recursive_search)
00615     ICL_CORE_GCC_DEPRECATE_STYLE
00616   { initializePlugins(recursive_search); }
00617 
00621   ICL_CORE_VC_DEPRECATE_STYLE void LoadHandle(std::string plugin)
00622     ICL_CORE_GCC_DEPRECATE_STYLE
00623   { loadHandle(plugin); }
00624 
00628   ICL_CORE_VC_DEPRECATE_STYLE void LoadPlugins()
00629     ICL_CORE_GCC_DEPRECATE_STYLE
00630   { loadPlugins(); }
00631 
00635   ICL_CORE_VC_DEPRECATE_STYLE void UnloadPlugin(const std::string &identifier)
00636     ICL_CORE_GCC_DEPRECATE_STYLE
00637   { unloadPlugin(identifier); }
00638 
00642   ICL_CORE_VC_DEPRECATE_STYLE void ClosePluginHandle(const std::string &identifier)
00643     ICL_CORE_GCC_DEPRECATE_STYLE
00644   { closePluginHandle(identifier); }
00645 
00649   ICL_CORE_VC_DEPRECATE_STYLE T* LoadPluginInstance(PluginHandle plugin_handle, const std::string &identifier)
00650     ICL_CORE_GCC_DEPRECATE_STYLE
00651   { return loadPluginInstance(plugin_handle, identifier); }
00652 
00653 #endif
00654 
00655 
00657   std::map<std::string, T*> m_loaded_plugins;
00658 
00660   std::map<std::string, PluginHandle> m_plugin_handles;
00661 
00663   std::map<std::string, T*> m_static_plugins;
00664 
00665   bool m_initialized;
00666 
00667   bool m_lazy_loading;
00668 };
00669 
00670 }
00671 }
00672 
00673 #endif


fzi_icl_core
Author(s):
autogenerated on Tue Aug 8 2017 02:28:03