Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

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

Generated on Thu Sep 16 16:17:17 2004 for nostdinc by doxygen 1.3.8