OpenWalnut
1.4.0
|
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