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