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>
35 # include <utils/system/fam_thread.h>
37 #include <config/config.h>
38 #include <utils/system/dynamic_module/module_manager.h>
45 #include <sys/types.h>
57 plname_eq(std::string name) {
60 bool operator()(Plugin *plugin)
62 return (__name == plugin->name());
90 const char *meta_plugin_prefix,
95 __mutex =
new Mutex();
96 this->thread_collector = thread_collector;
101 __meta_plugin_prefix = meta_plugin_prefix;
112 fam->add_filter(
"^[^.].*\\."SOEXT
"$");
113 fam->add_listener(
this);
114 fam->watch_dir(PLUGINDIR);
115 __fam_thread->start();
118 "cannot detect changed plugins on disk.");
127 __fam_thread->cancel();
128 __fam_thread->join();
132 __pinfo_cache.
lock();
133 __pinfo_cache.clear();
136 for (rpit = plugins.rbegin(); rpit != plugins.rend(); ++rpit) {
138 plugin_loader->
unload(*rpit);
142 delete plugin_loader;
161 __pinfo_cache.
lock();
165 const char *file_ext =
"."SOEXT;
167 if ( NULL == (plugin_dir = opendir(PLUGINDIR)) ) {
168 throw Exception(errno,
"Plugin directory %s could not be opened", PLUGINDIR);
171 for (
unsigned int i = 0; NULL != (dirp = readdir(plugin_dir)); ++i) {
172 char *file_name = dirp->d_name;
173 char *pos = strstr(file_name, file_ext);
174 std::string plugin_name = std::string(file_name).substr(0, strlen(file_name) - strlen(file_ext));
177 __pinfo_cache.push_back(make_pair(plugin_name,
181 "exception follows", plugin_name.c_str());
187 closedir(plugin_dir);
193 std::string p = std::string(i->
path()).substr(__meta_plugin_prefix.length());
194 std::string s = std::string(
"Meta: ") + i->
get_string();
196 __pinfo_cache.push_back(make_pair(p, s));
203 __pinfo_cache.sort();
212 std::list<std::pair<std::string, std::string> >
215 std::list<std::pair<std::string, std::string> > rv;
217 std::list<std::pair<std::string, std::string> >::iterator i;
218 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
228 std::list<std::string>
231 std::list<std::string> rv;
234 for (pit = plugins.begin(); pit != plugins.end(); ++pit) {
235 rv.push_back((*pit)->name());
238 __meta_plugins.
lock();
239 for (__mpit = __meta_plugins.begin(); __mpit != __meta_plugins.end(); ++__mpit) {
240 rv.push_back(__mpit->first);
255 if (plugin_loader->
is_loaded(plugin_name)) {
259 return (__meta_plugins.find(plugin_name) != __meta_plugins.end());
270 std::list<std::string>
271 PluginManager::parse_plugin_list(
const char *plugin_list)
273 std::list<std::string> rv;
275 char *plugins = strdup(plugin_list);
279 plugin = strtok_r(plugins,
",", &saveptr);
281 rv.push_back(plugin);
282 plugin = strtok_r(NULL,
",", &saveptr);
299 std::list<std::string> pp = parse_plugin_list(plugin_list);
301 for (std::list<std::string>::iterator i = pp.begin(); i != pp.end(); ++i) {
302 if ( i->length() == 0 )
continue;
304 bool try_real_plugin =
true;
305 if ( __meta_plugins.find(*i) == __meta_plugins.end() ) {
306 std::string meta_plugin = __meta_plugin_prefix + *i;
308 std::string pset = __config->
get_string(meta_plugin.c_str());
309 if (pset.length() == 0) {
310 throw Exception(
"Refusing to load an empty meta plugin");
313 __meta_plugins.
lock();
316 __meta_plugins[*i] = pset;
320 pset.c_str(), i->c_str());
322 notify_loaded(i->c_str());
324 e.
append(
"Could not initialize meta plugin %s, aborting loading.", i->c_str());
329 try_real_plugin =
false;
333 try_real_plugin =
true;
337 if (try_real_plugin &&
338 (find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end()))
342 Plugin *plugin = plugin_loader->
load(i->c_str());
346 plugins.push_back(plugin);
347 plugin_ids[*i] = next_plugin_id++;
348 notify_loaded(i->c_str());
350 e.
prepend(
"Plugin >>> %s <<< could not be initialized, unloading", i->c_str());
352 plugin_loader->
unload(plugin);
358 if ( __meta_plugins.find(*i) == __meta_plugins.end() ) {
378 if ( (pit = find_if(plugins.begin(), plugins.end(), plname_eq(plugin_name)))
381 thread_collector->
remove((*pit)->threads());
382 plugin_loader->
unload(*pit);
384 plugin_ids.erase(plugin_name);
385 notify_unloaded(plugin_name);
388 __meta_plugins.
lock();
389 __mpit = __meta_plugins.begin();
390 while (__mpit != __meta_plugins.end()) {
391 std::list<std::string> pp = parse_plugin_list(__mpit->second.c_str());
394 for (std::list<std::string>::iterator i = pp.begin(); i != pp.end(); ++i) {
395 if ( *i == plugin_name ) {
403 notify_unloaded(tmp->first.c_str());
404 __meta_plugins.erase(tmp);
412 LibLogger::log_error(
"PluginManager",
"Could not finalize one or more threads of plugin %s, NOT unloading plugin", plugin_name);
415 }
else if (__meta_plugins.find(plugin_name) != __meta_plugins.end()) {
416 std::list<std::string> pp = parse_plugin_list(__meta_plugins[plugin_name].c_str());
418 for (std::list<std::string>::reverse_iterator i = pp.rbegin(); i != pp.rend(); ++i) {
419 if ( i->length() == 0 )
continue;
420 if ((find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end())
421 && (__meta_plugins.find(*i) != __meta_plugins.end()) ) {
427 i->c_str(), plugin_name);
443 __pinfo_cache.
lock();
444 std::string p = std::string(v->
path()).substr(__meta_plugin_prefix.length());
445 std::string s = std::string(
"Meta: ") + v->
get_string();
446 std::list<std::pair<std::string, std::string> >::iterator i;
448 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
456 __pinfo_cache.push_back(make_pair(p, s));
470 __pinfo_cache.
lock();
471 std::string p = std::string(path).substr(__meta_plugin_prefix.length());
472 std::list<std::pair<std::string, std::string> >::iterator i;
473 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
475 __pinfo_cache.erase(i);
486 const char *file_ext =
"."SOEXT;
488 const char *pos = strstr(filename, file_ext);
489 std::string p = std::string(filename).substr(0, strlen(filename) - strlen(file_ext));
491 __pinfo_cache.
lock();
493 std::list<std::pair<std::string, std::string> >::iterator i;
494 for (i = __pinfo_cache.begin(); i != __pinfo_cache.end(); ++i) {
498 __pinfo_cache.erase(i);
504 "description of plugin %s, exception follows",
515 if (plugin_loader->
is_loaded(p.c_str())) {
517 "loaded, no new info can be loaded, keeping old.",
522 __pinfo_cache.push_back(make_pair(p, s));
525 "description of plugin %s, exception follows",
531 __pinfo_cache.sort();
545 __listeners.push_back(listener);
547 __listeners.unique();
548 __listeners.unlock();
557 __listeners.remove_locked(listener);
561 PluginManager::notify_loaded(
const char *plugin_name)
564 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
566 (*__lit)->plugin_loaded(plugin_name);
567 }
catch (Exception &e) {
569 "during notification of plugin loaded, exception follows.");
573 __listeners.unlock();
577 PluginManager::notify_unloaded(
const char *plugin_name)
580 for (__lit = __listeners.begin(); __lit != __listeners.end(); ++__lit) {
582 (*__lit)->plugin_unloaded(plugin_name);
583 }
catch (Exception &e) {
585 "during notification of plugin unloaded, exception follows.");
589 __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.
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
void unlock() const
Unlock list.
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.
virtual void unlock() const
Unlock list.
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.
virtual void lock() const
Lock list.
ThreadList & threads()
Get a list of threads.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
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.
ModuleManager * get_module_manager() const
Get module manager.
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 lock() const
Lock list.
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.
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.
bool try_lock()
Tries to lock the mutex.
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.
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.
bool is_loaded(const char *plugin_name)
Check if a plugin is loaded.
Mutex mutual exclusion lock.
Interface for configuration handling.
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.
Plugin * load(const char *plugin_name)
Load a specific plugin The plugin loader is clever and guarantees that every plugin is only loaded on...