# BasicPluginManager.h

Go to the documentation of this file.

    00001 /*******************************************************************\
    00002
    00003               Copyright (C) 2003 Joseph Coffland
    00004
    00005     This program is free software; you can redistribute it and/or
    00006      modify it under the terms of the GNU General Public License
    00007     as published by the Free Software Foundation; either version 2
    00008         of the License, or (at your option) any later version.
    00009
    00010    This program is distributed in the hope that it will be useful,
    00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00013              GNU General Public License for more details.
    00014
    00015   You should have received a copy of the GNU General Public License
    00016      along with this program; if not, write to the Free Software
    00017       Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
    00018                            02111-1307, USA.
    00019
    00020             For information regarding this software email
    00021                    jcofflan@users.sourceforge.net
    00022
    00023 \*******************************************************************/
    00024
    00025 #ifndef BASICPLUGINMANAGER_H
    00026 #define BASICPLUGINMANAGER_H
    00027
    00028 #include "BasicException.h"
    00029 #include "BasicPluginInfo.h"
    00030 #include "BasicClassFactoryBase.h"
    00031
    00032 #include <map>
    00033 #include <list>
    00034 #include <string>
    00035 // #include <dlfcn.h>
    00036 #include <ltdl.h>
    00037 #include <string.h>
    00038 #include <glob.h>
    00039
    00040 template <class T>
    00041 class BasicPluginManager {
    00042 public:
    00043   typedef typename std::list<BasicPluginInfo *> infos_t;
    00044
    00045 private:
    00046   typedef typename std::map<std::string, BasicClassFactoryBase<T> *>
    00047   factories_t;
    00048   typedef typename std::map<std::string, BasicPluginInfo *> infoMap_t;
    00049   typedef typename std::map<std::string, T *> plugins_t;
    00050   typedef typename std::map<std::string, lt_dlhandle> libraryHandles_t;
    00051
    00053   factories_t factories;
    00054
    00056   infoMap_t infoMap;
    00057
    00059   plugins_t plugins;
    00060
    00062   libraryHandles_t libraryHandles;
    00063
    00065   infos_t infos;
    00066
    00068   BasicException *pluginException;
    00069
    00071   bool preloadDeps;
    00072
    00073 public:
    00075   static const char libExtension[];
    00076
    00077
    00078   BasicPluginManager(bool preloadDeps = false) :
    00079     pluginException(0), preloadDeps(preloadDeps) {
    00080     int result = lt_dlinit();
    00081     if(result != 0) {
    00082       std::cout << "Error initializing ltdl" << std::endl;
    00083     }
    00084   }
    00085
    00090   virtual ~BasicPluginManager() {
    00091     unload();
    00092
    00093     // Deallocate infos
    00094     infos_t::iterator it;
    00095     for (it = infos.begin(); it != infos.end(); it++)
    00096       delete *it;
    00097
    00098     // Deallocate factories
    00099     typename factories_t::iterator fIt;
    00100     for (fIt = factories.begin(); fIt != factories.end(); fIt++)
    00101       delete fIt->second;
    00102
    00103     closeLibraries();
    00104   }
    00105
    00113   virtual void init(T *plugin) {}
    00114
    00118   void destroyPlugin(std::string pluginName) {
    00119     if (!plugins[pluginName]) return;
    00120
    00121     // Deallocate dependent plugins first.
    00122     // Dependency cycles should be disallowed on plugin registration!
    00123     typename plugins_t::iterator it;
    00124     for (it = plugins.begin(); it != plugins.end(); it++)
    00125       if (dependsOn(it->first, pluginName))
    00126         destroyPlugin(it->first);
    00127
    00128     // Deallocate the plugin.
    00129     BasicClassFactoryBase<T> *factory = getPluginFactory(pluginName);
    00130     it = plugins.find(pluginName);
    00131     factory->destroy(it->second);
    00132     plugins.erase(it);
    00133   }
    00134
    00136   void unload() {
    00137     while (!plugins.empty()) {
    00138       if (!plugins.begin()->second) plugins.erase(plugins.begin());
    00139       else destroyPlugin(plugins.begin()->first);
    00140     }
    00141   }
    00142
    00144   void closeLibraries() {
    00145     typename libraryHandles_t::iterator it;
    00146     for (it = libraryHandles.begin(); it != libraryHandles.end(); it++)
    00147       if (it->second) lt_dlclose(it->second);
    00148     libraryHandles.clear();
    00149   }
    00150
    00158   bool dependsOn(std::string plugin1, std::string plugin2) {
    00159     const BasicPluginInfo *info = infoMap[plugin1];
    00160     if (!info) return false;
    00161
    00162     // Assumes dependency cycles have been disallowed on plugin registration!
    00163     std::string dep;
    00164     for (unsigned int i = 0; i < info->getNumDeps(); i++) {
    00165       dep = info->getDependency(i);
    00166       if (dep == plugin2 || dependsOn(dep, plugin2)) return true;
    00167     }
    00168     return false;
    00169   }
    00170
    00180   T *get(const std::string pluginName) {
    00181     T *plugin = plugins[pluginName];
    00182     if (plugin) return plugin;
    00183
    00184     // Get the factory
    00185     BasicClassFactoryBase<T> *factory = getPluginFactory(pluginName);
    00186
    00187     if (preloadDeps) {
    00188       // Make sure its dependencies have been initialized first.
    00189       const BasicPluginInfo *info = getPluginInfo(pluginName);
    00190       for (unsigned int i = 0; i < info->getNumDeps(); i++)
    00191         get(info->getDependency(i));
    00192     }
    00193
    00194     // Create the plugin
    00195     plugin = factory->create();
    00196     plugins[pluginName] = plugin;
    00197
    00198     // Initialize the plugin
    00199     init(plugin);
    00200
    00201     return plugin;
    00202   }
    00203
    00204
    00206   bool isLoaded(std::string pluginName) {
    00207     return plugins[pluginName] != 0;
    00208   }
    00209
    00211   const BasicPluginInfo *getPluginInfo(const std::string pluginName) {
    00212     typename infoMap_t::iterator it = infoMap.find(pluginName);
    00213     ASSERT_OR_THROW(std::string("Plugin '") + pluginName + " not found!",
    00214                     it != infoMap.end());
    00215
    00216     return it->second;
    00217   }
    00218
    00222   infos_t &getPluginInfos() {return infos;}
    00223
    00224
    00230   void loadLibraries(const std::string path) {
    00231     char *cPath = strdup(path.c_str());
    00232
    00233     char *aPath = strtok(cPath, ":");
    00234     while (aPath != NULL) {
    00235       loadSingleLibraryPath(aPath);
    00236
    00237       aPath = strtok(NULL, ":");
    00238     }
    00239
    00240     free(cPath);
    00241   }
    00242
    00248   void loadLibrary(const std::string filename) {
    00249     // Get the library name
    00250     std::string name;
    00251     std::string::size_type pos = filename.find_last_of("/");
    00252     if (pos != std::string::npos) name = filename.substr(pos + 1);
    00253     else name = filename;
    00254
    00255     // Exit if already opened.
    00256     if (libraryHandles[name] != NULL) return;
    00257
    00258     lt_dlhandle handle = lt_dlopen(filename.c_str()); // , RTLD_LAZY | RTLD_GLOBAL);
    00259     const char *error;
    00260     if ((handle == NULL) && (error = lt_dlerror())) {
    00261       std::cout << "Error Loading " << filename << " " << error << endl;
    00262       THROW(std::string("BasicPluginManager::loadLibrary() ") + error);
    00263     }
    00264
    00265     if (handle) libraryHandles[name] = handle;
    00266
    00267     if (pluginException) {
    00268       BasicException e = *pluginException;
    00269       delete pluginException;
    00270       throw BasicException(std::string("Exception while loading library '") +
    00271                            filename + "'", e);
    00272     }
    00273   }
    00274
    00281   void registerPlugin(BasicPluginInfo *info,
    00282                       BasicClassFactoryBase<T> *factory) {
    00283     ASSERT_OR_THROW("registerPlugin() Plugin info cannot be null!!",
    00284                     info);
    00285     ASSERT_OR_THROW("registerPlugin() Plugin factory cannot be null!!",
    00286                     factory);
    00287
    00288     ASSERT_OR_THROW(std::string("registerPlugin() A plugin with name ") +
    00289                     info->getName() + " was already registered!",
    00290                     infoMap[info->getName()] == NULL);
    00291
    00292     // Check for dependency loops.
    00293     std::string dep;
    00294     for (unsigned int i = 0; i < info->getNumDeps(); i++) {
    00295       dep = info->getDependency(i);
    00296       if (dependsOn(dep, info->getName()))
    00297         throw
    00298           BasicException(std::string("BasicPluginManager::registerPlugin() ") +
    00299                          "Detected dependency cycle between plugins '" +
    00300                          info->getName() + "' and '" + dep + "'!");
    00301     }
    00302
    00303     // Register the plugin
    00304     infoMap[info->getName()] = info;
    00305     infos.push_back(info);
    00306     factories[info->getName()] = factory;
    00307   }
    00308
    00313   void setPluginException(BasicException e) {
    00314     if (!pluginException)
    00315       pluginException = new BasicException(e);
    00316   }
    00317
    00318 protected:
    00320   BasicClassFactoryBase<T> *
    00321   getPluginFactory(const std::string pluginName) {
    00322     typename factories_t::iterator it = factories.find(pluginName);
    00323     ASSERT_OR_THROW(std::string("Plugin '") + pluginName + " not found!",
    00324                     it != factories.end());
    00325
    00326     return it->second;
    00327   }
    00328
    00334   void loadSingleLibraryPath(const std::string path) {
    00335     glob_t globbuf;
    00336     std::string pathGlob = path + "/" + "*" + libExtension;
    00337
    00338     if (glob(pathGlob.c_str(), 0, NULL, &globbuf) == 0) {
    00339       for (int i = 0; i < globbuf.gl_pathc; i++)
    00340         loadLibrary(globbuf.gl_pathv[i]);
    00341     }
    00342
    00343     globfree(&globbuf);
    00344   }
    00345 };
    00346
    00347
    00348 template<class T>
    00349 const char BasicPluginManager<T>::libExtension[] = ".so";
    00350
    00351 #endif