24#include <config/config.h>
25#include <core/exception.h>
26#include <core/plugin.h>
27#include <core/threading/mutex_locker.h>
28#include <core/threading/thread_collector.h>
29#include <core/threading/thread_initializer.h>
30#include <logging/liblogger.h>
31#include <plugin/listener.h>
32#include <plugin/loader.h>
33#include <plugin/manager.h>
35#include <utils/misc/string_split.h>
36#include <utils/system/dynamic_module/module_manager.h>
37#include <utils/system/fam_thread.h>
51 plname_eq(std::string name)
58 return (name_ == plugin->
name());
87 const char * meta_plugin_prefix,
93 this->thread_collector = thread_collector;
98 meta_plugin_prefix_ = meta_plugin_prefix;
109 fam->add_filter(
"^[^.].*\\." SOEXT
"$");
110 fam->add_listener(
this);
111 fam->watch_dir(PLUGINDIR);
112 fam_thread_->
start();
115 "File alteration monitoring not available, "
116 "cannot detect changed plugins on disk.");
130 pinfo_cache_.clear();
133 for (rpit = plugins.rbegin(); rpit != plugins.rend(); ++rpit) {
142 plugin_loader->
unload(*rpit);
146 delete plugin_loader;
167 const char * file_ext =
"." SOEXT;
169 if (NULL == (plugin_dir = opendir(PLUGINDIR))) {
170 throw Exception(errno,
"Plugin directory %s could not be opened", PLUGINDIR);
173 for (
unsigned int i = 0; NULL != (dirp = readdir(plugin_dir)); ++i) {
174 char * file_name = dirp->d_name;
175 char * pos = strstr(file_name, file_ext);
176 std::string plugin_name =
177 std::string(file_name).substr(0, strlen(file_name) - strlen(file_ext));
180 pinfo_cache_.push_back(
181 make_pair(plugin_name, plugin_loader->
get_description(plugin_name.c_str())));
184 "Could not get description of plugin %s, "
186 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));
217std::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) {
233std::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);
259 if (plugin_loader->
is_loaded(plugin_name.c_str())) {
263 return (meta_plugins_.find(plugin_name) != meta_plugins_.end());
275 std::string meta_plugin_path = meta_plugin_prefix_ + plugin_name;
276 return (config_->
is_string(meta_plugin_path.c_str()));
286std::list<std::string>
289 std::string meta_plugin_path = meta_plugin_prefix_ + plugin_name;
290 std::string meta_plugin_str = config_->
get_string(meta_plugin_path.c_str());
291 return parse_plugin_list(meta_plugin_str.c_str());
300std::list<std::string>
301PluginManager::parse_plugin_list(
const char *plugin_list)
303 std::list<std::string> rv;
305 char *plugins = strdup(plugin_list);
309 plugin = strtok_r(plugins,
",", &saveptr);
311 rv.push_back(plugin);
312 plugin = strtok_r(NULL,
",", &saveptr);
327 load(parse_plugin_list(plugin_list.c_str()));
339 for (std::list<std::string>::const_iterator i = plugin_list.begin(); i != plugin_list.end();
341 if (i->length() == 0)
344 bool try_real_plugin =
true;
345 if (meta_plugins_.find(*i) == meta_plugins_.end()) {
346 std::string meta_plugin = meta_plugin_prefix_ + *i;
347 bool found_meta =
false;
348 std::list<std::string> pset;
350 if (config_->
is_list(meta_plugin.c_str())) {
351 std::vector<std::string> tmp = config_->
get_strings(meta_plugin.c_str());
352 pset.insert(pset.end(), tmp.begin(), tmp.end());
354 pset = parse_plugin_list(config_->
get_string(meta_plugin.c_str()).c_str());
359 try_real_plugin =
true;
363 if (pset.size() == 0) {
364 throw Exception(
"Refusing to load an empty meta plugin");
367 meta_plugins_.
lock();
370 meta_plugins_[*i] = pset;
374 "Loading plugins %s for meta plugin %s",
375 str_join(pset.begin(), pset.end(),
",").c_str(),
379 notify_loaded(i->c_str());
381 e.
append(
"Could not initialize meta plugin %s, aborting loading.", i->c_str());
386 try_real_plugin =
false;
391 && (find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end())) {
394 Plugin *plugin = plugin_loader->
load(i->c_str());
398 plugins.push_back(plugin);
399 plugin_ids[*i] = next_plugin_id++;
401 notify_loaded(i->c_str());
403 e.
append(
"Plugin >>> %s <<< could not be initialized, unloading", i->c_str());
405 plugin_loader->
unload(plugin);
411 if (meta_plugins_.find(*i) == meta_plugins_.end()) {
430 if ((pit = find_if(plugins.begin(), plugins.end(), plname_eq(plugin_name))) != plugins.end()) {
432 thread_collector->
remove((*pit)->threads());
433 plugin_loader->
unload(*pit);
435 plugin_ids.erase(plugin_name);
436 notify_unloaded(plugin_name.c_str());
439 meta_plugins_.
lock();
440 mpit_ = meta_plugins_.begin();
441 while (mpit_ != meta_plugins_.end()) {
442 std::list<std::string> pp = mpit_->second;
445 for (std::list<std::string>::iterator i = pp.begin(); i != pp.end(); ++i) {
446 if (*i == plugin_name) {
454 notify_unloaded(tmp->first.c_str());
455 meta_plugins_.erase(tmp);
464 "Could not finalize one or more threads "
465 "of plugin %s, NOT unloading plugin",
466 plugin_name.c_str());
469 }
else if (meta_plugins_.find(plugin_name) != meta_plugins_.end()) {
470 std::list<std::string> pp = meta_plugins_[plugin_name];
472 for (std::list<std::string>::reverse_iterator i = pp.rbegin(); i != pp.rend(); ++i) {
473 if (i->length() == 0)
475 if ((find_if(plugins.begin(), plugins.end(), plname_eq(*i)) == plugins.end())
476 && (meta_plugins_.find(*i) != meta_plugins_.end())) {
482 "UNloading plugin %s for meta plugin %s",
484 plugin_name.c_str());
500 std::string p = std::string(v->
path()).substr(meta_plugin_prefix_.length());
501 std::string s = std::string(
"Meta: ") + v->
get_string();
502 std::list<std::pair<std::string, std::string>>::iterator i;
504 for (i = pinfo_cache_.begin(); i != pinfo_cache_.end(); ++i) {
512 pinfo_cache_.push_back(make_pair(p, s));
527 std::string p = std::string(path).substr(meta_plugin_prefix_.length());
528 std::list<std::pair<std::string, std::string>>::iterator i;
529 for (i = pinfo_cache_.begin(); i != pinfo_cache_.end(); ++i) {
531 pinfo_cache_.erase(i);
541 const char *file_ext =
"." SOEXT;
543 const char *pos = strstr(filename, file_ext);
544 std::string p = std::string(filename).substr(0, strlen(filename) - strlen(file_ext));
548 std::list<std::pair<std::string, std::string>>::iterator i;
549 for (i = pinfo_cache_.begin(); i != pinfo_cache_.end(); ++i) {
553 pinfo_cache_.erase(i);
559 "Could not get possibly modified "
560 "description of plugin %s, exception follows",
571 if (plugin_loader->
is_loaded(p.c_str())) {
573 "Plugin %s changed on disk, but is "
574 "loaded, no new info can be loaded, keeping old.",
580 LibLogger::log_info(
"PluginManager",
"Reloaded meta-data of %s on file change", p.c_str());
581 pinfo_cache_.push_back(make_pair(p, s));
606 listeners_.push_back(listener);
618 listeners_.remove_locked(listener);
622PluginManager::notify_loaded(
const char *plugin_name)
625 for (lit_ = listeners_.begin(); lit_ != listeners_.end(); ++lit_) {
627 (*lit_)->plugin_loaded(plugin_name);
628 }
catch (Exception &e) {
630 "PluginManagerListener threw exception "
631 "during notification of plugin loaded, exception follows.");
639PluginManager::notify_unloaded(
const char *plugin_name)
642 for (lit_ = listeners_.begin(); lit_ != listeners_.end(); ++lit_) {
644 (*lit_)->plugin_unloaded(plugin_name);
645 }
catch (Exception &e) {
647 "PluginManagerListener threw exception "
648 "during notification of plugin unloaded, exception follows.");
Plugin representation for JSON transfer.
std::optional< std::string > name() const
Get name value.
Thread cannot be initialized.
Thrown if a config entry could not be found.
Interface for configuration change handling.
Iterator interface to iterate over config values.
virtual const char * path() const =0
Path of value.
virtual bool next()=0
Check if there is another element and advance to this if possible.
virtual bool is_string() const =0
Check if current value is a string.
virtual std::string get_string() const =0
Get string value.
Interface for configuration handling.
virtual std::vector< std::string > get_strings(const char *path)=0
Get list of values from configuration which is of type string.
virtual void rem_change_handler(ConfigurationChangeHandler *h)
Remove a configuration change handler.
virtual ValueIterator * search(const char *path)=0
Iterator with search results.
virtual bool is_list(const char *path)=0
Check if a value is a list.
virtual bool is_string(const char *path)=0
Check if a value is of type string.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
virtual void add_change_handler(ConfigurationChangeHandler *h)
Add a configuration change handler.
Base class for exceptions in Fawkes.
void append(const char *format,...) noexcept
Append messages to the message list.
static const unsigned int FAM_MOVED_TO
File was moved to Y.
static const unsigned int FAM_MODIFY
File was modified.
static const unsigned int FAM_DELETE
Subfile was deleted.
static const unsigned int FAM_ISDIR
Event occurred against dir.
static const unsigned int FAM_MOVED_FROM
File was moved from X.
static const unsigned int FAM_CREATE
Subfile was created.
FileAlterationMonitor thread wrapper.
RefPtr< FileAlterationMonitor > get_fam()
Get FileAlterationMonitor.
static void log_warn(const char *component, const char *format,...)
Log warning message.
static void log_info(const char *component, const char *format,...)
Log informational message.
static void log_error(const char *component, const char *format,...)
Log error message.
static void log_debug(const char *component, const char *format,...)
Log debug message.
virtual void unlock() const
Unlock list.
virtual void lock() const
Lock list.
void lock() const
Lock list.
RefPtr< Mutex > mutex() const
Get access to the internal mutex.
void unlock() const
Unlock list.
void erase_locked(const KeyType &key)
Remove item with lock.
void set_open_flags(Module::ModuleFlags open_flags)
Set flags to open modules with.
ModuleFlags
Flags for the loading process.
Mutex mutual exclusion lock.
bool try_lock()
Tries to lock the mutex.
void lock()
Lock this mutex.
void unlock()
Unlock the mutex.
This class manages plugins.
bool is_loaded(const char *plugin_name)
Check if a plugin is loaded.
ModuleManager * get_module_manager() const
Get module manager.
std::string get_description(const char *plugin_name)
Get plugin description.
Plugin * load(const char *plugin_name)
Load a specific plugin The plugin loader is clever and guarantees that every plugin is only loaded on...
void unload(Plugin *plugin)
Unload the given plugin This will unload the given plugin.
virtual void config_value_changed(const Configuration::ValueIterator *v)
Called whenever a watched value has changed.
void remove_listener(PluginManagerListener *listener)
Remove listener.
bool is_loaded(const std::string &plugin_name)
Check if plugin is loaded.
~PluginManager()
Destructor.
void unload(const std::string &plugin_name)
Unload plugin.
virtual void config_comment_changed(const Configuration::ValueIterator *v)
Called whenever a comment of a watched value has changed.
void init_pinfo_cache()
Initialize plugin info cache.
std::list< std::pair< std::string, std::string > > get_available_plugins()
Generate list of all available plugins.
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
void add_listener(PluginManagerListener *listener)
Add listener.
void load(const std::string &plugin_list)
Load plugin.
std::list< std::string > get_loaded_plugins()
Get list of loaded plugins.
void unlock()
Unlock plugin manager.
virtual void config_tag_changed(const char *new_location)
Called whenever the tag has changed.
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()
Try to lock plugin manager.
std::list< std::string > get_meta_plugin_children(const std::string &plugin_name)
Get meta plugin children.
bool is_meta_plugin(const std::string &plugin_name)
Check if plugin is a meta plugin.
virtual void config_value_erased(const char *path)
Called whenever a value has been erased from the config.
void lock()
Lock plugin manager.
void set_module_flags(Module::ModuleFlags flags)
Set flags to open modules with.
ThreadList & threads()
Get a list of threads.
RefPtr<> is a reference-counting shared smartpointer.
virtual void force_remove(fawkes::ThreadList &tl)=0
Force removal of multiple threads.
virtual void add(ThreadList &tl)=0
Add multiple threads.
virtual void remove(ThreadList &tl)=0
Remove multiple threads.
void start(bool wait=true)
Call this method to start the thread.
void join()
Join the thread.
void cancel()
Cancel a thread.
Fawkes library namespace.
static std::string str_join(const std::vector< std::string > &v, char delim='/')
Join vector of strings string using given delimiter.