00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00037 #include <cassert>
00038 #include <string>
00039 #include <list>
00040 #include <map>
00041 #include <iostream>
00042 #include <sstream>
00043
00044 #include <ltdl.h>
00045
00046 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00047 # include "icl_core/Deprecate.h"
00048 #endif
00049
00050 namespace icl_core {
00052 namespace plugin {
00053
00056 template <class T, const char* const plugin_dir>
00057 class PluginManager: public PluginManagerBase
00058 {
00059 public:
00060 ~PluginManager()
00061 {
00062 while (!m_plugin_handles.empty() && !m_loaded_plugins.empty())
00063 {
00064 closePluginHandle(m_loaded_plugins.begin()->first);
00065 }
00066
00067 lt_dlexit();
00068 static PluginManager<T, plugin_dir>* m_instance;
00069 m_instance = 0;
00070 (void) m_instance;
00071 }
00072
00074 static PluginManager<T, plugin_dir> *instance()
00075 {
00077 static PluginManager<T, plugin_dir> *m_instance = 0;
00078
00079 if (!m_instance)
00080 {
00081 m_instance = new PluginManager<T, plugin_dir>();
00082 }
00083
00084 assert(m_instance);
00085 return m_instance;
00086 }
00087
00089 bool initialize(bool load_lazy = true, bool recursive_search = false)
00090 {
00091 if (isInitialized() && loadLazy() && !load_lazy)
00092 {
00093 loadPlugins();
00094 return true;
00095 }
00096
00097 if (isInitialized())
00098 {
00099 LOGGING_WARNING(Plugin, "The plugin framework is already initialized!" << icl_core::logging::endl);
00100 return true;
00101 }
00102
00103 initializePlugins(recursive_search);
00104
00105 if (!load_lazy)
00106 {
00107 loadPlugins();
00108 }
00109 else
00110 {
00111 m_lazy_loading = true;
00112 }
00113
00114 return true;
00115 }
00116
00117 bool isInitialized() const
00118 {
00119 return m_initialized;
00120 }
00121
00122 bool loadLazy() const
00123 {
00124 return m_lazy_loading;
00125 }
00126
00129 std::list<std::string> availablePlugins()
00130 {
00131 if (!isInitialized())
00132 {
00133 initialize(false);
00134 }
00135
00136 if (loadLazy())
00137 {
00138 loadPlugins();
00139 }
00140
00141 std::list<std::string> result;
00142 typename std::map<std::string, lt_dlhandle>::const_iterator iter;
00143 for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
00144 {
00145 result.push_back(iter->first);
00146 }
00147
00148 typename std::map<std::string, T*>::const_iterator siter;
00149 for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
00150 {
00151 result.push_back(siter->first);
00152 }
00153
00154 return result;
00155 }
00156
00159 std::list<T*> plugins()
00160 {
00161 if (!isInitialized())
00162 {
00163 initialize(false);
00164 }
00165
00166 if (loadLazy())
00167 {
00168 loadPlugins();
00169 }
00170
00171 std::list<T*> result;
00172 typename std::map<std::string, T*>::const_iterator iter;
00173 for (iter = m_loaded_plugins.begin(); iter != m_loaded_plugins.end(); ++iter)
00174 {
00175 result.push_back(iter->second);
00176 }
00177
00178 typename std::map<std::string, T*>::const_iterator siter;
00179 for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
00180 {
00181 result.push_back(siter->second);
00182 }
00183
00184 return result;
00185 }
00186
00190 T* plugin(const std::string &identifier)
00191 {
00192 if (!isInitialized())
00193 {
00194 initialize(false);
00195 }
00196
00197 if (loadLazy())
00198 {
00199 loadPlugins();
00200 }
00201
00202 if (m_static_plugins.find(identifier) != m_static_plugins.end())
00203 {
00204 return m_static_plugins[identifier];
00205 }
00206
00207 return m_loaded_plugins[identifier];
00208 }
00209
00213 T* createPluginInstance(const std::string &identifier)
00214 {
00215 if (!isInitialized())
00216 {
00217 initialize(false);
00218 }
00219
00220 if (loadLazy())
00221 {
00222 loadPlugins();
00223 }
00224
00225 lt_dlhandle plugin_handle = m_plugin_handles[identifier];
00226 return loadPluginInstance(plugin_handle, identifier);
00227 }
00228
00237 void addStaticPlugin(T* instance)
00238 {
00239 removeStaticPlugin(instance->Identifier());
00240 m_static_plugins[instance->Identifier()] = instance;
00241 LOGGING_DEBUG(Plugin, "Static plugin " << instance->Identifier() << " added." << icl_core::logging::endl);
00242 }
00243
00247 void removeStaticPlugin(const std::string &identifier)
00248 {
00249 m_static_plugins.erase(identifier);
00250 LOGGING_DEBUG(Plugin, "Static plugin " << identifier << " removed."
00251 << icl_core::logging::endl);
00252 }
00253
00258 bool isStaticPlugin(const std::string &identifier) const
00259 {
00260 return m_static_plugins.find(identifier) != m_static_plugins.end();
00261 }
00262
00264 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00265
00269 static ICL_CORE_VC_DEPRECATE_STYLE PluginManager<T, plugin_dir> *Instance()
00270 ICL_CORE_GCC_DEPRECATE_STYLE
00271 { return instance(); }
00272
00276 ICL_CORE_VC_DEPRECATE_STYLE bool Initialize(bool load_lazy = true,
00277 bool recursive_search = false)
00278 ICL_CORE_GCC_DEPRECATE_STYLE
00279 { return initialize(load_lazy, recursive_search); }
00280
00281 ICL_CORE_VC_DEPRECATE_STYLE bool IsInitialized() const
00282 ICL_CORE_GCC_DEPRECATE_STYLE
00283 { return isInitialized(); }
00284
00285 ICL_CORE_VC_DEPRECATE_STYLE bool LoadLazy() const
00286 ICL_CORE_GCC_DEPRECATE_STYLE
00287 { return loadLazy(); }
00288
00292 ICL_CORE_VC_DEPRECATE_STYLE std::list<std::string> AvailablePlugins()
00293 ICL_CORE_GCC_DEPRECATE_STYLE
00294 { return availablePlugins(); }
00295
00299 ICL_CORE_VC_DEPRECATE_STYLE std::list<T*> Plugins()
00300 ICL_CORE_GCC_DEPRECATE_STYLE
00301 { return plugins(); }
00302
00306 ICL_CORE_VC_DEPRECATE_STYLE T* Plugin(const std::string &identifier)
00307 ICL_CORE_GCC_DEPRECATE_STYLE
00308 { return plugin(identifier); }
00309
00313 ICL_CORE_VC_DEPRECATE_STYLE T* CreatePluginInstance(const std::string &identifier)
00314 ICL_CORE_GCC_DEPRECATE_STYLE
00315 { return createPluginInstance(identifier); }
00316
00320 ICL_CORE_VC_DEPRECATE_STYLE void AddStaticPlugin(T* instance)
00321 ICL_CORE_GCC_DEPRECATE_STYLE
00322 { addStaticPlugin(instance); }
00323
00327 ICL_CORE_VC_DEPRECATE_STYLE void RemoveStaticPlugin(const std::string &identifier)
00328 ICL_CORE_GCC_DEPRECATE_STYLE
00329 { removeStaticPlugin(identifier); }
00330
00335 ICL_CORE_VC_DEPRECATE_STYLE bool IsStaticPlugin(const std::string &identifier) const
00336 ICL_CORE_GCC_DEPRECATE_STYLE
00337 { return isStaticPlugin(identifier); }
00338
00339 #endif
00340
00341
00342 protected:
00344 PluginManager()
00345 : PluginManagerBase(plugin_dir),
00346 m_initialized(false),
00347 m_lazy_loading(false)
00348 {
00349 lt_dlinit();
00350 }
00351
00355 void initializePlugins(bool recursive_search)
00356 {
00357 assert(!isInitialized());
00358 clearErrorMessages();
00359 m_initialized = true;
00360
00361 StringList paths = pluginPaths();
00362 for (StringList::const_iterator iter = paths.begin(); iter != paths.end(); ++iter)
00363 {
00364 std::string path = *iter;
00365 boost::filesystem::path bpath(path);
00366 LOGGING_TRACE(Plugin, "Loading plugins from " << path << icl_core::logging::endl);
00367
00368 bool found = false;
00369 try
00370 {
00371 found = exists(bpath);
00372 }
00373 catch (const boost::filesystem::filesystem_error &e)
00374 {
00375 LOGGING_DEBUG(Plugin, "Exception when examining directory " << path
00376 << ": " << e.what() << icl_core::logging::endl);
00377
00378 }
00379
00380 if (!found)
00381 {
00382 LOGGING_DEBUG(Plugin, "Ignoring non-existing plugin path " << path << icl_core::logging::endl);
00383 continue;
00384 }
00385
00386 if (!recursive_search)
00387 {
00388 boost::filesystem::directory_iterator end_iter;
00389 for (boost::filesystem::directory_iterator dir_iter(bpath); dir_iter != end_iter; ++dir_iter)
00390 {
00391 if (boost::filesystem::is_regular_file(dir_iter->status()))
00392 {
00393 #if BOOST_FILESYSTEM_VERSION == 2
00394 loadHandle(dir_iter->string());
00395 #else
00396 loadHandle(dir_iter->path().string());
00397 #endif
00398 }
00399 }
00400 }
00401 else
00402 {
00403 boost::filesystem::recursive_directory_iterator end_iter;
00404 for (boost::filesystem::recursive_directory_iterator dir_iter(bpath);
00405 dir_iter != end_iter; ++dir_iter)
00406 {
00407 if (boost::filesystem::is_regular_file(dir_iter->status()))
00408 {
00409 #if BOOST_FILESYSTEM_VERSION == 2
00410 loadHandle(dir_iter->string());
00411 #else
00412 loadHandle(dir_iter->path().string());
00413 #endif
00414 }
00415 }
00416 }
00417 }
00418
00419 LOGGING_DEBUG(Plugin, "Initialized " << m_plugin_handles.size() << " plugins."
00420 << icl_core::logging::endl);
00421 }
00422
00425 void loadHandle(std::string plugin)
00426 {
00427 lt_dlhandle plugin_handle = lt_dlopen(plugin.c_str());
00428
00429
00430 lt_dlerror();
00431 typename T::identifier* get_identifier
00432 = (typename T::identifier*) lt_dlsym(plugin_handle, "identifier");
00433
00434 typename T::basetype* get_basetype
00435 = (typename T::basetype*) lt_dlsym(plugin_handle, "basetype");
00436
00437 const char* dlsym_error = lt_dlerror();
00438 if (dlsym_error)
00439 {
00440 #ifdef _WIN32
00441 LPVOID msg_buffer;
00442 unsigned error_code = GetLastError();
00443
00444 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
00445 | FORMAT_MESSAGE_FROM_SYSTEM,
00446 NULL,
00447 error_code,
00448 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00449 (LPTSTR) &msg_buffer,
00450 0, NULL);
00451
00452 std::ostringstream error;
00453 error << "Could not open dll: (" << error_code << ") " << msg_buffer;
00454 addErrorMessage(error.str());
00456
00457 printf("could not open dll: (%d) %s\n", error_code, msg_buffer);
00458 LocalFree(msg_buffer);
00459 #else // _WIN32
00460 std::ostringstream error;
00461 error << "Cannot load plugin " << plugin << ": " << dlsym_error;
00462 addErrorMessage(error.str());
00463 LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00464
00465 #endif // _WIN32
00466 }
00467 else
00468 {
00469 if (!get_identifier || !get_basetype)
00470 {
00471 std::ostringstream error;
00472 error << "Identifier or basetype method missing in plugin " << plugin;
00473 addErrorMessage(error.str());
00474 LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00475 }
00476 else if (strcmp(get_basetype(), typeid(T).name()) != 0)
00477 {
00478 LOGGING_WARNING(Plugin, "Plugin type mismatch: Exptected " << typeid(T).name()
00479 << ", got " << get_basetype() << icl_core::logging::endl);
00480 }
00481 else
00482 {
00483 m_plugin_handles[get_identifier()] = plugin_handle;
00484 LOGGING_DEBUG(Plugin, "Initialized plugin " << get_identifier() << " of basetype "
00485 << get_basetype() << icl_core::logging::endl);
00486 }
00487 }
00488 }
00489
00493 void loadPlugins()
00494 {
00495 m_lazy_loading = false;
00496
00497 typename std::map<std::string, lt_dlhandle>::const_iterator iter;
00498 for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
00499 {
00500 if (m_loaded_plugins.find(iter->first) == m_loaded_plugins.end())
00501 {
00502 m_loaded_plugins[iter->first] = createPluginInstance(iter->first);
00503 }
00504 }
00505
00506 LOGGING_DEBUG(Plugin, "Loaded " << m_loaded_plugins.size() << " plugins." << icl_core::logging::endl);
00507 }
00508
00511 void unloadPlugin(const std::string &identifier)
00512 {
00513 delete m_loaded_plugins[identifier];
00514 m_loaded_plugins.erase(identifier);
00515 }
00516
00519 void closePluginHandle(const std::string &identifier)
00520 {
00521 lt_dlhandle plugin_handle = m_plugin_handles[identifier];
00522 if (plugin_handle)
00523 {
00524 LOGGING_DEBUG(Plugin, "Close plugin " << identifier << icl_core::logging::endl);
00525
00526 if (m_loaded_plugins.find(identifier) != m_loaded_plugins.end())
00527 {
00528 T* plugin_instance = m_loaded_plugins[identifier];
00529 delete plugin_instance;
00530 m_loaded_plugins.erase(identifier);
00531 }
00532
00533 lt_dlclose(plugin_handle);
00534 }
00535 m_plugin_handles.erase(identifier);
00536 }
00537
00540 T* loadPluginInstance(lt_dlhandle plugin_handle, const std::string &identifier)
00541 {
00542 if (plugin_handle)
00543 {
00544
00545 lt_dlerror();
00546
00547 typename T::load_plugin* create_instance
00548 = (typename T::load_plugin*) lt_dlsym(plugin_handle,
00549 "load_plugin");
00550 const char* dlsym_error = lt_dlerror();
00551 if (dlsym_error)
00552 {
00553 #ifdef _WIN32
00554 LPVOID msg_buffer;
00555 unsigned error_code = GetLastError();
00556
00557 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
00558 | FORMAT_MESSAGE_FROM_SYSTEM,
00559 NULL,
00560 error_code,
00561 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00562 (LPTSTR) &msg_buffer,
00563 0, NULL);
00564
00565 std::ostringstream error;
00566 error << "Could not open dll: (" << error_code << ") " << msg_buffer;
00567 addErrorMessage(error.str());
00568 LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00569 LocalFree(msg_buffer);
00570 #else // _WIN32
00571 std::ostringstream error;
00572 error << "Cannot load plugin " << identifier << ": " << dlsym_error;
00573 addErrorMessage(error.str());
00574 LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00575
00576 #endif // _WIN32
00577 }
00578 else
00579 {
00580 T* plugin_instance = create_instance();
00581 if (!plugin_instance)
00582 {
00583 std::ostringstream error;
00584 error << "Cannot cast plugin " << identifier;
00585 addErrorMessage(error.str());
00586 LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
00587 }
00588 else
00589 {
00590 LOGGING_DEBUG(Plugin, "Loaded plugin " << plugin_instance->Identifier() << icl_core::logging::endl);
00591 }
00592 return plugin_instance;
00593 }
00594 }
00595 LOGGING_ERROR(Plugin, "No valid plugin handle available for " << identifier << icl_core::logging::endl);
00596 return NULL;
00597 }
00598
00600 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00601
00606 ICL_CORE_VC_DEPRECATE_STYLE void InitializePlugins(bool recursive_search)
00607 ICL_CORE_GCC_DEPRECATE_STYLE
00608 { initializePlugins(recursive_search); }
00609
00613 ICL_CORE_VC_DEPRECATE_STYLE void LoadHandle(std::string plugin)
00614 ICL_CORE_GCC_DEPRECATE_STYLE
00615 { loadHandle(plugin); }
00616
00620 ICL_CORE_VC_DEPRECATE_STYLE void LoadPlugins()
00621 ICL_CORE_GCC_DEPRECATE_STYLE
00622 { loadPlugins(); }
00623
00627 ICL_CORE_VC_DEPRECATE_STYLE void UnloadPlugin(const std::string &identifier)
00628 ICL_CORE_GCC_DEPRECATE_STYLE
00629 { unloadPlugin(identifier); }
00630
00634 ICL_CORE_VC_DEPRECATE_STYLE void ClosePluginHandle(const std::string &identifier)
00635 ICL_CORE_GCC_DEPRECATE_STYLE
00636 { closePluginHandle(identifier); }
00637
00641 ICL_CORE_VC_DEPRECATE_STYLE T* LoadPluginInstance(lt_dlhandle plugin_handle, const std::string &identifier)
00642 ICL_CORE_GCC_DEPRECATE_STYLE
00643 { return loadPluginInstance(plugin_handle, identifier); }
00644
00645 #endif
00646
00647
00649 std::map<std::string, T*> m_loaded_plugins;
00650
00652 std::map<std::string, lt_dlhandle> m_plugin_handles;
00653
00655 std::map<std::string, T*> m_static_plugins;
00656
00657 bool m_initialized;
00658
00659 bool m_lazy_loading;
00660 };
00661
00662 }
00663 }
00664
00665 #endif