OpenWalnut
1.2.5
|
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 <iostream> 00026 #include <map> 00027 #include <set> 00028 #include <list> 00029 #include <string> 00030 #include <utility> 00031 00032 #include <boost/regex.hpp> 00033 #include <boost/lexical_cast.hpp> 00034 00035 #include "../WKernel.h" 00036 #include "../WModuleCombiner.h" 00037 #include "../WModuleFactory.h" 00038 #include "../WModuleConnector.h" 00039 #include "../WModule.h" 00040 #include "../WDataModule.h" 00041 #include "../WModuleInputConnector.h" 00042 #include "../WModuleOutputConnector.h" 00043 #include "../exceptions/WModuleConnectorNotFound.h" 00044 00045 #include "../../common/exceptions/WFileNotFound.h" 00046 #include "../../common/WProperties.h" 00047 #include "../../common/WPropertyBase.h" 00048 #include "../../common/WPropertyVariable.h" 00049 #include "../../common/WPropertyTypes.h" 00050 #include "../../common/WLogger.h" 00051 #include "../../common/math/linearAlgebra/WLinearAlgebra.h" 00052 00053 #include "WModuleProjectFileCombiner.h" 00054 00055 WModuleProjectFileCombiner::WModuleProjectFileCombiner( boost::shared_ptr< WModuleContainer > target ): 00056 WModuleCombiner( target ), 00057 WProjectFileIO() 00058 { 00059 } 00060 00061 WModuleProjectFileCombiner::WModuleProjectFileCombiner(): 00062 WModuleCombiner( WKernel::getRunningKernel()->getRootContainer() ), 00063 WProjectFileIO() 00064 { 00065 } 00066 00067 WModuleProjectFileCombiner::~WModuleProjectFileCombiner() 00068 { 00069 // cleanup 00070 } 00071 00072 bool WModuleProjectFileCombiner::parse( std::string line, unsigned int lineNumber ) 00073 { 00074 // this is the proper regular expression for modules 00075 static const boost::regex modRe( "^ *MODULE:([0-9]*):(.*)$" ); 00076 static const boost::regex dataRe( "^ *DATA:([0-9]*):(.*)$" ); 00077 static const boost::regex conRe( "^ *CONNECTION:\\(([0-9]*),(.*)\\)->\\(([0-9]*),(.*)\\)$" ); 00078 static const boost::regex propRe( "^ *PROPERTY:\\(([0-9]*),(.*)\\)=(.*)$" ); 00079 00080 boost::smatch matches; // the list of matches 00081 if( boost::regex_match( line, matches, modRe ) ) 00082 { 00083 // it is a module line 00084 // matches[1] is the ID 00085 // matches[2] is the name of the module 00086 00087 wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Module \"" << matches[2] << "\" with ID " << matches[1]; 00088 00089 // create a module instance 00090 boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( matches[2] ); 00091 00092 // data modules are not allowed here 00093 if( !proto ) 00094 { 00095 wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << matches[2] << "\". Skipping."; 00096 } 00097 else if( proto->getType() == MODULE_DATA ) 00098 { 00099 wlog::error( "Project Loader" ) << "Data modules are not allowed to be specified in a \"MODULE\" Statement." << 00100 " Use the \"DATA\" statement instead. Skipping."; 00101 } 00102 else 00103 { 00104 boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto ); 00105 m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) ); 00106 } 00107 } 00108 else if( boost::regex_match( line, matches, dataRe ) ) 00109 { 00110 // it is a dataset line 00111 // matches[1] is the ID 00112 // matches[2] is the filename 00113 wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Data \"" << matches[2] << "\" with ID " << matches[1]; 00114 00115 // create a module instance 00116 boost::shared_ptr< WModule > proto = WModuleFactory::getModuleFactory()-> isPrototypeAvailable( "Data Module" ); 00117 if( !proto ) 00118 { 00119 wlog::error( "Project Loader" ) << "There is no prototype available for module \"" << "Data Module" << "\"." 00120 << " This should not happen!. Skipping."; 00121 } 00122 else 00123 { 00124 std::string parameter = std::string( matches[2] ); 00125 boost::shared_ptr< WModule > module = WModuleFactory::getModuleFactory()->create( proto ); 00126 if( parameter.empty() ) 00127 { 00128 wlog::error( "Project Loader" ) << "Data modules need an additional filename parameter. Skipping."; 00129 } 00130 else 00131 { 00132 boost::shared_static_cast< WDataModule >( module )->setFilename( parameter ); 00133 m_modules.insert( ModuleID( boost::lexical_cast< unsigned int >( matches[1] ), module ) ); 00134 } 00135 } 00136 } 00137 else if( boost::regex_match( line, matches, conRe ) ) 00138 { 00139 // it is a connector line 00140 // matches[1] and [2] are the module ID and connector name of the output connector 00141 // matches[3] and [4] are the module ID and connector name of the target input connector 00142 00143 wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Connection between \"" << matches[2] << "\" of module " 00144 << matches[1] << " and \"" << matches[4] << "\" of module " << matches[3] << "."; 00145 00146 // now we search in modules[ matches[1] ] for an output connector named matches[2] 00147 m_connections.push_back( Connection( Connector( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), 00148 Connector( boost::lexical_cast< unsigned int >( matches[3] ), matches[4] ) ) ); 00149 } 00150 else if( boost::regex_match( line, matches, propRe ) ) 00151 { 00152 // it is a property line 00153 // matches[1] is the module ID 00154 // matches[2] is the property name 00155 // matches[3] is the property value 00156 00157 wlog::debug( "Project Loader [Parser]" ) << "Line " << lineNumber << ": Property \"" << matches[2] << "\" of module " << matches[1] 00158 << " set to " << matches[3]; 00159 00160 m_properties.push_back( PropertyValue( Property( boost::lexical_cast< unsigned int >( matches[1] ), matches[2] ), matches[3] ) ); 00161 } 00162 else 00163 { 00164 return false; 00165 } 00166 00167 return true; 00168 } 00169 00170 void WModuleProjectFileCombiner::apply() 00171 { 00172 // now add each module to the target container 00173 for( std::map< unsigned int, boost::shared_ptr< WModule > >::const_iterator iter = m_modules.begin(); iter != m_modules.end(); ++iter ) 00174 { 00175 m_container->add( ( *iter ).second ); 00176 } 00177 00178 // now wait for the modules to get ready. We could have waited for this in the previous loop, but a long loading module would block others. 00179 // -> so we wait after adding and starting them 00180 for( std::map< unsigned int, boost::shared_ptr< WModule > >::iterator iter = m_modules.begin(); iter != m_modules.end(); ++iter ) 00181 { 00182 ( *iter ).second->isReadyOrCrashed().wait(); 00183 00184 // if isReady now is false, the module has crashed before it got ready -> remove the module from the list 00185 if( ( *iter ).second->isCrashed()() ) 00186 { 00187 wlog::warn( "Project Loader" ) << "In the module with ID " 00188 << ( *iter ).first 00189 << " a problem occurred. Connections and properties relating to this" 00190 << " module will fail."; 00191 m_modules.erase( iter ); 00192 } 00193 } 00194 00195 // now, as we have created the modules, we need to set the properties for each of it. 00196 for( std::list< PropertyValue >::const_iterator iter = m_properties.begin(); iter != m_properties.end(); ++iter ) 00197 { 00198 // grab corresponding module 00199 if( !m_modules.count( ( *iter ).first.first ) ) 00200 { 00201 wlog::error( "Project Loader" ) << "There is no module with ID \"" << ( *iter ).first.first << "\" to set the property \"" << 00202 ( *iter ).first.second << "\" for. Skipping."; 00203 continue; 00204 } 00205 boost::shared_ptr< WModule > m = m_modules[ ( *iter ).first.first ]; 00206 00207 // has this module the specified property? 00208 boost::shared_ptr< WPropertyBase > prop = m->getProperties()->findProperty( ( *iter ).first.second ); 00209 if( !prop ) 00210 { 00211 wlog::error( "Project Loader" ) << "The module \"" << m->getName() << "\" has no property named \"" << 00212 ( *iter ).first.second << "\". Skipping."; 00213 continue; 00214 } 00215 else 00216 { 00217 if( prop->getPurpose() != PV_PURPOSE_INFORMATION ) 00218 { 00219 // set the property here 00220 bool result = prop->setAsString( ( *iter ).second ); 00221 if( !result ) 00222 { 00223 wlog::error( "Project Loader" ) << "Failed to set property " << ( *iter ).first.second << " in module \"" << 00224 m->getName() << "\"."; 00225 } 00226 } 00227 else 00228 { 00229 wlog::error( "Project Loader" ) << "The module \"" << m->getName() << "\" has a property named \"" << 00230 ( *iter ).first.second << "\" which is an INFORMATION property. Skipping."; 00231 } 00232 } 00233 } 00234 00235 // and finally, connect them all together 00236 for( std::list< Connection >::const_iterator iter = m_connections.begin(); iter != m_connections.end(); ++iter ) 00237 { 00238 // each connection contains two connectors 00239 Connector c1 = ( *iter ).first; 00240 Connector c2 = ( *iter ).second; 00241 00242 // each of these connectors contains the module ID and the connector name 00243 // grab corresponding module 1 00244 boost::shared_ptr< WModule > m1; 00245 if( !m_modules.count( c1.first ) ) 00246 { 00247 wlog::error( "Project Loader" ) << "There is no module with ID \"" << c1.first << "\" for the connection " 00248 << "(" << c1.first << "," << c1.second << ")->(" << c2.first << "," << c2.second << "). Skipping."; 00249 00250 continue; 00251 } 00252 m1 = m_modules[ c1.first ]; 00253 00254 boost::shared_ptr< WModule > m2; 00255 if( !m_modules.count( c2.first ) ) 00256 { 00257 wlog::error( "Project Loader" ) << "There is no module with ID \"" << c2.first << "\" for the connection " 00258 << "(" << c1.first << "," << c1.second << ")->(" << c2.first << "," << c2.second << "). Skipping."; 00259 00260 continue; 00261 } 00262 m2 = m_modules[ c2.first ]; 00263 00264 // now we have the modules referenced by the ID 00265 // -> query the connectors 00266 // NOTE: we assume the first connector to be an output connector! 00267 boost::shared_ptr< WModuleOutputConnector > con1; 00268 try 00269 { 00270 con1 = m1->getOutputConnector( c1.second ); 00271 } 00272 catch( const WModuleConnectorNotFound& e ) 00273 { 00274 wlog::error( "Project Loader" ) << "There is no output connector \"" << c1.second << "\" in module \"" << m1->getName() << "\""; 00275 continue; 00276 } 00277 boost::shared_ptr< WModuleInputConnector > con2; 00278 try 00279 { 00280 con2 = m2->getInputConnector( c2.second ); 00281 } 00282 catch( const WModuleConnectorNotFound& e ) 00283 { 00284 wlog::error( "Project Loader" ) << "There is no input connector \"" << c2.second << "\" in module \"" << m2->getName() << "\""; 00285 continue; 00286 } 00287 00288 // finally, connect them 00289 try 00290 { 00291 con1->connect( con2 ); 00292 } 00293 catch( const WException& e ) 00294 { 00295 wlog::error( "Project Loader" ) << "Connection " << "(" << c1.first << "," << c1.second << ")->(" << c2.first << "," << c2.second << 00296 ") could not be created. Incompatible connectors?. Skipping."; 00297 continue; 00298 } 00299 } 00300 00301 // clear all our lists (deref all contained pointers) 00302 m_modules.clear(); 00303 m_connections.clear(); 00304 m_properties.clear(); 00305 } 00306 00307 void WModuleProjectFileCombiner::done() 00308 { 00309 apply(); 00310 } 00311 00312 void WModuleProjectFileCombiner::printProperties( std::ostream& output, boost::shared_ptr< WProperties > props, std::string indent, //NOLINT 00313 std::string prefix, unsigned int module ) 00314 { 00315 // lock, unlocked if l looses focus 00316 WProperties::PropertySharedContainerType::ReadTicket l = props->getProperties(); 00317 00318 output << indent << "// Property Group: " << props->getName() << std::endl; 00319 00320 // iterate of them and print them to output 00321 for( WProperties::PropertyConstIterator iter = l->get().begin(); iter != l->get().end(); ++iter ) 00322 { 00323 // information properties do not get written 00324 if( ( *iter )->getPurpose () == PV_PURPOSE_INFORMATION ) 00325 { 00326 continue; 00327 } 00328 if( ( *iter )->getType() != PV_GROUP ) 00329 { 00330 output << indent + " " << "PROPERTY:(" << module << "," << prefix + ( *iter )->getName() << ")=" 00331 << ( *iter )->getAsString() << std::endl; 00332 } 00333 else 00334 { 00335 // it is a group -> recursively print it 00336 if( prefix.empty() ) 00337 { 00338 printProperties( output, ( *iter )->toPropGroup(), indent + " ", ( *iter )->getName() + "/", module ); 00339 } 00340 else 00341 { 00342 printProperties( output, ( *iter )->toPropGroup(), indent + " ", prefix + ( *iter )->getName() + "/", module ); 00343 } 00344 } 00345 } 00346 00347 output << indent << "// Property Group END: " << props->getName() << std::endl; 00348 } 00349 00350 void WModuleProjectFileCombiner::save( std::ostream& output ) // NOLINT 00351 { 00352 // grab access object of root container 00353 WModuleContainer::ModuleSharedContainerType::ReadTicket container = WKernel::getRunningKernel()->getRootContainer()->getModules(); 00354 00355 std::map< boost::shared_ptr< WModule >, unsigned int > moduleToIDMap; 00356 00357 output << "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////" << std::endl << 00358 "// Modules and Properties" << std::endl << 00359 "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////" << std::endl << 00360 std::endl; 00361 00362 // iterate all modules: 00363 unsigned int i = 0; 00364 for( WModuleContainer::ModuleConstIterator iter = container->get().begin(); iter != container->get().end(); ++iter ) 00365 { 00366 // store the mapping of ptr to ID 00367 moduleToIDMap[ ( *iter ) ] = i; 00368 00369 // handle data modules separately 00370 if( ( *iter )->getType() == MODULE_DATA ) 00371 { 00372 output << "DATA:" << i << ":" << boost::shared_static_cast< WDataModule >( ( *iter ) )->getFilename() << std::endl; 00373 } 00374 else 00375 { 00376 output << "MODULE:" << i << ":" << ( *iter )->getName() << std::endl; 00377 } 00378 00379 // the properties: 00380 printProperties( output, ( *iter )->getProperties(), "", "", i ); 00381 00382 // some readability: 00383 output << std::endl; 00384 ++i; 00385 } 00386 00387 // finally, process all connections for each module 00388 output << "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////" << std::endl << 00389 "// Connections" << std::endl << 00390 "//////////////////////////////////////////////////////////////////////////////////////////////////////////////////" << std::endl << 00391 std::endl; 00392 00393 00394 // iterate over all modules 00395 for( WModuleContainer::ModuleConstIterator iter = container->get().begin(); iter != container->get().end(); ++iter ) 00396 { 00397 // iterate over all outputs 00398 const WModule::OutputConnectorList& outs = ( *iter )->getOutputConnectors(); 00399 for( WModule::OutputConnectorList::const_iterator citer = outs.begin(); citer != outs.end(); ++citer ) 00400 { 00401 // iterate over all connections: 00402 // TODO(ebaum): iterating over a protected member variable? Thats ugly. This should be adopted to WSharedObject 00403 boost::unique_lock<boost::shared_mutex> lock( ( *citer )->m_connectionListLock ); 00404 for( std::set<boost::shared_ptr<WModuleConnector> >::const_iterator iciter = ( *citer )->m_connected.begin(); 00405 iciter != ( *citer )->m_connected.end(); ++iciter ) 00406 { 00407 // as the module is a weak_ptr -> lock and get access to it 00408 boost::shared_ptr< WModule > theOtherModule = ( *iciter )->m_module.lock(); 00409 output << "CONNECTION:(" << moduleToIDMap[ ( *iter ) ] << "," << ( *citer )->getName() << ")->(" << 00410 moduleToIDMap[ theOtherModule ] << "," << ( *iciter )->getName() << ")" << std::endl; 00411 } 00412 lock.unlock(); 00413 } 00414 } 00415 } 00416