00001 #include "OBTPluginLoader.h"
00002 #include "OBTPluginInformation.h"
00003 #include "OBTOldPlugin.h"
00004 #include "OBTBasicPlugin.h"
00005 #include "OBT_ASSERT.h"
00006
00007 #include <sys/stat.h>
00008 #ifndef _MSC_VER
00009 #include <dlfcn.h>
00010 #endif
00011
00012 namespace OBT
00013 {
00014
00015
00016 struct PluginImpl
00017 {
00018 friend class PluginLoaderImpl ;
00019 PluginImpl( const std::string& path,
00020 OBT_PLUGIN_HANDLE handle,
00021 PluginInterface* impl,
00022 bool isOldPlugin )
00023 : _path( path ), _handle( handle ), _impl( impl ), _isOldPlugin( isOldPlugin )
00024 {
00025 }
00026 virtual ~PluginImpl() {}
00027 std::string _path ;
00028 OBT_PLUGIN_HANDLE _handle ;
00029 PluginInterface* _impl ;
00030 bool _isOldPlugin ;
00031 } ;
00032 }
00033 using namespace OBT ;
00034
00035
00036
00037
00038
00039 PluginLoaderImpl::~PluginLoaderImpl()
00040 {
00041 for( PluginsList::reverse_iterator it = _plugins.rbegin() ;
00042 it != _plugins.rend() ;
00043 ++it )
00044 {
00045 ( *it )->_impl->finish() ;
00046 unloadAndCheckForPluginDeletion( *it ) ;
00047 delete *it ;
00048 *it = 0 ;
00049 }
00050 }
00051
00052
00053
00054
00055 void PluginLoaderImpl::unloadAndCheckForPluginDeletion( PluginImpl* pluginImpl )
00056 {
00057 unloadCall( pluginImpl->_handle ) ;
00058 if( pluginImpl->_isOldPlugin )
00059 {
00060
00061
00062 delete pluginImpl->_impl ;
00063 pluginImpl->_impl = 0 ;
00064 }
00065 }
00066
00067
00068
00069 template< typename FuncType >
00070 FuncType PluginLoaderImpl::getFunc( OBT_PLUGIN_HANDLE handle, const char* funcName ) const
00071 {
00072 void* functionPointer = 0 ;
00073 if( 0 != handle )
00074 {
00075 #ifdef _MSC_VER
00076 functionPointer = GetProcAddress( handle, funcName ) ;
00077 #else
00078 dlerror() ;
00079 functionPointer = dlsym( handle, funcName ) ;
00080 #endif
00081 }
00082 return reinterpret_cast< FuncType >( functionPointer ) ;
00083 }
00084
00085
00086
00087 std::string PluginLoaderImpl::getPath( const std::string& path, const std::string& name ) const
00088 {
00089 std::string realPath( path ) ;
00090 if( !name.empty() )
00091 {
00092 #if defined _MSC_VER
00093 # if defined NDEBUG
00094 std::string extension( ".dll" ) ;
00095 std::string subPath( "/release/" ) ;
00096 # else
00097 std::string extension( "_d.dll" ) ;
00098 std::string subPath( "/debug/" ) ;
00099 # endif
00100
00101 realPath = path + "/" + name + extension ;
00102 struct stat buffer ;
00103 if( stat( realPath.c_str(), &buffer ) )
00104 {
00105 realPath = path + subPath + name + extension ;
00106 }
00107 #else
00108 // try in realPath
00109 realPath = path + ( path.empty() ? "lib" : "/lib" ) + name + ".so" ;
00110 #endif
00111 }
00112 return realPath ;
00113 }
00114
00115
00116
00117 OBT_PLUGIN_HANDLE PluginLoaderImpl::loadCall( const char* path ) const
00118 {
00119 #if defined _MSC_VER
00120 return LoadLibrary( path ) ;
00121 #else
00122 dlerror() ;
00123 return dlopen( path, RTLD_LAZY | RTLD_GLOBAL ) ;
00124 #endif
00125 }
00126
00127
00128
00129 std::string PluginLoaderImpl::errorMsgCall() const
00130 {
00131 std::string msg ;
00132 #if !defined _MSC_VER
00133
00134 char* error = dlerror() ;
00135 if( error )
00136 {
00137 msg = "Error message from plugin: ";
00138 msg += error ;
00139
00140 }
00141 #endif
00142 return msg ;
00143 }
00144
00145
00146
00147 void PluginLoaderImpl::unloadCall( OBT_PLUGIN_HANDLE handle ) const
00148 {
00149 if( 0 != handle )
00150 {
00151 #ifdef _MSC_VER
00152 FreeLibrary( handle ) ;
00153 #else
00154 dlerror() ;
00155 dlclose( handle ) ;
00156 #endif
00157 }
00158 }
00159
00160
00161
00162 PluginLoaderImpl::PluginsList::iterator PluginLoaderImpl::find( PluginInterface* plugin )
00163 {
00164 PluginsList::iterator it = _plugins.begin() ;
00165 while( it != _plugins.end() && ( *it )->_impl != plugin )
00166 {
00167 ++it ;
00168 }
00169 return it ;
00170 }
00171
00172
00173
00174 PluginLoaderImpl::PluginsList::iterator PluginLoaderImpl::find( const std::string& path )
00175 {
00176 PluginsList::iterator it = _plugins.begin() ;
00177 while( it != _plugins.end() && ( *it )->_path != path )
00178 {
00179 ++it ;
00180 }
00181 return it ;
00182 }
00183
00184
00185
00186 PluginInterface* PluginLoaderImpl::load( const std::string& path, const std::string& name, const std::string& prm )
00187 {
00188
00189 PluginInterface* pluginInterface = 0 ;
00190
00191 std::string realPath( getPath( path, name ) ) ;
00192
00193 bool notLoaded = ( find( realPath ) == _plugins.end() ) ;
00194
00195 OBT_PLUGIN_HANDLE pluginHandle = notLoaded ? loadCall( realPath.c_str() ) : 0 ;
00196
00197 bool isOldPlugin = false ;
00198
00199 if( 0 != pluginHandle )
00200 {
00201
00202 std::ostringstream msg ;
00203
00204
00205 PluginGetFunc pluginGetFunc = getFunc< PluginGetFunc >( pluginHandle, "get_OBT_PluginInterface" ) ;
00206
00207 pluginInterface = ( 0 != pluginGetFunc ) ? pluginGetFunc() : 0 ;
00208 if( 0 == pluginInterface )
00209 {
00210
00211
00212 TRACE_INFO( "The plugin \"" << realPath
00213 << "\" does not use a OBT::PluginInterface object "
00214 << "to describe its entry points, build one for compatibility " ) ;
00215
00216
00217 GetInformationFunc getInfoFunc = getFunc< GetInformationFunc >( pluginHandle, "getPluginInformation" ) ;
00218 InitFunc initFunc = getFunc< InitFunc >( pluginHandle, "initPlugin" ) ;
00219 FinishFunc finishFunc = getFunc< FinishFunc >( pluginHandle, "finishPlugin" ) ;
00220
00221 if( 0 != getInfoFunc && 0 != initFunc && 0 != finishFunc )
00222 {
00223 pluginInterface = new OldPlugin( getInfoFunc, initFunc, finishFunc ) ;
00224 isOldPlugin = true ;
00225 }
00226 else
00227 {
00228 if( 0 == getInfoFunc ) msg << "The plugin \"" << realPath << "\" misses the \"getPluginInformation\" function\n" ;
00229 if( 0 == initFunc ) msg << "The plugin \"" << realPath << "\" misses the \"initPlugin\" function\n" ;
00230 if( 0 == finishFunc ) msg << "The plugin \"" << realPath << "\" misses the \"finishPlugin\" function\n" ;
00231 }
00232 }
00233
00234 if( 0 == pluginInterface )
00235 {
00236
00237
00238 if( msg.str().empty() )
00239 {
00240 msg << "Unable to get the plugin object of \"" << realPath << "\"" ;
00241 }
00242 }
00243 else
00244 {
00245 if( pluginInterface->init( prm ) )
00246 {
00247
00248 PluginImpl* impl = new PluginImpl( path, pluginHandle, pluginInterface, isOldPlugin ) ;
00249 _plugins.push_back( impl ) ;
00250 }
00251 else
00252 {
00253 msg << "Initialization of the plugin object of \"" << realPath << "\" failed" ;
00254 pluginInterface->finish() ;
00255 pluginInterface = 0 ;
00256
00257
00258 unloadCall( pluginHandle ) ;
00259 }
00260 }
00261
00262 if( 0 == pluginInterface )
00263 {
00264 TRACE_ERROR( msg.str() ) ;
00265 }
00266 }
00267 else
00268 {
00269
00270
00271 TRACE_ERROR( "Unable to load plugin: \"" + realPath + "\" " + errorMsgCall() ) ;
00272 }
00273 return pluginInterface ;
00274 }
00275
00276
00277
00278 bool PluginLoaderImpl::unload( PluginInterface* plugin )
00279 {
00280 bool ok = false ;
00281 PluginsList::iterator it = find( plugin ) ;
00282 if( it != _plugins.end() )
00283 {
00284 ok = ( *it )->_impl->finish() ;
00285 unloadAndCheckForPluginDeletion( *it ) ;
00286 delete *it ;
00287 _plugins.erase( it ) ;
00288 }
00289 else
00290 {
00291 TRACE_ERROR( "The plugin \"" << plugin << "\" is not loaded" ) ;
00292 }
00293 return ok ;
00294 }