24 #include <plugin/manager.h> 25 #include <plugin/listener.h> 26 #include <plugin/loader.h> 28 #include <core/plugin.h> 29 #include <core/threading/thread_collector.h> 30 #include <core/threading/thread_initializer.h> 31 #include <core/threading/mutex_locker.h> 32 #include <core/exception.h> 33 #include <logging/liblogger.h> 34 #include <utils/system/fam_thread.h> 35 #include <config/config.h> 36 #include <utils/system/dynamic_module/module_manager.h> 43 #include <sys/types.h> 55 plname_eq(std::string name) {
58 bool operator()(Plugin *plugin)
60 return (__name == plugin->name());
88 const char *meta_plugin_prefix,
93 __mutex =
new Mutex();
94 this->thread_collector = thread_collector;
99 __meta_plugin_prefix = meta_plugin_prefix;
110 fam->add_filter(
"^[^.].*\\." SOEXT
"$");
111 fam->add_listener(
this);
112 fam->watch_dir(PLUGINDIR);
113 __fam_thread->
start();
116 "cannot detect changed plugins on disk.");
126 __fam_thread->
join();
130 __pinfo_cache.
lock();
131 __pinfo_cache.clear();
134 for (rpit = plugins.rbegin(); rpit != plugins.rend(); ++rpit) {
143 plugin_loader->
unload(*rpit);
147 delete plugin_loader;
166 __pinfo_cache.
lock();
170 const char *file_ext =
"." SOEXT;
172 if ( NULL == (plugin_dir = opendir(PLUGINDIR)) ) {
173 throw Exception(errno,
"Plugin directory %s could not be opened", PLUGINDIR);
176 for (
unsigned int i = 0; NULL != (dirp = readdir(plugin_dir)); ++i) {
177 char *file_name = dirp->d_name;
178 char *pos = strstr(file_name, file_ext);
179 std::string plugin_name = std::string(file_name).substr(0, strlen(file_name) - strlen(file_ext));
182 __pinfo_cache.push_back(make_pair(plugin_name,
186 "exception follows", plugin_name.c_str());
192 closedir(plugin_dir);
198 std::string p = std::string(i->
path()).substr(__meta_plugin_prefix.length());
199 std::string s = std::string(
"Meta: ") + i->
get_string();
201 __pinfo_cache.push_back(make_pair(p, s));
208 __pinfo_cache.sort();
217 std::list<std::pair<std::string, std::string> >
220 std::list<std::pair<std::string, std::string> > rv;
222 std::list<std::pair<std::string, std::string> >::iterator i;
223 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
233 std::list<std::string>
236 std::list<std::string> rv;
239 for (pit = plugins.begin(); pit != plugins.end(); ++pit) {
240 rv.push_back((*pit)->name());
243 __meta_plugins.
lock();
244 for (__mpit = __meta_plugins.begin(); __mpit != __meta_plugins.end(); ++__mpit) {
245 rv.push_back(__mpit->first);
260 if (plugin_loader->
is_loaded(plugin_name)) {
264 return (__meta_plugins.find(plugin_name) != __meta_plugins.end());
275 std::list<std::string>
276 PluginManager::parse_plugin_list(
const char *plugin_list)
278 std::list<std::string> rv;
280 char *plugins = strdup(plugin_list);
284 plugin = strtok_r(plugins,
",", &saveptr);
286 rv.push_back(plugin);
287 plugin = strtok_r(NULL,
",", &saveptr);
304 std::list<std::string> pp = parse_plugin_list(plugin_list);
306 for (std::list<std::string>::iterator i = pp.begin(); i != pp.end(); ++i) {
307 if ( i->length() == 0 )
continue;
309 bool try_real_plugin =
true;
310 if ( __meta_plugins.find(*i) == __meta_plugins.end() ) {
311 std::string meta_plugin = __meta_plugin_prefix + *i;
312 bool found_meta =
false;
313 std::string pset =
"";
315 pset = __config->
get_string(meta_plugin.c_str());
320 try_real_plugin =
true;
324 if (pset.length() == 0) {
325 throw Exception(
"Refusing to load an empty meta plugin");
328 __meta_plugins.
lock();
331 __meta_plugins[*i] = pset;
335 pset.c_str(), i->c_str());
337 notify_loaded(i->c_str());
339 e.
append(
"Could not initialize meta plugin %s, aborting loading.", i->c_str());
344 try_real_plugin =
false;
348 if (try_real_plugin &&
349 (find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end()))
353 Plugin *plugin = plugin_loader->
load(i->c_str());
357 plugins.push_back(plugin);
358 plugin_ids[*i] = next_plugin_id++;
359 notify_loaded(i->c_str());
361 e.
prepend(
"Plugin >>> %s <<< could not be initialized, unloading", i->c_str());
363 plugin_loader->
unload(plugin);
369 if ( __meta_plugins.find(*i) == __meta_plugins.end() ) {
389 if ( (pit = find_if(plugins.begin(), plugins.end(), plname_eq(plugin_name)))
392 thread_collector->
remove((*pit)->threads());
393 plugin_loader->
unload(*pit);
395 plugin_ids.erase(plugin_name);
396 notify_unloaded(plugin_name);
399 __meta_plugins.
lock();
400 __mpit = __meta_plugins.begin();
401 while (__mpit != __meta_plugins.end()) {
402 std::list<std::string> pp = parse_plugin_list(__mpit->second.c_str());
405 for (std::list<std::string>::iterator i = pp.begin(); i != pp.end(); ++i) {
406 if ( *i == plugin_name ) {
414 notify_unloaded(tmp->first.c_str());
415 __meta_plugins.erase(tmp);
423 LibLogger::log_error(
"PluginManager",
"Could not finalize one or more threads of plugin %s, NOT unloading plugin", plugin_name);
426 }
else if (__meta_plugins.find(plugin_name) != __meta_plugins.end()) {
427 std::list<std::string> pp = parse_plugin_list(__meta_plugins[plugin_name].c_str());
429 for (std::list<std::string>::reverse_iterator i = pp.rbegin(); i != pp.rend(); ++i) {
430 if ( i->length() == 0 )
continue;
431 if ((find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end())
432 && (__meta_plugins.find(*i) != __meta_plugins.end()) ) {
438 i->c_str(), plugin_name);
454 __pinfo_cache.
lock();
455 std::string p = std::string(v->
path()).substr(__meta_plugin_prefix.length());
456 std::string s = std::string(
"Meta: ") + v->
get_string();
457 std::list<std::pair<std::string, std::string> >::iterator i;
459 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
467 __pinfo_cache.push_back(make_pair(p, s));
481 __pinfo_cache.
lock();
482 std::string p = std::string(path).substr(__meta_plugin_prefix.length());
483 std::list<std::pair<std::string, std::string> >::iterator i;
484 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
486 __pinfo_cache.erase(i);
497 const char *file_ext =
"." SOEXT;
499 const char *pos = strstr(filename, file_ext);
500 std::string p = std::string(filename).substr(0, strlen(filename) - strlen(file_ext));
502 __pinfo_cache.
lock();
504 std::list<std::pair<std::string, std::string> >::iterator i;
505 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
509 __pinfo_cache.erase(i);
515 "description of plugin %s, exception follows",
527 if (plugin_loader->
is_loaded(p.c_str())) {
529 "loaded, no new info can be loaded, keeping old.",
537 __pinfo_cache.push_back(make_pair(p, s));
549 __pinfo_cache.sort();
563 __listeners.push_back(listener);
565 __listeners.unique();
566 __listeners.unlock();
575 __listeners.remove_locked(listener);
579 PluginManager::notify_loaded(
const char *plugin_name)
582 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
584 (*__lit)->plugin_loaded(plugin_name);
587 "during notification of plugin loaded, exception follows.");
591 __listeners.unlock();
595 PluginManager::notify_unloaded(
const char *plugin_name)
598 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
600 (*__lit)->plugin_unloaded(plugin_name);
603 "during notification of plugin unloaded, exception follows.");
607 __listeners.unlock();
void set_open_flags(Module::ModuleFlags open_flags)
Set flags to open modules with.
static void log_info(const char *component, const char *format,...)
Log informational message.
~PluginManager()
Destructor.
void set_module_flags(Module::ModuleFlags flags)
Set flags to open modules with.
void erase_locked(const KeyType &key)
Remove item with lock.
void lock() const
Lock list.
virtual void lock() const
Lock list.
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
std::list< std::pair< std::string, std::string > > get_available_plugins()
Generate list of all available plugins.
void init_pinfo_cache()
Initialize plugin info cache.
Fawkes library namespace.
void unlock()
Unlock the mutex.
bool try_lock()
Try to lock plugin manager.
Interface for configuration change handling.
virtual void config_comment_changed(const Configuration::ValueIterator *v)
Called whenever a comment of a watched value has changed.
Thrown if a config entry could not be found.
virtual ValueIterator * search(const char *path)=0
Iterator with search results.
static const unsigned int FAM_CREATE
Subfile was created.
virtual bool next()=0
Check if there is another element and advance to this if possible.
RefPtr< FileAlterationMonitor > get_fam()
Get FileAlterationMonitor.
ThreadList & threads()
Get a list of threads.
static const unsigned int FAM_ISDIR
Event occurred against dir.
This class manages plugins.
ModuleFlags
Flags for the loading process.
void lock()
Lock plugin manager.
void add_listener(PluginManagerListener *listener)
Add listener.
static void log_error(const char *component, const char *format,...)
Log error message.
void unload(Plugin *plugin)
Unload the given plugin This will unload the given plugin.
Thread cannot be initialized.
virtual bool is_string() const =0
Check if current value is a string.
virtual void config_tag_changed(const char *new_location)
Called whenever the tag has changed.
Base class for exceptions in Fawkes.
virtual void force_remove(fawkes::ThreadList &tl)=0
Force removal of multiple threads.
void load(const char *plugin_list)
Load plugin.
virtual void rem_change_handler(ConfigurationChangeHandler *h)
Remove a configuration change handler.
void prepend(const char *format,...)
Prepend messages to the message list.
void remove_listener(PluginManagerListener *listener)
Remove listener.
virtual void unlock() const
Unlock list.
void unlock() const
Unlock list.
std::list< std::string > get_loaded_plugins()
Get list of loaded plugins.
std::string get_description(const char *plugin_name)
Get plugin description.
void unload(const char *plugin_name)
Unload plugin.
virtual std::string get_string() const =0
Get string value.
static const unsigned int FAM_MOVED_FROM
File was moved from X.
virtual const char * path() const =0
Path of value.
virtual void add(ThreadList &tl)=0
Add multiple threads.
static const unsigned int FAM_MOVED_TO
File was moved to Y.
static void log_warn(const char *component, const char *format,...)
Log warning message.
PluginManager(ThreadCollector *thread_collector, Configuration *config, const char *meta_plugin_prefix, Module::ModuleFlags module_flags=Module::MODULE_FLAGS_DEFAULT, bool init_cache=true)
Constructor.
bool try_lock()
Tries to lock the mutex.
void cancel()
Cancel a thread.
virtual void config_value_changed(const Configuration::ValueIterator *v)
Called whenever a watched value has changed.
RefPtr<> is a reference-counting shared smartpointer.
virtual void config_value_erased(const char *path)
Called whenever a value has been erased from the config.
bool is_loaded(const char *plugin_name)
Check if plugin is loaded.
Iterator interface to iterate over config values.
void join()
Join the thread.
FileAlterationMonitor thread wrapper.
void lock()
Lock this mutex.
virtual void add_change_handler(ConfigurationChangeHandler *h)
Add a configuration change handler.
static const unsigned int FAM_DELETE
Subfile was deleted.
static const unsigned int FAM_MODIFY
File was modified.
void unlock()
Unlock plugin manager.
ModuleManager * get_module_manager() const
Get module manager.
bool is_loaded(const char *plugin_name)
Check if a plugin is loaded.
Mutex mutual exclusion lock.
Interface for configuration handling.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
void append(const char *format,...)
Append messages to the message list.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
void start(bool wait=true)
Call this method to start the thread.
Plugin * load(const char *plugin_name)
Load a specific plugin The plugin loader is clever and guarantees that every plugin is only loaded on...