Commit 3cc24f26 authored by Emmanuel Milou's avatar Emmanuel Milou

Add a library manager + exception handling;

Remove namespace
parent 71e71378
......@@ -5,5 +5,6 @@ noinst_LTLIBRARIES = libplugin.la
SUBDIRS=test
libplugin_la_SOURCES = \
pluginmanager.cpp
pluginmanager.cpp \
librarymanager.cpp
#include "librarymanager.h"
LibraryManager::LibraryManager (const std::string &filename)
: _filename(filename), _handlePtr(NULL)
{
_handlePtr = loadLibrary (filename);
}
LibraryManager::~LibraryManager (void)
{
unloadLibrary ();
}
LibraryManager::LibraryHandle LibraryManager::loadLibrary (const std::string &filename)
{
LibraryHandle pluginHandlePtr = NULL;
const char *error;
_debug("Loading dynamic library %s\n", filename.c_str());
/* Load the library */
pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY );
if( !pluginHandlePtr ) {
error = dlerror();
_debug("Error while opening plug-in: %s\n", error);
return NULL;
}
dlerror();
return pluginHandlePtr;
}
int LibraryManager::unloadLibrary ()
{
if (_handlePtr == NULL)
return 1;
_debug("Unloading dynamic library ...\n");
dlclose( _handlePtr );
if (dlerror())
{
_debug("Error unloading the library : %s\n...", dlerror());
return 1;
}
return 0;
}
int LibraryManager::resolveSymbol (const std::string &symbol, SymbolHandle *symbolPtr)
{
SymbolHandle sy = 0;
if (_handlePtr){
try {
sy = dlsym(_handlePtr, symbol.c_str());
if(sy != NULL) {
*symbolPtr = sy;
return 0;
}
}
catch (...) {}
throw LibraryManagerException ( _filename, symbol, LibraryManagerException::symbolNotFound);
}
else
return 1;
}
/************************************************************************************************/
LibraryManagerException::LibraryManagerException (const std::string &libraryName, const std::string &details, Reason reason) :
_reason (reason), _details (""), std::runtime_error ("")
{
if (_reason == loadingFailed)
_details = "Error when loading " + libraryName + "\n" + details;
else
_details = "Error when resolving symbol " + details + " in " + libraryName;
}
const char* LibraryManagerException::what () const throw()
{
return _details.c_str();
}
#ifndef LIBRARY_MANAGER_H
#define LIBRARY_MANAGER_H
#include "dlfcn.h"
#include <stdexcept>
#include "global.h"
class LibraryManager {
public:
typedef void* LibraryHandle;
typedef void* SymbolHandle;
LibraryManager (const std::string &filename);
~LibraryManager (void);
int resolveSymbol (const std::string &symbol, SymbolHandle *ptr);
int unloadLibrary (void);
protected:
LibraryHandle loadLibrary (const std::string &filename);
private:
std::string _filename;
LibraryHandle _handlePtr;
};
class LibraryManagerException : public std::runtime_error {
public:
typedef enum Reason {
loadingFailed = 0,
symbolNotFound
}Reason;
LibraryManagerException (const std::string &libraryName, const std::string &details, Reason reason);
~LibraryManagerException (void) throw() {}
inline Reason getReason (void) { return _reason; }
const char* what () const throw();
private:
Reason _reason;
std::string _details;
};
#endif // LIBRARY_MANAGER_H
......@@ -4,40 +4,39 @@
#include <string>
#include "global.h"
#include "pluginmanager.h"
/*
* @file plugin.h
* @brief Define a plugin object
*/
namespace sflphone {
class Plugin {
class Plugin {
public:
Plugin( const std::string &name ){
_name = name;
}
public:
Plugin( const std::string &name ){
_name = name;
}
virtual ~Plugin() {}
virtual ~Plugin() {}
inline std::string getPluginName (void) { return _name; }
inline std::string getPluginName (void) { return _name; }
/**
* Return the minimal core version required so that the plugin could work
* @return int The version required
*/
virtual int initFunc (PluginInfo **info) = 0;
/**
* Return the minimal core version required so that the plugin could work
* @return int The version required
*/
virtual int initFunc (int i) = 0;
private:
Plugin &operator =(const Plugin &plugin);
private:
Plugin &operator =(const Plugin &plugin);
std::string _name;
};
std::string _name;
};
}
typedef ::sflphone::Plugin* createFunc (void);
typedef Plugin* createFunc (void);
typedef void destroyFunc (::sflphone::Plugin*);
typedef void destroyFunc (Plugin*);
#endif //PLUGIN_H
......@@ -3,10 +3,10 @@
#include "pluginmanager.h"
::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0;
PluginManager* PluginManager::_instance = 0;
::sflphone::PluginManager*
::sflphone::PluginManager::instance()
PluginManager*
PluginManager::instance()
{
if(!_instance){
return new PluginManager();
......@@ -14,28 +14,26 @@
return _instance;
}
::sflphone::PluginManager::PluginManager()
:_loadedPlugins()
PluginManager::PluginManager()
:_loadedPlugins()
{
_instance = this;
}
::sflphone::PluginManager::~PluginManager()
PluginManager::~PluginManager()
{
_instance = 0;
}
int
::sflphone::PluginManager::loadPlugins (const std::string &path)
PluginManager::loadPlugins (const std::string &path)
{
std::string pluginDir, current;
::sflphone::Plugin *plugin;
DIR *dir;
dirent *dirStruct;
int result=0;
void *handle;
createFunc* createPlugin;
LibraryManager *library;
Plugin *plugin;
const std::string pDir = "..";
const std::string cDir = ".";
......@@ -52,22 +50,25 @@
current = dirStruct->d_name;
/* Test if the current item is not the parent or the current directory */
if( current != pDir && current != cDir ){
handle = loadDynamicLibrary( pluginDir + current );
if(instanciatePlugin (handle, &plugin) != 0)
/* Load the dynamic library */
library = loadDynamicLibrary( pluginDir + current );
/* Instanciate the plugin object */
if(instanciatePlugin (library, &plugin) != 0)
{
_debug("Error instanciating the plugin ...\n");
return 1;
}
/*
if(registerPlugin (handle, interface) != 0)
/* Regitering the current plugin */
if(registerPlugin (plugin, library) != 0)
{
_debug("Error registering the plugin ...\n");
return 1;
}*/
}
}
}
}
}
else
return 1;
......@@ -78,84 +79,134 @@
return 0;
}
::sflphone::Plugin*
::sflphone::PluginManager::isPluginLoaded (const std::string &name)
int
PluginManager::unloadPlugins (void)
{
if(_loadedPlugins.empty()) return NULL;
PluginInfo *info;
if(_loadedPlugins.empty()) return 0;
/* Use an iterator on the loaded plugins map */
pluginMap::iterator iter;
iter = _loadedPlugins.begin();
while( iter != _loadedPlugins.end() ) {
if ( iter->first == name ) {
/* Return the associated plugin */
return iter->second;
info = iter->second;
if (deletePlugin (info) != 0)
{
_debug("Error deleting the plugin ... \n");
return 1;
}
unloadDynamicLibrary (info->_libraryPtr);
if (unregisterPlugin (info) != 0)
{
_debug("Error unregistering the plugin ... \n");
return 1;
}
iter++;
}
/* If we are here, it means that the plugin we were looking for has not been loaded */
return NULL;
return 0;
}
void*
::sflphone::PluginManager::loadDynamicLibrary (const std::string& filename)
bool
PluginManager::isPluginLoaded (const std::string &name)
{
if(_loadedPlugins.empty()) return false;
/* Use an iterator on the loaded plugins map */
pluginMap::iterator iter;
iter = _loadedPlugins.find (name);
void *pluginHandlePtr = NULL;
const char *error;
/* Returns map::end if the specified key has not been found */
if(iter==_loadedPlugins.end())
return false;
_debug("Loading dynamic library %s\n", filename.c_str());
/* Returns the plugin pointer */
return true;
}
/* Load the library */
pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY );
if( !pluginHandlePtr ) {
error = dlerror();
_debug("Error while opening plug-in: %s\n", error);
return NULL;
}
dlerror();
return pluginHandlePtr;
LibraryManager*
PluginManager::loadDynamicLibrary (const std::string& filename)
{
/* Load the library through the library manager */
return new LibraryManager (filename);
}
int
PluginManager::unloadDynamicLibrary (LibraryManager *libraryPtr)
{
_debug("Unloading dynamic library ...\n");
/* Close it */
return libraryPtr->unloadLibrary ();
}
int
::sflphone::PluginManager::instanciatePlugin (void *handlePtr, ::sflphone::Plugin **plugin)
PluginManager::instanciatePlugin (LibraryManager *libraryPtr, Plugin **plugin)
{
createFunc *createPlugin;
LibraryManager::SymbolHandle symbol;
createPlugin = (createFunc*)dlsym(handlePtr, "create");
if( dlerror() )
{
_debug("Error creating the plugin: %s\n", dlerror());
if (libraryPtr->resolveSymbol ("createPlugin", &symbol) != 0)
return 1;
}
createPlugin = (createFunc*)symbol;
*plugin = createPlugin();
return 0;
}
int
::sflphone::PluginManager::registerPlugin (void *handlePtr, Plugin *plugin)
PluginManager::deletePlugin (PluginInfo *plugin)
{
std::string name;
destroyFunc *destroyPlugin;
LibraryManager::SymbolHandle symbol;
if( !(handlePtr && plugin!=0) )
if (plugin->_libraryPtr->resolveSymbol ("destroyPlugin", &symbol) != 0)
return 1;
name = plugin->getPluginName();
/* Add the data in the loaded plugin map */
_loadedPlugins[ name ] = plugin;
destroyPlugin = (destroyFunc*)symbol;
/* Call it */
destroyPlugin (plugin->_plugin);
return 0;
}
int
::sflphone::PluginManager::unloadDynamicLibrary (void * pluginHandlePtr)
PluginManager::registerPlugin (Plugin *plugin, LibraryManager *library)
{
dlclose( pluginHandlePtr );
dlerror();
std::string key;
PluginInfo *p_info;
if( plugin==0 )
return 1;
p_info = new PluginInfo();
/* Retrieve information from the plugin */
plugin->initFunc (&p_info);
key = p_info->_name;
//p_info->_plugin = plugin;
p_info->_libraryPtr = library;
/* Add the data in the loaded plugin map */
_loadedPlugins[ key ] = p_info;
return 0;
}
int
PluginManager::unregisterPlugin (PluginInfo *plugin)
{
pluginMap::iterator iter;
std::string key;
key = plugin->_name;
if (!isPluginLoaded(key))
return 1;
iter = _loadedPlugins.find (key);
_loadedPlugins.erase (iter);
return 0;
}
......@@ -6,19 +6,27 @@
* @brief Base class of the plugin manager
*/
#include "plugin.h"
#include "librarymanager.h"
#include "global.h"
#include <map>
#include <string>
#include <vector>
namespace sflphone {
class PluginManager {
class Plugin;
typedef struct PluginInfo {
std::string _name;
LibraryManager *_libraryPtr;
Plugin *_plugin;
int _major_version;
int _minor_version;
} PluginInfo;
public:
#include "plugin.h"
class PluginManager {
public:
/**
* Destructor
*/
......@@ -34,46 +42,51 @@ namespace sflphone {
* @param path The absolute path to the directory
* @return int The number of items loaded
*/
int loadPlugins( const std::string &path = "" );
int loadPlugins (const std::string &path = "");
int instanciatePlugin( void *handlePtr, Plugin** plugin );
int unloadPlugins (void);
int instanciatePlugin (LibraryManager* libraryPtr, Plugin** plugin);
/**
* Check if a plugin has been already loaded
* @param name The name of the plugin looked for
* @return Plugin* The pointer on the plugin or NULL if not found
* @return bool The pointer on the plugin or NULL if not found
*/
Plugin* isPluginLoaded( const std::string &name );
bool isPluginLoaded (const std::string &name);
int registerPlugin (void *handle, Plugin *plugin);
int registerPlugin (Plugin *plugin, LibraryManager *library);
int unregisterPlugin (PluginInfo *plugin);
int deletePlugin (PluginInfo *plugin);
/**
* Load a unix dynamic/shared library
* @param filename The path to the dynamic/shared library
* @return void* A pointer on it
* @return LibraryManager* A pointer on the library
*/
void * loadDynamicLibrary( const std::string &filename );
LibraryManager* loadDynamicLibrary (const std::string &filename);
/**
* Unload a unix dynamic/shared library
* @param pluginHandleptr The pointer on the loaded plugin
* @param LibraryManager* The pointer on the loaded library
*/
int unloadDynamicLibrary( void * pluginHandlePtr );
int unloadDynamicLibrary (LibraryManager* libraryPtr);
private:
private:
/**
* Default constructor
*/
PluginManager();
/* Map of plugins associated by their string name */
typedef std::map<std::string, Plugin*> pluginMap;
typedef std::map<std::string, PluginInfo*> pluginMap;
pluginMap _loadedPlugins;
/* The unique static instance */
static PluginManager* _instance;
};
}
};
#endif //PLUGIN_MANAGER_H
#include "../plugin.h"
namespace sflphone {
class PluginTest : public Plugin {
public:
PluginTest( const std::string &name )
:Plugin( name ) {
}
virtual int initFunc (int i)
{
return i;
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
class PluginTest : public Plugin {
public:
PluginTest( const std::string &name )
:Plugin( name ) {
}
};
}
virtual int initFunc (PluginInfo **info) {
(*info)->_plugin = this;
(*info)->_major_version = MAJOR_VERSION;
(*info)->_minor_version = MINOR_VERSION;
(*info)->_name = getPluginName();
return 0;
}
};
extern "C" ::sflphone::Plugin* create (void){
return new ::sflphone::PluginTest("mytest");
extern "C" Plugin* createPlugin (void){
return new PluginTest("mytest");
}
extern "C" void destroy (::sflphone::Plugin *p){
extern "C" void destroyPlugin (Plugin *p){
delete p;
}
......@@ -26,60 +26,70 @@
using std::cout;
using std::endl;
#define PLUGIN_TEST_DIR "/usr/lib/sflphone/plugins/libplugintest.so"
#define PLUGIN_TEST_NAME "mytest"
#define PLUGIN_TEST_DIR "/usr/lib/sflphone/plugins/"
#define PLUGIN_TEST_DESC "mytest"
#define PLUGIN_TEST_NAME "/usr/lib/sflphone/plugins/libplugintest.so"
void PluginManagerTest::setUp(){
// Instanciate the plugin manager singleton
_pm = ::sflphone::PluginManager::instance();
handlePtr = NULL;
_pm = PluginManager::instance();
library = 0;
plugin = 0;
}
void PluginManagerTest::testLoadDynamicLibrary(){
CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_DIR) != NULL);
CPPUNIT_ASSERT(_pm->loadDynamicLibrary(PLUGIN_TEST_NAME) != NULL);
}
void PluginManagerTest::testUnloadDynamicLibrary(){
handlePtr = _pm->loadDynamicLibrary(PLUGIN_TEST_DIR);
CPPUNIT_ASSERT(handlePtr != 0);