OpenWalnut  1.4.0
WModuleLoader.cpp
00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <set>
00026 #include <string>
00027 #include <vector>
00028 
00029 #include <boost/regex.hpp>
00030 
00031 #include "../common/WIOTools.h"
00032 #include "../common/WPathHelper.h"
00033 #include "../common/WSharedLib.h"
00034 
00035 #include "WModuleLoader.h"
00036 
00037 WModuleLoader::WModuleLoader( )
00038 {
00039     // initialize members
00040 }
00041 
00042 WModuleLoader::~WModuleLoader()
00043 {
00044     // cleanup all the handles
00045     m_libs.clear();
00046 }
00047 
00048 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket,
00049                           boost::filesystem::path dir, unsigned int level )
00050 {
00051     for( boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator( dir );
00052          i != boost::filesystem::directory_iterator(); ++i )
00053     {
00054         // all modules need to begin with this
00055         std::string stem = i->path().stem().string();
00056 
00057         // we want to strip the search directory from the path
00058         std::string relPath = i->path().string();
00059         relPath.erase( 0, dir.string().length() + 1 ); // NOTE: +1 because we want to remove the "/" too
00060 
00061         // is it a lib? Use a regular expression to check this
00062         // NOTE:: the double \\ is needed to escape the escape char (to interpret the "dot" as dot and not as "any char".
00063         #ifdef __WIN32__
00064             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() +"$" );
00065         #elif __APPLE__
00066             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\.[0-9]+\\.[0-9]+\\.[0-9]+\\" + WSharedLib::getSystemSuffix() + "$" );
00067         #else
00068             static const boost::regex CheckLibMMP( "^(lib)?(.*)\\" + WSharedLib::getSystemSuffix() + "\\.[0-9]+\\.[0-9]+\\.[0-9]+$" );
00069         #endif
00070         // this will contain the filename afterwards
00071         boost::smatch matches;
00072         std::string fn = i->path().filename().string();
00073         bool matchLibName = boost::regex_match( fn, matches, CheckLibMMP );
00074         std::string libBaseName = matchLibName ? std::string( matches[2] ) : "";
00075 
00076         if( !boost::filesystem::is_directory( *i ) &&
00077             matchLibName &&
00078             ( stem.compare( 0, getModulePrefix().length(), getModulePrefix() ) == 0 )
00079           )
00080         {
00081             try
00082             {
00083                 // load lib
00084                 boost::shared_ptr< WSharedLib > l( new WSharedLib( i->path() ) );
00085 
00086                 bool isLoadableModule = false;
00087                 bool isLoadableArbitrary = false;
00088 
00089                 // be nice. Do not fail if the module symbol does not exist
00090                 if( l->existsFunction( W_LOADABLE_MODULE_SYMBOL ) )
00091                 {
00092                     // get instantiation function
00093                     W_LOADABLE_MODULE_SIGNATURE f;
00094                     l->fetchFunction< W_LOADABLE_MODULE_SIGNATURE >( W_LOADABLE_MODULE_SYMBOL, f );
00095 
00096                     isLoadableModule = true;
00097 
00098                     // get the first prototype
00099                     WModuleList m;
00100                     f( m );
00101 
00102                     // could the prototype be created?
00103                     if( m.empty() )
00104                     {
00105                         continue;
00106                     }
00107                     else
00108                     {
00109                         // yes, add it to the list of prototypes
00110                         for( WModuleList::const_iterator iter = m.begin(); iter != m.end(); ++iter )
00111                         {
00112                             // which lib?
00113                             ( *iter )->setLibPath( i->path() );
00114                             // we use the library name (excluding extension and optional lib prefix) as package name
00115                             ( *iter )->setPackageName( libBaseName );
00116                             // resource path
00117                             ( *iter )->setLocalPath( WPathHelper::getModuleResourcePath( i->path().parent_path(), ( *iter )->getPackageName() ) );
00118 
00119                             // add module
00120                             ticket->get().insert( *iter );
00121 
00122                             // we need to keep a reference to the lib
00123                             m_libs.push_back( l );
00124                         }
00125 
00126                         wlog::debug( "Module Loader" ) << "Loaded " << m.size() << " modules from " << relPath;
00127                     }
00128                 }
00129 
00130                 // do the same for the arbitrary register functionality
00131                 // get instantiation function
00132                 if( l->existsFunction( W_LOADABLE_REGISTERARBITRARY_SYMBOL ) )
00133                 {
00134                     isLoadableArbitrary = true;
00135 
00136                     // store this temporarily. This is called later, after OW was completely initialized
00137                     // put together the right path and call function
00138                     m_arbitraryRegisterLibs.push_back(
00139                         PostponedLoad( l, WPathHelper::getModuleResourcePath( i->path().parent_path(), libBaseName ) )
00140                     );
00141                 }
00142                 // lib gets closed if l looses focus
00143 
00144                 if( !isLoadableModule && !isLoadableArbitrary )
00145                 {
00146                     wlog::warn( "Module Loader" ) << "Library does neither contain a module nor another extension.";
00147                 }
00148             }
00149             catch( const WException& e )
00150             {
00151                 WLogger::getLogger()->addLogMessage( "Load failed for module \"" + relPath + "\". " + e.what() + ". Ignoring.",
00152                                                      "Module Loader", LL_ERROR );
00153             }
00154         }
00155         else if( ( level <= 10 ) &&  // this sould be enough to tranverse the typical structure build/release/lib/openwalnut/MODULENAME (5 levels)
00156                  boost::filesystem::is_directory( *i ) )     // this only traverses down one level
00157         {
00158             // if it a dir -> traverse down
00159             load( ticket, *i, level + 1 );
00160         }
00161     }
00162 }
00163 
00164 void WModuleLoader::load( WSharedAssociativeContainer< std::set< boost::shared_ptr< WModule > > >::WriteTicket ticket )
00165 {
00166     std::vector< boost::filesystem::path > allPaths = WPathHelper::getAllModulePaths();
00167 
00168     // go through each of the paths
00169     for( std::vector< boost::filesystem::path >::const_iterator path = allPaths.begin(); path != allPaths.end(); ++path )
00170     {
00171         WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() + "\".", "Module Loader", LL_INFO );
00172 
00173         // does the directory exist?
00174         if( !boost::filesystem::is_directory( *path ) || !boost::filesystem::exists( *path ) )
00175         {
00176             WLogger::getLogger()->addLogMessage( "Searching modules in \"" + ( *path ).string() +
00177                                                  "\" failed. It is not a directory or does not exist." +
00178                                                  " Ignoring.", "Module Loader", LL_WARNING );
00179 
00180             continue;
00181         }
00182 
00183         // directly search the path for libOWmodule_ files
00184         load( ticket, *path );
00185     }
00186 }
00187 
00188 void WModuleLoader::initializeExtensions()
00189 {
00190     typedef std::vector< PostponedLoad > Vec;
00191     for( Vec::const_iterator iter = m_arbitraryRegisterLibs.begin(); iter != m_arbitraryRegisterLibs.end(); ++iter )
00192     {
00193         wlog::debug( "WModuleLoader" ) << "Initializing extensions of \"" << ( *iter ).m_lib->getLibraryName() << "\"";
00194         W_LOADABLE_REGISTERARBITRARY_SIGNATURE arbitraryRegister;
00195         ( *iter ).m_lib->fetchFunction< W_LOADABLE_REGISTERARBITRARY_SIGNATURE >( W_LOADABLE_REGISTERARBITRARY_SYMBOL, arbitraryRegister );
00196         arbitraryRegister( ( *iter ).m_path );
00197     }
00198 }
00199 
00200 std::string WModuleLoader::getModulePrefix()
00201 {
00202     // all module file names need to have this prefix:
00203     return WSharedLib::getSystemPrefix();
00204 }
00205