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 #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
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
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();
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
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
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
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
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