OpenWalnut 1.2.5
WModuleProjectFileCombiner.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 <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 
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends