2 /***************************************************************************
3 * loader.cpp - Loads plugins from .so shared objects
5 * Created: Wed Aug 23 15:23:36 2006
6 * Copyright 2006-2008 Tim Niemueller [www.niemueller.de]
8 ****************************************************************************/
10 /* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
24 #include <plugin/loader.h>
26 #include <utils/system/dynamic_module/module_manager_factory.h>
27 #include <utils/system/dynamic_module/module_manager.h>
28 #include <utils/system/dynamic_module/module.h>
33 #if 0 /* just to make Emacs auto-indent happy */
38 class PluginLoaderData
42 std::map< Plugin *, Module * > plugin_module_map;
43 std::map< std::string, Plugin * > name_plugin_map;
44 std::map< Plugin *, std::string > plugin_name_map;
48 /** @class PluginLoadException <plugin/loader.h>
49 * This exception is thrown if the requested plugin could not be loaded.
53 * @param plugin name of the plugin that caused the exception
54 * @param message message of exception
56 PluginLoadException::PluginLoadException(const char *plugin, const char *message)
57 : Exception(), __plugin_name(plugin)
59 append("Plugin '%s' could not be loaded: %s", plugin, message);
64 PluginLoadException::~PluginLoadException() throw()
69 * @param plugin name of the plugin that caused the exception
70 * @param message message of exception
71 * @param e exception to copy further messages from
73 PluginLoadException::PluginLoadException(const char *plugin, const char *message,
75 : Exception(), __plugin_name(plugin)
77 append("Plugin '%s' could not be loaded: %s", plugin, message);
81 /** Get name of plugin which failed to load.
85 PluginLoadException::plugin_name() const
91 /** @class PluginUnloadException <plugin/loader.h>
92 * This exception is thrown if the requested plugin could not be unloaded.
96 * @param plugin_name name of the plugin
97 * @param add_msg additional message, reason for problem
99 PluginUnloadException::PluginUnloadException(const char *plugin_name,
103 append("Plugin '%s' could not be unloaded", plugin_name);
108 /** @class PluginLoader <plugin/loader.h>
109 * This class manages plugins.
110 * With this class plugins can be loaded and unloaded. Information is
111 * kept about active plugins.
113 * @author Tim Niemueller
117 * @param plugin_base_dir The base directory where to search for the shared
118 * libraries which contain the plugins
119 * @param config Fawkes configuration
121 PluginLoader::PluginLoader(const char *plugin_base_dir, Configuration *config)
123 d = new PluginLoaderData();
125 d->mm = ModuleManagerFactory::getInstance(ModuleManagerFactory::MMT_DL, plugin_base_dir);
129 PluginLoader::~PluginLoader()
137 PluginLoader::open_module(const char *plugin_name)
139 std::string module_name = std::string(plugin_name) + "." + d->mm->get_module_file_extension();
142 return d->mm->open_module(module_name.c_str());
143 } catch (ModuleOpenException &e) {
144 throw PluginLoadException(plugin_name, "failed to open module", e);
150 PluginLoader::create_instance(const char *plugin_name, Module *module)
152 if ( ! module->has_symbol("plugin_factory") ) {
153 throw PluginLoadException(plugin_name, "Symbol 'plugin_factory' not found. Forgot EXPORT_PLUGIN?");
155 if ( ! module->has_symbol("plugin_description") ) {
156 throw PluginLoadException(plugin_name, "Symbol 'plugin_description' not found. Forgot PLUGIN_DESCRIPTION?");
159 PluginFactoryFunc pff = (PluginFactoryFunc)module->get_symbol("plugin_factory");
164 throw PluginLoadException(plugin_name, "Plugin could not be instantiated");
166 p->set_name(plugin_name);
173 /** Load a specific plugin
174 * The plugin loader is clever and guarantees that every plugin is only
175 * loaded once (as long as you use only one instance of the PluginLoader,
176 * using multiple instances is discouraged. If you try to open a plugin
177 * a second time it will return the
178 * very same instance that it returned on previous load()s.
179 * @param plugin_name The name of the plugin to be loaded, the plugin name has to
180 * correspond to a plugin name and the name of the shared object that will
181 * be opened for this plugin (for instance on Linux systems opening the
182 * plugin test_plugin will look for plugin_base_dir/test_plugin.so)
183 * @return Returns a pointer to the opened plugin. Do not under any
184 * circumstances delete this object, use unload() instead! Since the delete
185 * operator could be overloaded this would result in memory chaos.
186 * @exception PluginLoadException thrown if plugin could not be loaded
187 * @exception ModuleOpenException passed along from module manager
190 PluginLoader::load(const char *plugin_name)
192 std::string pn = plugin_name;
194 if ( d->name_plugin_map.find(pn) != d->name_plugin_map.end() ) {
195 return d->name_plugin_map[pn];
199 Module *module = open_module(plugin_name);
200 Plugin *p = create_instance(plugin_name, module);
202 d->plugin_module_map[p] = module;
203 d->name_plugin_map[pn] = p;
204 d->plugin_name_map[p] = pn;
207 } catch (PluginLoadException &e) {
213 /** Get plugin description.
214 * @param plugin_name name of the plugin
215 * @return plugin description tring
216 * @throw PluginLoadException thrown if opening the plugin fails
219 PluginLoader::get_description(const char *plugin_name)
221 Module *module = open_module(plugin_name);
223 if ( ! module->has_symbol("plugin_description") ) {
224 throw PluginLoadException(plugin_name, "Symbol 'plugin_description' not found. Forgot PLUGIN_DESCRIPTION?");
227 PluginDescriptionFunc pdf = (PluginDescriptionFunc)module->get_symbol("plugin_description");
228 std::string rv = pdf();
229 d->mm->close_module(module);
235 /** Check if a plugin is loaded.
236 * @param plugin_name name of the plugin to chekc
237 * @return true if the plugin is loaded, false otherwise
240 PluginLoader::is_loaded(const char *plugin_name)
242 return ( d->name_plugin_map.find(plugin_name) != d->name_plugin_map.end() );
246 /** Unload the given plugin
247 * This will unload the given plugin. The plugin is destroyed with the
248 * proper destroy method from the shared object. The shared object is unloaded
249 * after the destruction of the plugin.
250 * Note that even though you may call load() multiple times per plugin you may
251 * only unload() it once! Every further access will lead to a segmentation
253 * Make sure that you have closed any resources claimed by the plugin like
254 * threads, memory access etc.
255 * @param plugin The plugin that has to be unloaded
258 PluginLoader::unload(Plugin *plugin)
260 if ( d->plugin_module_map.find(plugin) != d->plugin_module_map.end() ) {
262 PluginDestroyFunc pdf = (PluginDestroyFunc)d->plugin_module_map[plugin]->get_symbol("plugin_destroy");
266 d->mm->close_module(d->plugin_module_map[plugin]);
267 d->plugin_module_map.erase(plugin);
269 d->name_plugin_map.erase(d->plugin_name_map[plugin]);
270 d->plugin_name_map.erase(plugin);
274 } // end namespace fawkes