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