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