Changeset 4869 for branches/erijo-dev
- Timestamp:
- 03/20/07 05:17:03 (21 months ago)
- Location:
- branches/erijo-dev/licq/src/plugin
- Files:
-
- 1 added
- 2 removed
- 4 modified
- 4 moved
-
CMakeLists.txt (modified) (1 diff)
-
plugin.h (added)
-
pluginfactory.h (moved) (moved from branches/erijo-dev/licq/src/plugin/pluginfactoryproxy.h) (4 diffs)
-
pluginloader.cpp (modified) (8 diffs)
-
pluginloader.h (modified) (3 diffs)
-
pluginprototype.cpp (deleted)
-
pluginprototype.h (deleted)
-
pluginrepository.cpp (moved) (moved from branches/erijo-dev/licq/src/plugin/pluginmanager.cpp) (2 diffs)
-
pluginrepository.h (moved) (moved from branches/erijo-dev/licq/src/plugin/pluginmanager.h) (1 diff)
-
tests/CMakeLists.txt (modified) (1 diff)
-
tests/pluginfactorytest.cpp (moved) (moved from branches/erijo-dev/licq/src/plugin/tests/pluginfactoryproxytest.cpp) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
branches/erijo-dev/licq/src/plugin/CMakeLists.txt
r4852 r4869 1 1 set(licqplugin_SRCS 2 2 pluginloader.cpp 3 pluginmanager.cpp 4 pluginprototype.cpp 3 pluginrepository.cpp 5 4 ) 6 5 -
branches/erijo-dev/licq/src/plugin/pluginfactory.h
r4852 r4869 18 18 */ 19 19 20 #ifndef LICQ_TPLUGINFACTORY PROXY_H21 #define LICQ_TPLUGINFACTORY PROXY_H20 #ifndef LICQ_TPLUGINFACTORY_H 21 #define LICQ_TPLUGINFACTORY_H 22 22 23 23 #include "licq/interface/pluginfactory.h" 24 24 #include "utils/dynamiclibrary.h" 25 25 26 #include <boost/noncopyable.hpp>27 26 #include <boost/shared_ptr.hpp> 27 #include <cassert> 28 28 29 29 namespace Licq 30 30 { 31 31 32 class TPluginFactoryProxy; 33 typedef boost::shared_ptr<TPluginFactoryProxy> TPluginFactoryProxyPtr; 34 35 class TPluginFactoryProxy : private boost::noncopyable 32 class TPluginFactory : public IPluginFactory 36 33 { 37 34 private: … … 43 40 44 41 /// Function to use when destroying the factory. 45 destroyPluginFactory_tFactoryDestructor;42 FnDestroyPluginFactory FactoryDestructor; 46 43 47 44 public: 48 /** \brief Create a new plugin factory proxy.45 /** \brief Create a new plugin factory. 49 46 50 47 \param[in] library The library the real factory was loaded from. 51 \param[in] factory The real factory. 52 \param[in] factoryDestructor The function that should be called to 53 destroy the real factory. 48 \param[in] constructor The function to call to create the real factory. 49 \param[in] destructor The function to call to destroy the real factory. 54 50 */ 55 TPluginFactoryProxy(TDynamicLibrary* library, IPluginFactory* factory, 56 destroyPluginFactory_t factoryDestructor); 51 TPluginFactory(TDynamicLibrary* library, 52 FnCreatePluginFactory constructor, 53 FnDestroyPluginFactory destructor); 57 54 58 55 /** \brief Destroy the factory. … … 60 57 Destroys the real factory and unloads the dynamic library. 61 58 */ 62 ~TPluginFactory Proxy();59 ~TPluginFactory(); 63 60 64 /** \brief Get the real factory. 65 \return The real factory. 66 */ 67 IPluginFactory* getFactory(); 61 /// File the factory was loaded from. 62 std::string getLibraryFilename() const; 63 64 // From IPluginFactory 65 unsigned int getPluginCount() const; 66 TPluginInformation getPluginInformation(unsigned int index) const; 67 IPlugin* createPlugin(unsigned int index, TPluginId id, ILog* log); 68 68 }; 69 69 70 70 } // namespace Licq 71 71 72 inline 73 Licq::TPluginFactoryProxy::TPluginFactoryProxy(TDynamicLibrary* library, 74 IPluginFactory* factory, 75 destroyPluginFactory_t factoryDestructor) 76 : Library(library), Factory(factory), FactoryDestructor(factoryDestructor) 72 inline Licq::TPluginFactory::TPluginFactory(TDynamicLibrary* library, 73 FnCreatePluginFactory constructor, 74 FnDestroyPluginFactory destructor) 75 : Library(library), 76 Factory(constructor()), 77 FactoryDestructor(destructor) 77 78 { 78 // Empty79 assert(Factory != NULL); 79 80 } 80 81 81 inline Licq::TPluginFactory Proxy::~TPluginFactoryProxy()82 inline Licq::TPluginFactory::~TPluginFactory() 82 83 { 83 84 FactoryDestructor(Factory); … … 85 86 } 86 87 87 inline Licq::IPluginFactory* Licq::TPluginFactoryProxy::getFactory()88 inline std::string Licq::TPluginFactory::getLibraryFilename() const 88 89 { 89 return Factory; 90 assert(Library != NULL); 91 return Library->getFilename(); 92 } 93 94 inline unsigned int Licq::TPluginFactory::getPluginCount() const 95 { 96 return Factory->getPluginCount(); 97 } 98 99 inline Licq::TPluginInformation 100 Licq::TPluginFactory::getPluginInformation(unsigned int index) const 101 { 102 return Factory->getPluginInformation(index); 103 } 104 105 inline Licq::IPlugin* 106 Licq::TPluginFactory::createPlugin(unsigned int index, TPluginId id, ILog* log) 107 { 108 return Factory->createPlugin(index, id, log); 90 109 } 91 110 -
branches/erijo-dev/licq/src/plugin/pluginloader.cpp
r4852 r4869 18 18 */ 19 19 20 #include "licq/interface/pluginfactory.h"21 20 #include "licq/version.h" 22 21 23 22 #include "plugin/pluginloader.h" 24 #include "plugin/pluginfactoryproxy.h"25 23 #include "utils/dynamiclibrary.h" 26 24 … … 44 42 } 45 43 46 unsigned int 47 Licq::TPluginLoader::loadPluginsFromDir(const bfs::path& dir, TPluginPrototypeList* pluginList) 44 unsigned int Licq:: 45 TPluginLoader::loadPluginsFromDir(const bfs::path& dir, 46 TPluginFactories* factories) 48 47 { 49 48 assert(bfs::is_directory(dir) == true); … … 55 54 { 56 55 if (!bfs::is_directory(*file)) 57 loadCount += loadPluginsFromFile(*file, pluginList);56 loadCount += loadPluginsFromFile(*file, factories); 58 57 } 59 58 … … 61 60 } 62 61 63 unsigned int 64 Licq::TPluginLoader::loadPluginsFromFile(const bfs::path& file, TPluginPrototypeList* pluginList) 62 unsigned int Licq:: 63 TPluginLoader::loadPluginsFromFile(const bfs::path& file, 64 TPluginFactories* factories) 65 65 { 66 66 assert(bfs::is_directory(file) == false); … … 80 80 81 81 // First check that the plugin and daemon uses the same API version 82 getPluginApiVersion_tapiVersion;82 FnGetPluginApiVersion apiVersion; 83 83 if (!lib->loadSymbol("licqGetPluginApiVersion", &apiVersion)) 84 84 return 0; … … 93 93 94 94 // Load symbols for creating and destroying plugin factory 95 createPluginFactory_tcreatePluginFactory;95 FnCreatePluginFactory createPluginFactory; 96 96 if (!lib->loadSymbol("licqCreatePluginFactory", &createPluginFactory)) 97 97 return 0; 98 98 99 destroyPluginFactory_tdestroyPluginFactory;99 FnDestroyPluginFactory destroyPluginFactory; 100 100 if (!lib->loadSymbol("licqDestroyPluginFactory", &destroyPluginFactory)) 101 101 return 0; 102 102 103 // Try and create the plugin factory 104 TPluginFactoryProxyPtr 105 factoryProxy(new TPluginFactoryProxy(libptr.release(), 106 createPluginFactory(), 107 destroyPluginFactory)); 108 if (factoryProxy->getFactory() == NULL) 103 // Create the plugin factory 104 boost::shared_ptr<TPluginFactory> 105 factory(new TPluginFactory(libptr.release(), 106 createPluginFactory, 107 destroyPluginFactory)); 108 109 if (factory->getPluginCount() == 0) 109 110 { 110 Log->error("Failed to create plugin factory for %s", filename.c_str()); 111 // No point in saving an empty factory. 112 Log->debug("IPluginFactory::getPluginCount() == 0 for %s", filename.c_str()); 111 113 return 0; 112 114 } 113 115 114 // Create the "plugins" 115 const unsigned int count = factoryProxy->getFactory()->getPluginCount(); 116 for (unsigned int i = 0; i < count; ++i) 117 pluginList->push_back(new TPluginPrototype(factoryProxy, i)); 118 119 // If count = 0, the factory will be destroyed and the library unloaded 120 return count; 116 // Save it 117 factories->push_back(factory); 118 return 1; 121 119 } 122 120 … … 127 125 } 128 126 129 unsigned int Licq::TPluginLoader::loadPlugins(const std::string& path, TPluginPrototypeList* pluginList) 127 unsigned int Licq:: 128 TPluginLoader::loadPlugins(const std::string& path, 129 TPluginFactories* factories) 130 130 { 131 assert( pluginList!= NULL);131 assert(factories != NULL); 132 132 133 133 if (path.empty()) … … 144 144 145 145 if (bfs::is_directory(absolute)) 146 return loadPluginsFromDir(absolute, pluginList);146 return loadPluginsFromDir(absolute, factories); 147 147 else 148 return loadPluginsFromFile(absolute, pluginList);148 return loadPluginsFromFile(absolute, factories); 149 149 } 150 catch (const bfs::filesystem_error& e )150 catch (const bfs::filesystem_error& ex) 151 151 { 152 Log->error("Failed to load plugins from \"%s\": %s", path.c_str(), e .what());152 Log->error("Failed to load plugins from \"%s\": %s", path.c_str(), ex.what()); 153 153 } 154 154 -
branches/erijo-dev/licq/src/plugin/pluginloader.h
r4852 r4869 22 22 23 23 #include "licq/interface/log.h" 24 #include "plugin/plugin prototype.h"24 #include "plugin/pluginfactory.h" 25 25 26 #include <boost/shared_ptr.hpp> 27 #include <list> 28 29 // Forward declaration 26 30 namespace boost 27 31 { 28 32 namespace filesystem 29 33 { 30 class path;34 class path; 31 35 } 32 36 } … … 34 38 namespace Licq 35 39 { 40 41 typedef std::list< boost::shared_ptr<TPluginFactory> > TPluginFactories; 36 42 37 43 class TPluginLoader … … 41 47 42 48 /** \brief Load plugins from all files in given directory. 43 \return The number of plugin s loaded.49 \return The number of plugin factories loaded. 44 50 */ 45 unsigned int loadPluginsFromDir(const boost::filesystem::path& dir, TPluginPrototypeList* pluginList); 51 unsigned int loadPluginsFromDir(const boost::filesystem::path& dir, 52 TPluginFactories* factories); 46 53 47 54 /** \brief Load all plugins in given file. 48 \return The number of plugins loaded. 55 \return The number of plugin factories loaded. Since a single file 56 can only contain zero or one factory, this method always returns 0 or 1. 49 57 */ 50 unsigned int loadPluginsFromFile(const boost::filesystem::path& file, TPluginPrototypeList* pluginList); 58 unsigned int loadPluginsFromFile(const boost::filesystem::path& file, 59 TPluginFactories* factories); 51 60 52 61 public: 53 62 /// Creates a new plugin loader. 54 TPluginLoader(ILog* log);63 explicit TPluginLoader(ILog* log); 55 64 56 65 /** \brief Load all plugins from the given path. 57 66 58 67 \param[in] path Path to seach for plugins. 59 \param[out] pluginList Loaded plugins will be added to the back of this list. 60 The ownership of all returned plugins is transfered to the caller. 68 \param[out] factories Loaded factories will be added to the back. 61 69 62 \return The number of plugin s loaded.70 \return The number of plugin factories loaded. 63 71 */ 64 unsigned int loadPlugins(const std::string& path, TPluginPrototypeList* pluginList); 72 unsigned int loadPlugins(const std::string& path, 73 TPluginFactories* factories); 65 74 }; 66 75 -
branches/erijo-dev/licq/src/plugin/pluginrepository.cpp
r4852 r4869 18 18 */ 19 19 20 #include "plugin/pluginmanager.h" 20 #include "plugin/plugin.h" 21 #include "plugin/pluginrepository.h" 21 22 #include "utils/misc.h" 22 23 23 Licq::TPlugin Manager::TPluginManager(ILog* log)24 Licq::TPluginRepository::TPluginRepository(ILog* log) 24 25 : Log(log), PluginLoader(log), NextPluginId(1) 25 26 { … … 27 28 } 28 29 29 Licq::TPlugin Manager::~TPluginManager()30 Licq::TPluginRepository::~TPluginRepository() 30 31 { 31 std::for_each(Plugin PrototypeList.begin(), PluginPrototypeList.end(), ObjectDeleter());32 std::for_each(PluginCache.begin(), PluginCache.end(), ObjectDeleter()); 32 33 } 33 34 34 void Licq::TPlugin Manager::addPluginSearchPath(const std::string& path)35 void Licq::TPluginRepository::addSearchPath(const std::string& path) 35 36 { 36 unsigned int count = PluginLoader.loadPlugins(path, &PluginPrototypeList);37 Log->debug("Loaded %d plugin%s from '%s'", count, (count == 1 ? "" : "s"), path.c_str()); 37 PluginPaths.push_back(path); 38 } 38 39 39 // TODO Remove duplicate plugins (same name, remove older IntVersion) 40 void Licq::TPluginRepository::rebuildCache() 41 { 42 // Remove all old factories 43 PluginFactories.clear(); 40 44 41 TPluginPrototypeList::iterator it = PluginPrototypeList.begin();42 for (; it != PluginPrototypeList.end(); ++it)45 for (TStringList::const_iterator path = PluginPaths.begin(); 46 path != PluginPaths.end(); ++path) 43 47 { 44 Log->info("Plugin %s version %s.", 45 (*it)->getPluginInformation().Name.c_str(), 46 (*it)->getPluginInformation().Version.c_str()); 47 Log->info(" %s", (*it)->getPluginInformation().Description.c_str()); 48 const unsigned int count = PluginLoader.loadPlugins(*path, &PluginFactories); 49 Log->debug("Loaded %u plugin%s from %s", 50 count, (count == 1 ? "" : "s"), path->c_str()); 51 } 52 53 // Clear the cache 54 std::for_each(PluginCache.begin(), PluginCache.end(), ObjectDeleter()); 55 56 for (TPluginFactories::const_iterator factory = PluginFactories.begin(); 57 factory != PluginFactories.end(); ++factory) 58 { 59 const unsigned int count = (*factory)->getPluginCount(); 60 for (unsigned int index = 0; index < count; ++index) 61 { 62 TCacheEntry* entry = new TCacheEntry; 63 entry->LibraryFilename = (*factory)->getLibraryFilename(); 64 entry->Factory = *factory; 65 entry->Index = index; 66 entry->Information = (*factory)->getPluginInformation(index); 67 68 // Check for duplicate plugins 69 TPluginCache::iterator cache = PluginCache.find(entry->Information.Name); 70 if (cache != PluginCache.end()) 71 { 72 // Keep the one with the highest IntVersion, or if equal, the first loaded. 73 if (entry->Information.IntVersion <= cache->second->Information.IntVersion) 74 { 75 delete entry; 76 continue; 77 } 78 else 79 { 80 delete cache->second; 81 PluginCache.erase(cache); 82 } 83 } 84 85 PluginCache[entry->Information.Name] = entry; 86 } 48 87 } 49 88 } 89 90 void Licq::TPluginRepository::unloadUnusedPlugins() 91 { 92 PluginFactories.clear(); 93 } 94 95 void Licq::TPluginRepository:: 96 getAvailablePlugins(std::list<TPluginInformation>* pluginInformation) 97 { 98 for (TPluginCache::const_iterator cache = PluginCache.begin(); 99 cache != PluginCache.end(); ++cache) 100 { 101 pluginInformation->push_back(cache->second->Information); 102 } 103 } 104 105 Licq::IPlugin* Licq::TPluginRepository::createPlugin(const std::string& name) 106 { 107 TPluginCache::const_iterator cache = PluginCache.find(name); 108 if (cache == PluginCache.end()) 109 { 110 Log->error("No such plugin %s", name.c_str()); 111 return NULL; 112 } 113 114 boost::shared_ptr<IPluginFactory> factory = cache->second->Factory.lock(); 115 if (!factory) 116 { 117 // Need to reload the library 118 TPluginFactories factories; 119 if (PluginLoader.loadPlugins(cache->second->LibraryFilename, &factories) == 0) 120 { 121 Log->error("Failed to reopen plugin library %s", 122 cache->second->LibraryFilename.c_str()); 123 return NULL; 124 } 125 126 assert(factories.size() == 1); 127 factory = factories.front(); 128 } 129 130 assert(factory); 131 IPlugin* plugin = factory->createPlugin(cache->second->Index, NextPluginId, Log); 132 133 if (plugin != NULL) 134 { 135 NextPluginId += 1; 136 return new TPlugin(plugin, factory); 137 } 138 139 return NULL; 140 } -
branches/erijo-dev/licq/src/plugin/pluginrepository.h
r4852 r4869 18 18 */ 19 19 20 #ifndef LICQ_TPLUGIN MANAGER_H21 #define LICQ_TPLUGIN MANAGER_H20 #ifndef LICQ_TPLUGINREPOSITORY_H 21 #define LICQ_TPLUGINREPOSITORY_H 22 22 23 23 #include "licq/interface/log.h" 24 #include "licq/interface/plugin.h" 25 #include "licq/interface/plugininformation.h" 26 27 #include "plugin/pluginfactory.h" 24 28 #include "plugin/pluginloader.h" 25 #include "plugin/pluginprototype.h"26 29 27 #include <boost/noncopyable.hpp> 30 #include <boost/weak_ptr.hpp> 31 #include <map> 32 #include <string> 28 33 29 34 namespace Licq 30 35 { 31 36 32 class TPlugin Manager : boost::noncopyable37 class TPluginRepository 33 38 { 34 39 private: 35 40 ILog* Log; 36 41 42 /// A list of paths to search for plugins. 43 TStringList PluginPaths; 44 37 45 TPluginLoader PluginLoader; 38 TPluginPrototypeList PluginPrototypeList; 46 47 /// By keeping factories in this list, their dynamic library is keept in memory. 48 TPluginFactories PluginFactories; 49 50 struct TCacheEntry 51 { 52 std::string LibraryFilename; 53 boost::weak_ptr<IPluginFactory> Factory; 54 unsigned int Index; 55 TPluginInformation Information; 56 }; 57 58 typedef std::map<std::string, TCacheEntry*> TPluginCache; 59 TPluginCache PluginCache; 39 60 40 61 TPluginId NextPluginId; 41 62 42 63 public: 43 TPluginManager(ILog* log);44 ~TPlugin Manager();64 explicit TPluginRepository(ILog* log); 65 ~TPluginRepository(); 45 66 46 void addPluginSearchPath(const std::string& path); 67 void addSearchPath(const std::string& path); 68 void rebuildCache(); 69 70 void unloadUnusedPlugins(); 71 72 void getAvailablePlugins(std::list<TPluginInformation>* pluginInformation); 73 74 IPlugin* createPlugin(const std::string& name); 47 75 }; 48 76 -
branches/erijo-dev/licq/src/plugin/tests/CMakeLists.txt
r4852 r4869 1 1 set(licqplugintest_SRCS 2 2 main.cpp 3 pluginfactory proxytest.cpp3 pluginfactorytest.cpp 4 4 ) 5 5 -
branches/erijo-dev/licq/src/plugin/tests/pluginfactorytest.cpp
r4852 r4869 21 21 22 22 #include "licq/interface/pluginfactory.h" 23 #include "plugin/pluginfactoryproxy.h" 23 #include "plugin/pluginfactory.h" 24 25 class TPluginFactory : public Licq::IPluginFactory 26 { 27 public: 28 virtual unsigned int getPluginCount() const { return 0; } 29 virtual Licq::TPluginInformation getPluginInformation(unsigned int) const 30 { 31 return Licq::TPluginInformation(); 32 } 33 34 virtual Licq::IPlugin* createPlugin(unsigned int, Licq::TPluginId, Licq::ILog*) 35 { 36 return NULL; 37 } 38 }; 24 39 25 40 static unsigned int DestructorCount = 0; 41 static TPluginFactory PluginFactory; 42 static Licq::IPluginFactory* DestroyedPluginFactory = NULL; 26 43 27 void licqDestroyPluginFactory(Licq::IPluginFactory*)44 Licq::IPluginFactory* licqCreatePluginFactory() 28 45 { 46 return &PluginFactory; 47 } 48 49 void licqDestroyPluginFactory(Licq::IPluginFactory* factory) 50 { 51 DestroyedPluginFactory = factory; 29 52 DestructorCount += 1; 30 53 } 31 54 32 BOOST_AUTO_UNIT_TEST( tc_pluginfactory proxy)55 BOOST_AUTO_UNIT_TEST( tc_pluginfactory ) 33 56 { 57 BOOST_CHECK_EQUAL(DestroyedPluginFactory, (Licq::IPluginFactory*)NULL); 34 58 BOOST_CHECK_EQUAL(DestructorCount, 0u); 35 59 { 36 Licq::TPluginFactoryProxy proxy(NULL, NULL, &licqDestroyPluginFactory); 37 BOOST_CHECK_EQUAL(proxy.getFactory(), (Licq::IPluginFactory*)NULL); 60 Licq::TPluginFactory factory(NULL, 61 &licqCreatePluginFactory, 62 &licqDestroyPluginFactory); 38 63 } 39 64 BOOST_CHECK_EQUAL(DestructorCount, 1u); 65 BOOST_CHECK_EQUAL(&PluginFactory, DestroyedPluginFactory); 40 66 }
