OpenWalnut 1.3.1
WModuleFactory.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 <algorithm>
00026 #include <iostream>
00027 #include <set>
00028 #include <string>
00029 #include <typeinfo>
00030 #include <vector>
00031 
00032 #include "../common/WLogger.h"
00033 #include "combiner/WApplyCombiner.h"
00034 #include "exceptions/WPrototypeNotUnique.h"
00035 #include "exceptions/WPrototypeUnknown.h"
00036 #include "WModule.h"
00037 #include "WModuleCombiner.h"
00038 #include "WModuleFactory.h"
00039 
00040 // factory instance as singleton
00041 boost::shared_ptr< WModuleFactory > WModuleFactory::m_instance = boost::shared_ptr< WModuleFactory >();
00042 
00043 WModuleFactory::WModuleFactory():
00044     m_prototypes(),
00045     m_moduleLoader()
00046 {
00047     // initialize members
00048 }
00049 
00050 WModuleFactory::~WModuleFactory()
00051 {
00052     // cleanup
00053 }
00054 
00055 void WModuleFactory::load()
00056 {
00057     // load modules
00058     WLogger::getLogger()->addLogMessage( "Loading Modules", "ModuleFactory", LL_INFO );
00059 
00060     // operation must be exclusive
00061     PrototypeSharedContainerType::WriteTicket l = m_prototypes.getWriteTicket();
00062 
00063     // Load the dynamic modules here:
00064     m_moduleLoader.load( l );
00065 
00066     // initialize every module in the set
00067     std::set< std::string > names;  // helper to find duplicates
00068     PrototypeContainerIteratorType listIter = l->get().begin();
00069     while( listIter != l->get().end() )
00070     {
00071         WLogger::getLogger()->addLogMessage( "Initializing module prototype: \"" + ( *listIter )->getName() + "\"", "ModuleFactory", LL_DEBUG );
00072 
00073         // that should not happen. Names should not occur multiple times since they are unique
00074         if( names.count( ( *listIter )->getName() ) )
00075         {
00076             WLogger::getLogger()->addLogMessage( std::string( "Module \"" + ( *listIter )->getName() +
00077                                                                "\" is not unique. Modules have to have a unique name. Ignoring this module." ),
00078                                                  "ModuleFactory", LL_ERROR );
00079             // we remove the module from the prototype list
00080             l->get().erase( listIter++ );
00081             continue;
00082         }
00083         else
00084         {
00085             names.insert( ( *listIter )->getName() );
00086             initializeModule( ( *listIter ) );
00087             ++listIter;
00088         }
00089     }
00090     WLogger::getLogger()->addLogMessage( "Loading Modules Done", "ModuleFactory", LL_INFO );
00091 }
00092 
00093 bool WModuleFactory::isPrototype( boost::shared_ptr< WModule > module )
00094 {
00095     // for this a read lock is sufficient, gets unlocked if it looses scope
00096     PrototypeSharedContainerType::ReadTicket l = getModuleFactory()->m_prototypes.getReadTicket();
00097     return getModuleFactory()->checkPrototype( module, l );
00098 }
00099 
00100 bool WModuleFactory::checkPrototype( boost::shared_ptr< WModule > module, PrototypeSharedContainerType::ReadTicket ticket )
00101 {
00102     return ( ticket->get().count( module ) != 0 );
00103 }
00104 
00105 boost::shared_ptr< WModule > WModuleFactory::create( boost::shared_ptr< WModule > prototype )
00106 {
00107     wlog::debug( "ModuleFactory" ) << "Creating new instance of prototype \"" << prototype->getName() << "\".";
00108 
00109     // for this a read lock is sufficient, gets unlocked if it looses scope
00110     PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
00111 
00112     // ensure this one is a prototype and nothing else
00113     if( !checkPrototype( prototype, l ) )
00114     {
00115         throw WPrototypeUnknown( std::string( "Could not clone module \"" + prototype->getName() + "\" since it is no prototype." ) );
00116     }
00117 
00118     // explicitly unlock
00119     l.reset();
00120 
00121     // call prototypes factory function
00122     boost::shared_ptr< WModule > clone = boost::shared_ptr< WModule >( prototype->factory() );
00123     clone->setLocalPath( prototype->getLocalPath() );   // prototype and clone have the same local path.
00124     initializeModule( clone );
00125 
00126     return clone;
00127 }
00128 
00129 void WModuleFactory::initializeModule( boost::shared_ptr< WModule > module )
00130 {
00131     module->initialize();
00132 }
00133 
00134 boost::shared_ptr< WModuleFactory > WModuleFactory::getModuleFactory()
00135 {
00136     if( !m_instance )
00137     {
00138         m_instance = boost::shared_ptr< WModuleFactory >( new WModuleFactory() );
00139     }
00140 
00141     return m_instance;
00142 }
00143 
00144 
00145 const boost::shared_ptr< WModule > WModuleFactory::isPrototypeAvailable( std::string name )
00146 {
00147     // for this a read lock is sufficient, gets unlocked if it looses scope
00148     PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
00149 
00150     // find first and only prototype (ensured during load())
00151     boost::shared_ptr< WModule > ret = boost::shared_ptr< WModule >();
00152     for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
00153             ++listIter )
00154     {
00155         if( ( *listIter )->getName() == name )
00156         {
00157             ret = ( *listIter );
00158             break;
00159         }
00160     }
00161 
00162     return ret;
00163 }
00164 
00165 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByName( std::string name )
00166 {
00167     boost::shared_ptr< WModule > ret = isPrototypeAvailable( name );
00168 
00169     // if not found -> throw
00170     if( ret == boost::shared_ptr< WModule >() )
00171     {
00172         throw WPrototypeUnknown( std::string( "Could not find prototype \"" + name + "\"." ) );
00173     }
00174 
00175     return ret;
00176 }
00177 
00178 const boost::shared_ptr< WModule > WModuleFactory::getPrototypeByInstance( boost::shared_ptr< WModule > instance )
00179 {
00180     return getPrototypeByName( instance->getName() );
00181 }
00182 
00183 std::vector< WModule::ConstSPtr > WModuleFactory::getPrototypesByType( MODULE_TYPE type )
00184 {
00185     std::vector< WModule::ConstSPtr > ret;
00186 
00187     // for this a read lock is sufficient, gets unlocked if it looses scope
00188     PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
00189 
00190     // find first and only prototype (ensured during load())
00191     for( std::set< boost::shared_ptr< WModule > >::const_iterator listIter = l->get().begin(); listIter != l->get().end();
00192             ++listIter )
00193     {
00194         if( ( *listIter )->getType() == type )
00195         {
00196             ret.push_back( *listIter );
00197         }
00198     }
00199 
00200     return ret;
00201 }
00202 
00203 WModuleFactory::PrototypeSharedContainerType::ReadTicket WModuleFactory::getPrototypes() const
00204 {
00205     return m_prototypes.getReadTicket();
00206 }
00207 
00208 WCombinerTypes::WCompatiblesList WModuleFactory::getCompatiblePrototypes( boost::shared_ptr< WModule > module )
00209 {
00210     WCombinerTypes::WCompatiblesList compatibles;
00211 
00212     // for this a read lock is sufficient, gets unlocked if it looses scope
00213     PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
00214 
00215     // has the module an output? If not, return.
00216     bool addModulesWithoutInput = !module;
00217 
00218     if( addModulesWithoutInput )
00219     {
00220         // First, add all modules with no input connector.
00221         for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
00222                 ++listIter )
00223         {
00224             // get connectors of this prototype
00225             WModule::InputConnectorList pcons = ( *listIter )->getInputConnectors();
00226             if(  pcons.size() == 0  )
00227             {
00228                 // the modules which match every time need their own groups
00229                 WCombinerTypes::WOneToOneCombiners lComp;
00230 
00231                 // NOTE: it is OK here to use the variable module even if it is NULL as the combiner in this case only adds the specified module
00232                 lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( module, "", *listIter, "" ) ) );
00233 
00234                 // add this list
00235                 compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
00236             }
00237         }
00238     }
00239 
00240     // if NULL was specified, only return all modules without any inputs
00241     if( module )
00242     {
00243         // go through every prototype
00244         for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
00245              ++listIter )
00246         {
00247             WCombinerTypes::WOneToOneCombiners lComp = WApplyCombiner::createCombinerList< WApplyCombiner >( module, ( *listIter ) );
00248 
00249             // add the group
00250             if( lComp.size() != 0 )
00251             {
00252                 compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
00253             }
00254         }
00255     }
00256 
00257     // unlock. No locking needed for further steps.
00258     l.reset();
00259 
00260     // sort the compatibles
00261     std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
00262 
00263     return compatibles;
00264 }
00265 
00266 WCombinerTypes::WCompatiblesList WModuleFactory::getAllPrototypes()
00267 {
00268     WCombinerTypes::WCompatiblesList compatibles;
00269 
00270     // for this a read lock is sufficient, gets unlocked if it looses scope
00271     PrototypeSharedContainerType::ReadTicket l = m_prototypes.getReadTicket();
00272 
00273     // Add all modules.
00274     for( PrototypeContainerConstIteratorType listIter = l->get().begin(); listIter != l->get().end();
00275             ++listIter )
00276     {
00277         // the modules which match every time need their own groups
00278         WCombinerTypes::WOneToOneCombiners lComp;
00279 
00280         // NOTE: it is OK here to use the variable module even if it is NULL as the combiner in this case only adds the specified module
00281         lComp.push_back( boost::shared_ptr< WApplyCombiner >( new WApplyCombiner( *listIter ) ) );
00282 
00283         // add this list
00284         compatibles.push_back( WCombinerTypes::WCompatiblesGroup( ( *listIter ), lComp ) );
00285     }
00286 
00287     // unlock. No locking needed for further steps.
00288     l.reset();
00289 
00290     // sort the compatibles
00291     std::sort( compatibles.begin(), compatibles.end(), WCombinerTypes::compatiblesSort );
00292 
00293     return compatibles;
00294 }
00295