PluginManager.h
Go to the documentation of this file.
1 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
2 
3 // -- BEGIN LICENSE BLOCK ----------------------------------------------
4 // This file is part of FZIs ic_workspace.
5 //
6 // This program is free software licensed under the LGPL
7 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
8 // You can find a copy of this license in LICENSE folder in the top
9 // directory of the source code.
10 //
11 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
12 //
13 // -- END LICENSE BLOCK ------------------------------------------------
14 
15 //----------------------------------------------------------------------
27 //----------------------------------------------------------------------
28 #ifndef ICL_CORE_PLUGIN_PLUGIN_MANAGER_H_INCLUDED
29 #define ICL_CORE_PLUGIN_PLUGIN_MANAGER_H_INCLUDED
30 
34 
35 #include <boost/filesystem.hpp>
36 #include <boost/algorithm/string/predicate.hpp>
37 
38 #include <cassert>
39 #include <string>
40 #include <list>
41 #include <map>
42 #include <iostream>
43 #include <sstream>
44 
45 #include <dlfcn.h>
46 
47 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
48 # include "icl_core/Deprecate.h"
49 #endif
50 
51 namespace icl_core {
53 namespace plugin {
54 
55 typedef void* PluginHandle;
56 
59 template <class T, const char* const plugin_dir>
61 {
62 public:
64  {
65  while (!m_plugin_handles.empty() && !m_loaded_plugins.empty())
66  {
67  closePluginHandle(m_loaded_plugins.begin()->first);
68  }
69 
70  static PluginManager<T, plugin_dir>* m_instance;
71  m_instance = 0;
72  (void) m_instance;
73  }
74 
77  {
79  static PluginManager<T, plugin_dir> *m_instance = 0;
80 
81  if (!m_instance)
82  {
83  m_instance = new PluginManager<T, plugin_dir>();
84  }
85 
86  assert(m_instance);
87  return m_instance;
88  }
89 
91  bool initialize(bool load_lazy = true, bool recursive_search = false)
92  {
93  if (isInitialized() && loadLazy() && !load_lazy)
94  {
95  loadPlugins();
96  return true;
97  }
98 
99  if (isInitialized())
100  {
101  LOGGING_WARNING(Plugin, "The plugin framework is already initialized!" << icl_core::logging::endl);
102  return true;
103  }
104 
105  initializePlugins(recursive_search);
106 
107  if (!load_lazy)
108  {
109  loadPlugins();
110  }
111  else
112  {
113  m_lazy_loading = true;
114  }
115 
116  return true;
117  }
118 
119  bool isInitialized() const
120  {
121  return m_initialized;
122  }
123 
124  bool loadLazy() const
125  {
126  return m_lazy_loading;
127  }
128 
131  std::list<std::string> availablePlugins()
132  {
133  if (!isInitialized())
134  {
135  initialize(false);
136  }
137 
138  if (loadLazy())
139  {
140  loadPlugins();
141  }
142 
143  std::list<std::string> result;
144  typename std::map<std::string, PluginHandle>::const_iterator iter;
145  for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
146  {
147  result.push_back(iter->first);
148  }
149 
150  typename std::map<std::string, T*>::const_iterator siter;
151  for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
152  {
153  result.push_back(siter->first);
154  }
155 
156  return result;
157  }
158 
161  std::list<T*> plugins()
162  {
163  if (!isInitialized())
164  {
165  initialize(false);
166  }
167 
168  if (loadLazy())
169  {
170  loadPlugins();
171  }
172 
173  std::list<T*> result;
174  typename std::map<std::string, T*>::const_iterator iter;
175  for (iter = m_loaded_plugins.begin(); iter != m_loaded_plugins.end(); ++iter)
176  {
177  result.push_back(iter->second);
178  }
179 
180  typename std::map<std::string, T*>::const_iterator siter;
181  for (siter = m_static_plugins.begin(); siter != m_static_plugins.end(); ++siter)
182  {
183  result.push_back(siter->second);
184  }
185 
186  return result;
187  }
188 
192  T* plugin(const std::string &identifier)
193  {
194  if (!isInitialized())
195  {
196  initialize(false);
197  }
198 
199  if (loadLazy())
200  {
201  loadPlugins();
202  }
203 
204  if (m_static_plugins.find(identifier) != m_static_plugins.end())
205  {
206  return m_static_plugins[identifier];
207  }
208 
209  return m_loaded_plugins[identifier];
210  }
211 
215  T* createPluginInstance(const std::string &identifier)
216  {
217  if (!isInitialized())
218  {
219  initialize(false);
220  }
221 
222  if (loadLazy())
223  {
224  loadPlugins();
225  }
226 
227  PluginHandle plugin_handle = m_plugin_handles[identifier];
228  return loadPluginInstance(plugin_handle, identifier);
229  }
230 
240  {
241  removeStaticPlugin(instance->Identifier());
242  m_static_plugins[instance->Identifier()] = instance;
243  LOGGING_DEBUG(Plugin, "Static plugin " << instance->Identifier() << " added." << icl_core::logging::endl);
244  }
245 
249  void removeStaticPlugin(const std::string &identifier)
250  {
251  m_static_plugins.erase(identifier);
252  LOGGING_DEBUG(Plugin, "Static plugin " << identifier << " removed."
254  }
255 
260  bool isStaticPlugin(const std::string &identifier) const
261  {
262  return m_static_plugins.find(identifier) != m_static_plugins.end();
263  }
264 
266 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
267 
273  { return instance(); }
274 
278  ICL_CORE_VC_DEPRECATE_STYLE bool Initialize(bool load_lazy = true,
279  bool recursive_search = false)
281  { return initialize(load_lazy, recursive_search); }
282 
283  ICL_CORE_VC_DEPRECATE_STYLE bool IsInitialized() const
285  { return isInitialized(); }
286 
287  ICL_CORE_VC_DEPRECATE_STYLE bool LoadLazy() const
289  { return loadLazy(); }
290 
294  ICL_CORE_VC_DEPRECATE_STYLE std::list<std::string> AvailablePlugins()
296  { return availablePlugins(); }
297 
301  ICL_CORE_VC_DEPRECATE_STYLE std::list<T*> Plugins()
303  { return plugins(); }
304 
308  ICL_CORE_VC_DEPRECATE_STYLE T* Plugin(const std::string &identifier)
310  { return plugin(identifier); }
311 
315  ICL_CORE_VC_DEPRECATE_STYLE T* CreatePluginInstance(const std::string &identifier)
317  { return createPluginInstance(identifier); }
318 
322  ICL_CORE_VC_DEPRECATE_STYLE void AddStaticPlugin(T* instance)
324  { addStaticPlugin(instance); }
325 
329  ICL_CORE_VC_DEPRECATE_STYLE void RemoveStaticPlugin(const std::string &identifier)
331  { removeStaticPlugin(identifier); }
332 
337  ICL_CORE_VC_DEPRECATE_STYLE bool IsStaticPlugin(const std::string &identifier) const
339  { return isStaticPlugin(identifier); }
340 
341 #endif
342 
344 protected:
347  : PluginManagerBase(plugin_dir),
348  m_initialized(false),
349  m_lazy_loading(false)
350  {
351  // nothing to do
352  }
353 
357  void initializePlugins(bool recursive_search)
358  {
359  assert(!isInitialized());
361  m_initialized = true;
362 
363  StringList paths = pluginPaths();
364  for (StringList::const_iterator iter = paths.begin(); iter != paths.end(); ++iter)
365  {
366  std::string path = *iter;
367  boost::filesystem::path bpath(path);
368  LOGGING_TRACE(Plugin, "Loading plugins from " << path << icl_core::logging::endl);
369 
370  bool found = false;
371  try
372  {
373  found = exists(bpath);
374  }
375  catch (const boost::filesystem::filesystem_error &e)
376  {
377  LOGGING_DEBUG(Plugin, "Exception when examining directory " << path
378  << ": " << e.what() << icl_core::logging::endl);
379  // Ignored
380  }
381 
382  if (!found)
383  {
384  LOGGING_DEBUG(Plugin, "Ignoring non-existing plugin path " << path << icl_core::logging::endl);
385  continue;
386  }
387 
388  if (!recursive_search)
389  {
390  boost::filesystem::directory_iterator end_iter;
391  for (boost::filesystem::directory_iterator dir_iter(bpath); dir_iter != end_iter; ++dir_iter)
392  {
393  if (boost::filesystem::is_regular_file(dir_iter->status()))
394  {
395 #if BOOST_FILESYSTEM_VERSION == 2
396  loadHandle(dir_iter->string());
397 #else
398  loadHandle(dir_iter->path().string());
399 #endif
400  }
401  }
402  }
403  else
404  {
405  boost::filesystem::recursive_directory_iterator end_iter;
406  for (boost::filesystem::recursive_directory_iterator dir_iter(bpath);
407  dir_iter != end_iter; ++dir_iter)
408  {
409  if (boost::filesystem::is_regular_file(dir_iter->status()))
410  {
411 #if BOOST_FILESYSTEM_VERSION == 2
412  loadHandle(dir_iter->string());
413 #else
414  loadHandle(dir_iter->path().string());
415 #endif
416  }
417  }
418  }
419  }
420 
421  LOGGING_DEBUG(Plugin, "Initialized " << m_plugin_handles.size() << " plugins."
423  }
424 
427  void loadHandle(std::string plugin)
428  {
429 #ifdef _WIN32
430  if (boost::algorithm::ends_with(plugin, ".lib")) {
431  LOGGING_DEBUG(Plugin, "Ignoring .lib file in plugin directory: " << plugin << icl_core::logging::endl);
432  return;
433  }
434 #endif
435 
436  PluginHandle plugin_handle = dlopen(plugin.c_str(), RTLD_LAZY);
437 
438  dlerror(); // Clear any previous errors.
439  typename T::identifier* get_identifier
440  = (typename T::identifier*) dlsym(plugin_handle, "identifier");
441 
442  typename T::basetype* get_basetype
443  = (typename T::basetype*) dlsym(plugin_handle, "basetype");
444 
445  const char* dlsym_error = dlerror();
446  if (dlsym_error)
447  {
448 #ifdef _WIN32
449  LPVOID msg_buffer;
450  unsigned error_code = GetLastError();
451 
452  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
453  | FORMAT_MESSAGE_FROM_SYSTEM,
454  NULL,
455  error_code,
456  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
457  (LPTSTR) &msg_buffer,
458  0, NULL);
459 
460  std::ostringstream error;
461  error << "Could not open dll: (" << error_code << ") " << msg_buffer;
462  addErrorMessage(error.str());
464  //LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
465  printf("could not open dll: (%d) %s\n", error_code, msg_buffer);
466  LocalFree(msg_buffer);
467 #else // _WIN32
468  std::ostringstream error;
469  error << "Cannot load plugin " << plugin << ": " << dlsym_error;
470  addErrorMessage(error.str());
471  LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
472  // cannot find symbol
473 #endif // _WIN32
474  }
475  else
476  {
477  if (!get_identifier || !get_basetype)
478  {
479  std::ostringstream error;
480  error << "Identifier or basetype method missing in plugin " << plugin;
481  addErrorMessage(error.str());
482  LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
483  }
484  else if (strcmp(get_basetype(), typeid(T).name()) != 0)
485  {
486  LOGGING_WARNING(Plugin, "Plugin type mismatch: Exptected " << typeid(T).name()
487  << ", got " << get_basetype() << icl_core::logging::endl);
488  }
489  else
490  {
491  m_plugin_handles[get_identifier()] = plugin_handle;
492  LOGGING_DEBUG(Plugin, "Initialized plugin " << get_identifier() << " of basetype "
493  << get_basetype() << icl_core::logging::endl);
494  }
495  }
496  }
497 
501  void loadPlugins()
502  {
503  m_lazy_loading = false;
504 
505  typename std::map<std::string, PluginHandle>::const_iterator iter;
506  for (iter = m_plugin_handles.begin(); iter != m_plugin_handles.end(); ++iter)
507  {
508  if (m_loaded_plugins.find(iter->first) == m_loaded_plugins.end())
509  {
510  m_loaded_plugins[iter->first] = createPluginInstance(iter->first);
511  }
512  }
513 
514  LOGGING_DEBUG(Plugin, "Loaded " << m_loaded_plugins.size() << " plugins." << icl_core::logging::endl);
515  }
516 
519  void unloadPlugin(const std::string &identifier)
520  {
521  delete m_loaded_plugins[identifier];
522  m_loaded_plugins.erase(identifier);
523  }
524 
527  void closePluginHandle(const std::string &identifier)
528  {
529  PluginHandle plugin_handle = m_plugin_handles[identifier];
530  if (plugin_handle)
531  {
532  LOGGING_DEBUG(Plugin, "Close plugin " << identifier << icl_core::logging::endl);
533 
534  if (m_loaded_plugins.find(identifier) != m_loaded_plugins.end())
535  {
536  T* plugin_instance = m_loaded_plugins[identifier];
537  delete plugin_instance;
538  m_loaded_plugins.erase(identifier);
539  }
540 
541  dlclose(plugin_handle);
542  }
543  m_plugin_handles.erase(identifier);
544  }
545 
548  T* loadPluginInstance(PluginHandle plugin_handle, const std::string &identifier)
549  {
550  if (plugin_handle)
551  {
552  // clear errors
553  dlerror();
554 
555  typename T::load_plugin* create_instance
556  = (typename T::load_plugin*) dlsym(plugin_handle,
557  "load_plugin");
558  const char* dlsym_error = dlerror();
559  if (dlsym_error)
560  {
561 #ifdef _WIN32
562  LPVOID msg_buffer;
563  unsigned error_code = GetLastError();
564 
565  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
566  | FORMAT_MESSAGE_FROM_SYSTEM,
567  NULL,
568  error_code,
569  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
570  (LPTSTR) &msg_buffer,
571  0, NULL);
572 
573  std::ostringstream error;
574  error << "Could not open dll: (" << error_code << ") " << msg_buffer;
575  addErrorMessage(error.str());
576  LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
577  LocalFree(msg_buffer);
578 #else // _WIN32
579  std::ostringstream error;
580  error << "Cannot load plugin " << identifier << ": " << dlsym_error;
581  addErrorMessage(error.str());
582  LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
583  // cannot find symbol
584 #endif // _WIN32
585  }
586  else
587  {
588  T* plugin_instance = create_instance();
589  if (!plugin_instance)
590  {
591  std::ostringstream error;
592  error << "Cannot cast plugin " << identifier;
593  addErrorMessage(error.str());
594  LOGGING_ERROR(Plugin, error.str() << icl_core::logging::endl);
595  }
596  else
597  {
598  LOGGING_DEBUG(Plugin, "Loaded plugin " << plugin_instance->Identifier() << icl_core::logging::endl);
599  }
600  return plugin_instance;
601  }
602  }
603  LOGGING_ERROR(Plugin, "No valid plugin handle available for " << identifier << icl_core::logging::endl);
604  return NULL;
605  }
606 
608 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
609 
614  ICL_CORE_VC_DEPRECATE_STYLE void InitializePlugins(bool recursive_search)
616  { initializePlugins(recursive_search); }
617 
621  ICL_CORE_VC_DEPRECATE_STYLE void LoadHandle(std::string plugin)
623  { loadHandle(plugin); }
624 
628  ICL_CORE_VC_DEPRECATE_STYLE void LoadPlugins()
630  { loadPlugins(); }
631 
635  ICL_CORE_VC_DEPRECATE_STYLE void UnloadPlugin(const std::string &identifier)
637  { unloadPlugin(identifier); }
638 
642  ICL_CORE_VC_DEPRECATE_STYLE void ClosePluginHandle(const std::string &identifier)
644  { closePluginHandle(identifier); }
645 
649  ICL_CORE_VC_DEPRECATE_STYLE T* LoadPluginInstance(PluginHandle plugin_handle, const std::string &identifier)
651  { return loadPluginInstance(plugin_handle, identifier); }
652 
653 #endif
654 
657  std::map<std::string, T*> m_loaded_plugins;
658 
660  std::map<std::string, PluginHandle> m_plugin_handles;
661 
663  std::map<std::string, T*> m_static_plugins;
664 
666 
668 };
669 
670 }
671 }
672 
673 #endif
void addStaticPlugin(T *instance)
#define ICL_CORE_VC_DEPRECATE_STYLE
Definition: Deprecate.h:53
Contains import/export definitions for the Win32 plattform.
void addErrorMessage(const std::string &message)
T * createPluginInstance(const std::string &identifier)
Contains macros to deprecate classes, types, functions and variables.
T * plugin(const std::string &identifier)
#define LOGGING_DEBUG(streamname, arg)
void removeStaticPlugin(const std::string &identifier)
void loadHandle(std::string plugin)
std::map< std::string, PluginHandle > m_plugin_handles
Loadable plugin handles.
ICL_CORE_VC_DEPRECATE_STYLE bool Initialize(int &argc, char *argv[], bool remove_read_arguments) ICL_CORE_GCC_DEPRECATE_STYLE
Definition: Config.h:902
#define LOGGING_ERROR(streamname, arg)
static PluginManager< T, plugin_dir > * instance()
Singleton instance accessor.
Definition: PluginManager.h:76
Contains logging definitions for the icl_core_plugin library.
ThreadStream & endl(ThreadStream &stream)
Definition: ThreadStream.h:249
std::map< std::string, T * > m_loaded_plugins
Plugins loaded from disk via ltdl.
void initializePlugins(bool recursive_search)
bool isStaticPlugin(const std::string &identifier) const
#define LOGGING_WARNING(streamname, arg)
Contains PluginManagerBase.
std::list< std::string > availablePlugins()
void closePluginHandle(const std::string &identifier)
std::map< std::string, T * > m_static_plugins
Plugins available from an already loaded lib, added manually.
std::list< std::string > StringList
PluginManager()
Protected default constructor.
bool initialize(bool load_lazy=true, bool recursive_search=false)
Initializes the PluginManager.
Definition: PluginManager.h:91
T * loadPluginInstance(PluginHandle plugin_handle, const std::string &identifier)
#define LOGGING_TRACE(streamname, arg)
#define ICL_CORE_GCC_DEPRECATE_STYLE
Definition: Deprecate.h:54
void unloadPlugin(const std::string &identifier)


fzi_icl_core
Author(s):
autogenerated on Mon Jun 10 2019 13:17:58