mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
Add the dynamic loading for the plugin framework; integate unit tests
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
# Global variables
|
||||
src=$(top_srcdir)
|
||||
sflcodecdir=$(libdir)/sflphone/codecs
|
||||
sflplugindir=$(libdir)/sflphone/plugins
|
||||
|
||||
PJSIP_LIBS = -lpjnath-sfl -lpjsua-sfl -lpjsip-sfl -lpjmedia-sfl -lpjsip-simple-sfl -lpjsip-ua-sfl -lpjmedia-codec-sfl -lpjlib-util-sfl -lpj-sfl
|
||||
|
||||
@ -16,5 +17,6 @@ AM_CPPFLAGS = \
|
||||
@SIP_CFLAGS@ \
|
||||
@DBUSCPP_CFLAGS@ \
|
||||
-DCODECS_DIR=\""$(sflcodecdir)"\" \
|
||||
-DPLUGINS_DIR=\""$(sflplugindir)"\" \
|
||||
-DENABLE_TRACE
|
||||
|
||||
|
@ -87,6 +87,7 @@ libsflphone_la_LIBADD = \
|
||||
./audio/libaudio.la \
|
||||
./dbus/libdbus.la \
|
||||
./config/libconfig.la \
|
||||
./plug-in/libplugin.la \
|
||||
$(IAX_LIBS)
|
||||
|
||||
libsflphone_la_SOURCES =
|
||||
|
@ -1,5 +1,8 @@
|
||||
include ../../globals.mak
|
||||
|
||||
noinst_LTLIBRARIES = libplugin.la
|
||||
|
||||
libplugin_la_SOURCES = \
|
||||
pluginmanager.cpp
|
||||
plugin.cpp
|
||||
pluginmanager.cpp \
|
||||
plugin.h
|
||||
|
||||
|
@ -1,26 +1,27 @@
|
||||
#include "plugin.h"
|
||||
|
||||
Plugin::Plugin( const std::string &filename )
|
||||
::sflphone::Plugin::Plugin( const std::string &filename UNUSED )
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
}
|
||||
|
||||
Plugin::Plugin( const Plugin &plugin )
|
||||
::sflphone::Plugin::Plugin( const Plugin &plugin UNUSED )
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
}
|
||||
|
||||
Plugin::~Plugin()
|
||||
::sflphone::Plugin::~Plugin()
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
}
|
||||
|
||||
int Plugin::getCoreVersion( void )
|
||||
int ::sflphone::Plugin::getCoreVersion( void ) const
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Plugin::registerPlugin( PluginManager & )
|
||||
void ::sflphone::Plugin::registerPlugin( PluginManager & )
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "global.h"
|
||||
|
||||
/*
|
||||
* @file plugin.h
|
||||
* @brief Define a plugin object
|
||||
@ -15,21 +17,21 @@ class PluginManager;
|
||||
class Plugin {
|
||||
|
||||
public:
|
||||
Plugin( const std::string &filename );
|
||||
Plugin( const Plugin &plugin );
|
||||
~Plugin();
|
||||
Plugin( const std::string &name );
|
||||
//Plugin( const Plugin &plugin );
|
||||
virtual ~Plugin() {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Return the minimal core version required so that the plugin could work
|
||||
* @return int The version required
|
||||
*/
|
||||
int getCoreVersion() const;
|
||||
virtual int getCoreVersion() const = 0;
|
||||
|
||||
/**
|
||||
* Register the plugin to the plugin manager
|
||||
*/
|
||||
void registerPlugin( PluginManager & );
|
||||
virtual void registerPlugin( PluginManager & ) = 0;
|
||||
|
||||
private:
|
||||
Plugin &operator =(const Plugin &plugin);
|
||||
|
@ -1,6 +1,98 @@
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include "pluginmanager.h"
|
||||
|
||||
void ::sflphone::PluginManager::loadPlugins( const std::string &path )
|
||||
::sflphone::PluginManager::PluginManager():_loadedPlugins()
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
::sflphone::PluginManager::~PluginManager()
|
||||
{
|
||||
_instance = 0;
|
||||
}
|
||||
|
||||
int ::sflphone::PluginManager::loadPlugins( const std::string &path )
|
||||
{
|
||||
std::string pluginDir, current;
|
||||
::sflphone::Plugin *plugin;
|
||||
DIR *dir;
|
||||
dirent *dirStruct;
|
||||
int result=0;
|
||||
|
||||
const std::string pDir = "..";
|
||||
const std::string cDir = ".";
|
||||
|
||||
/* The directory in which plugins are dropped. Default: /usr/lib/sflphone/plugins/ */
|
||||
( path == "" )? pluginDir = std::string(PLUGINS_DIR).append("/"):pluginDir = path;
|
||||
_debug("Loading plugins from %s...\n", pluginDir.c_str());
|
||||
|
||||
dir = opendir( pluginDir.c_str() );
|
||||
/* Test if the directory exists or is readable */
|
||||
if( dir ){
|
||||
/* Read the directory */
|
||||
while( (dirStruct=readdir(dir)) ){
|
||||
/* Get the name of the current item in the directory */
|
||||
current = dirStruct->d_name;
|
||||
/* Test if the current item is not the parent or the current directory */
|
||||
if( current != pDir && current != cDir ){
|
||||
loadDynamicLibrary( current );
|
||||
result++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Close the directory */
|
||||
closedir( dir );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
::sflphone::Plugin* ::sflphone::PluginManager::isPluginLoaded( const std::string &name )
|
||||
{
|
||||
if(_loadedPlugins.empty()) return NULL;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
|
||||
/* If we are here, it means that the plugin we were looking for has not been loaded */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* ::sflphone::PluginManager::loadDynamicLibrary( const std::string& filename ) {
|
||||
|
||||
void *pluginHandlePtr = NULL;
|
||||
const char *error;
|
||||
|
||||
_debug("Loading dynamic library %s\n", filename.c_str());
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
/* Load the library */
|
||||
pluginHandlePtr = dlopen( filename.c_str(), RTLD_LAZY );
|
||||
if( !pluginHandlePtr ) {
|
||||
error = dlerror();
|
||||
_debug("Error while opening plug-in: %s\n", error);
|
||||
}
|
||||
dlerror();
|
||||
#endif
|
||||
|
||||
return pluginHandlePtr;
|
||||
}
|
||||
|
||||
void ::sflphone::PluginManager::unloadDynamicLibrary( void * pluginHandlePtr ) {
|
||||
|
||||
dlclose( pluginHandlePtr );
|
||||
dlerror();
|
||||
}
|
||||
|
||||
::sflphone::PluginManager* ::sflphone::PluginManager::_instance = 0;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@ -16,17 +17,55 @@ namespace sflphone {
|
||||
class PluginManager {
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
PluginManager();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~PluginManager();
|
||||
|
||||
/**
|
||||
* Returns the unique instance of the plugin manager
|
||||
*/
|
||||
static PluginManager* instance();
|
||||
|
||||
/**
|
||||
* Load all the plugins found in a specific directory
|
||||
* @param path The absolute path to the directory
|
||||
* @return int The number of items loaded
|
||||
*/
|
||||
void loadPlugins( const std::string &path );
|
||||
int loadPlugins( const std::string &path = "" );
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
Plugin* isPluginLoaded( const std::string &name );
|
||||
|
||||
private:
|
||||
/* Map of plugins associated by their string name */
|
||||
typedef std::map<std::string, ::sflphone::Plugin> pluginMap;
|
||||
/**
|
||||
* Load a unix dynamic/shared library
|
||||
* @param filename The path to the dynamic/shared library
|
||||
* @return void* A pointer on it
|
||||
*/
|
||||
void * loadDynamicLibrary( const std::string &filename );
|
||||
|
||||
/**
|
||||
* Unload a unix dynamic/shared library
|
||||
* @param pluginHandleptr The pointer on the loaded plugin
|
||||
*/
|
||||
void unloadDynamicLibrary( void * pluginHandlePtr );
|
||||
|
||||
/* Map of plugins associated by their string name */
|
||||
typedef std::map<std::string, ::sflphone::Plugin*> pluginMap;
|
||||
pluginMap _loadedPlugins;
|
||||
|
||||
/* The unique static instance */
|
||||
static PluginManager* _instance;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
include ../globals.mak
|
||||
|
||||
bin_PROGRAMS = configurationTester
|
||||
bin_PROGRAMS = configurationTester pluginmanagerTester
|
||||
|
||||
OBJECT_FILES= \
|
||||
../src/sflphoned-managerimpl.o \
|
||||
@ -16,6 +16,7 @@ OBJECT_FILES= \
|
||||
../src/sflphoned-iaxaccount.o \
|
||||
../src/sflphoned-eventthread.o \
|
||||
../src/sflphoned-useragent.o \
|
||||
../src/plug-in/pluginmanager.o \
|
||||
../src/sflphoned-samplerateconverter.o
|
||||
|
||||
configurationTester_SOURCES = \
|
||||
@ -23,6 +24,11 @@ configurationTester_SOURCES = \
|
||||
configurationTest.h \
|
||||
TestMain.cpp
|
||||
|
||||
pluginmanagerTester_SOURCES = \
|
||||
pluginmanagerTest.h \
|
||||
pluginmanagerTest.cpp \
|
||||
TestMain.cpp
|
||||
|
||||
configurationTester_LDADD = \
|
||||
../src/libsflphone.la \
|
||||
$(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \
|
||||
@ -36,4 +42,18 @@ configurationTester_LDADD = \
|
||||
@SAMPLERATE_LIBS@ \
|
||||
$(PJSIP_LIBS) \
|
||||
$(OBJECT_FILES)
|
||||
|
||||
|
||||
pluginmanagerTester_LDADD = \
|
||||
../src/libsflphone.la \
|
||||
$(SFLPHONE_LIBS) $(ZEROCONFLIB) $(LIB_DNSSD) $(IAX_LIBS) \
|
||||
@ALSA_LIBS@ \
|
||||
@PULSEAUDIO_LIBS@ \
|
||||
@CPPUNIT_LIBS@ \
|
||||
@CCEXT2_LIBS@ \
|
||||
@CCGNU2_LIBS@ \
|
||||
@CCRTP_LIBS@ \
|
||||
@DBUSCPP_LIBS@ \
|
||||
@SAMPLERATE_LIBS@ \
|
||||
$(PJSIP_LIBS) \
|
||||
$(OBJECT_FILES)
|
||||
|
||||
|
44
test/pluginmanagerTest.cpp
Normal file
44
test/pluginmanagerTest.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "pluginmanagerTest.h"
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
void PluginManagerTest::setUp(){
|
||||
// Instanciate the plugin manager object
|
||||
_pm = new ::sflphone::PluginManager();
|
||||
}
|
||||
|
||||
void PluginManagerTest::testLoadPluginDirectory(){
|
||||
_pm->loadPlugins();
|
||||
}
|
||||
|
||||
void PluginManagerTest::testNonloadedPlugin(){
|
||||
CPPUNIT_ASSERT( _pm->isPluginLoaded("test") == NULL );
|
||||
}
|
||||
|
||||
void PluginManagerTest::tearDown(){
|
||||
// Delete the plugin manager object
|
||||
delete _pm; _pm=NULL;
|
||||
}
|
75
test/pluginmanagerTest.h
Normal file
75
test/pluginmanagerTest.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Savoir-Faire Linux inc.
|
||||
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
// Cppunit import
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
#include <cppunit/TestCaller.h>
|
||||
#include <cppunit/TestCase.h>
|
||||
#include <cppunit/TestSuite.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Application import
|
||||
#include "plug-in/pluginmanager.h"
|
||||
|
||||
/*
|
||||
* @file pluginManagerTest.cpp
|
||||
* @brief Regroups unitary tests related to the plugin manager.
|
||||
*/
|
||||
|
||||
#ifndef _PLUGINMANAGER_TEST_
|
||||
#define _PLUGINMANAGER_TEST_
|
||||
|
||||
class PluginManagerTest : public CppUnit::TestCase {
|
||||
|
||||
/*
|
||||
* Use cppunit library macros to add unit test the factory
|
||||
*/
|
||||
CPPUNIT_TEST_SUITE( PluginManagerTest );
|
||||
CPPUNIT_TEST( testLoadPluginDirectory );
|
||||
CPPUNIT_TEST( testNonloadedPlugin );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
PluginManagerTest() : CppUnit::TestCase("Plugin Manager Tests") {}
|
||||
|
||||
/*
|
||||
* Code factoring - Common resources can be initialized here.
|
||||
* This method is called by unitcpp before each test
|
||||
*/
|
||||
void setUp();
|
||||
|
||||
/*
|
||||
* Code factoring - Common resources can be released here.
|
||||
* This method is called by unitcpp after each test
|
||||
*/
|
||||
inline void tearDown();
|
||||
|
||||
void testLoadPluginDirectory();
|
||||
|
||||
void testNonloadedPlugin();
|
||||
|
||||
private:
|
||||
::sflphone::PluginManager *_pm;
|
||||
};
|
||||
|
||||
/* Register our test module */
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( PluginManagerTest );
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user