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 <fstream> 00027 #include <iterator> 00028 #include <list> 00029 #include <string> 00030 #include <vector> 00031 00032 #include <boost/regex.hpp> 00033 00034 #include "WModule.h" 00035 #include "WKernel.h" 00036 #include "combiner/WModuleProjectFileCombiner.h" 00037 #include "WRoiProjectFileIO.h" 00038 #include "../graphicsEngine/WGEProjectFileIO.h" 00039 #include "../common/exceptions/WFileNotFound.h" 00040 #include "../common/exceptions/WFileOpenFailed.h" 00041 #include "../common/WStringUtils.h" 00042 00043 #include "WProjectFile.h" 00044 00045 WProjectFile::ParserList WProjectFile::m_additionalParsers; 00046 00047 WProjectFile::WProjectFile( boost::filesystem::path project ): 00048 WThreadedRunner(), 00049 boost::enable_shared_from_this< WProjectFile >(), 00050 m_project( project ) 00051 { 00052 // initialize members 00053 boost::shared_ptr< WProjectFileIO > p1( new WModuleProjectFileCombiner() ); 00054 boost::shared_ptr< WProjectFileIO > p2( new WRoiProjectFileIO() ); 00055 boost::shared_ptr< WProjectFileIO > p3( new WGEProjectFileIO() ); 00056 00057 // The module graph parser 00058 m_moduleIO = boost::dynamic_pointer_cast< WModuleProjectFileCombiner >( p1->clone( this ) ); 00059 m_parsers.push_back( m_moduleIO ); 00060 m_writers.push_back( m_moduleIO ); 00061 00062 // The ROI parser 00063 m_parsers.push_back( p2->clone( this ) ); 00064 m_writers.push_back( p2->clone( this ) ); 00065 00066 // The Camera parser 00067 m_parsers.push_back( p3->clone( this ) ); 00068 m_writers.push_back( p3->clone( this ) ); 00069 00070 // add the current list of additional parsers 00071 ParserList::ReadTicket r = m_additionalParsers.getReadTicket(); 00072 00073 // Grab all items and add to my own list of parsers 00074 for( ParserList::ConstIterator it = r->get().begin(); it != r->get().end(); ++it ) 00075 { 00076 if( ( *it )->getApplyOrder() == WProjectFileIO::POST_MODULES ) 00077 { 00078 m_parsers.push_back( ( *it )->clone( this ) ); 00079 } 00080 else 00081 { 00082 m_parsers.push_front( ( *it )->clone( this ) ); 00083 } 00084 00085 // always add savers behind the module saver, to allow the module saver build the id map 00086 m_writers.push_back( ( *it )->clone( this ) ); 00087 } 00088 00089 // ticket unlocked automatically upon its destruction 00090 } 00091 00092 WProjectFile::WProjectFile( boost::filesystem::path project, ProjectLoadCallback doneCallback ): 00093 WThreadedRunner(), 00094 boost::enable_shared_from_this< WProjectFile >(), 00095 m_project( project ), 00096 m_signalLoadDoneConnection( m_signalLoadDone.connect( doneCallback ) ) 00097 { 00098 // initialize members 00099 boost::shared_ptr< WProjectFileIO > p1( new WModuleProjectFileCombiner() ); 00100 boost::shared_ptr< WProjectFileIO > p2( new WRoiProjectFileIO() ); 00101 boost::shared_ptr< WProjectFileIO > p3( new WGEProjectFileIO() ); 00102 00103 // The module graph parser 00104 m_moduleIO = boost::dynamic_pointer_cast< WModuleProjectFileCombiner >( p1->clone( this ) ); 00105 m_parsers.push_back( m_moduleIO ); 00106 m_writers.push_back( m_moduleIO ); 00107 00108 // The ROI parser 00109 m_parsers.push_back( p2->clone( this ) ); 00110 m_writers.push_back( p2->clone( this ) ); 00111 00112 // The Camera parser 00113 m_parsers.push_back( p3->clone( this ) ); 00114 m_writers.push_back( p3->clone( this ) ); 00115 00116 // add the current list of additional parsers 00117 ParserList::ReadTicket r = m_additionalParsers.getReadTicket(); 00118 00119 // Grab all items and add to my own list of parsers 00120 for( ParserList::ConstIterator it = r->get().begin(); it != r->get().end(); ++it ) 00121 { 00122 if( ( *it )->getApplyOrder() == WProjectFileIO::POST_MODULES ) 00123 { 00124 m_parsers.push_back( ( *it )->clone( this ) ); 00125 } 00126 else 00127 { 00128 m_parsers.push_front( ( *it )->clone( this ) ); 00129 } 00130 00131 // always add savers behind the module saver, to allow the module saver build the id map 00132 m_writers.push_back( ( *it )->clone( this ) ); 00133 } 00134 00135 // ticket unlocked automatically upon its destruction 00136 } 00137 00138 WProjectFile::~WProjectFile() 00139 { 00140 // cleanup 00141 m_parsers.clear(); 00142 m_writers.clear(); 00143 m_signalLoadDoneConnection.disconnect(); 00144 } 00145 00146 boost::shared_ptr< WProjectFileIO > WProjectFile::getCameraWriter() 00147 { 00148 return boost::shared_ptr< WProjectFileIO >( new WGEProjectFileIO() ); 00149 } 00150 00151 boost::shared_ptr< WProjectFileIO > WProjectFile::getModuleWriter() 00152 { 00153 return boost::shared_ptr< WProjectFileIO >( new WModuleProjectFileCombiner() ); 00154 } 00155 00156 boost::shared_ptr< WProjectFileIO > WProjectFile::getROIWriter() 00157 { 00158 return boost::shared_ptr< WProjectFileIO >( new WRoiProjectFileIO() ); 00159 } 00160 00161 void WProjectFile::load() 00162 { 00163 // the instance needs to be added here, as it else could be freed before the thread finishes ( remember: it is a shared_ptr ). 00164 WKernel::getRunningKernel()->getRootContainer()->addPendingThread( shared_from_this() ); 00165 00166 // actually run 00167 run(); 00168 } 00169 00170 void WProjectFile::save( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer ) 00171 { 00172 std::list< boost::shared_ptr< WProjectFileIO > > l( writer.begin(), writer.end() ); 00173 save( l ); 00174 } 00175 00176 void WProjectFile::save( const std::list< boost::shared_ptr< WProjectFileIO > >& writer ) 00177 { 00178 wlog::info( "Project File" ) << "Saving project file \"" << m_project.string() << "\"."; 00179 00180 // open the file for write 00181 std::ofstream output( m_project.string().c_str() ); 00182 if( !output.is_open() ) 00183 { 00184 throw WFileOpenFailed( std::string( "The project file \"" ) + m_project.string() + 00185 std::string( "\" could not be opened for write access." ) ); 00186 } 00187 00188 // allow each parser to handle save request 00189 for( std::list< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = writer.begin(); iter != writer.end(); ++iter ) 00190 { 00191 ( *iter )->save( output ); 00192 output << std::endl; 00193 } 00194 00195 output.close(); 00196 } 00197 00198 void WProjectFile::save() 00199 { 00200 save( m_writers ); 00201 } 00202 00203 void WProjectFile::threadMain() 00204 { 00205 // Parse the file 00206 wlog::info( "Project File" ) << "Loading project file \"" << m_project.string() << "\"."; 00207 00208 // store some errors and warnings 00209 std::vector< std::string > errors; 00210 std::vector< std::string > warnings; 00211 00212 // read the file 00213 std::ifstream input( m_project.string().c_str() ); 00214 if( !input.is_open() ) 00215 { 00216 errors.push_back( std::string( "The project file \"" ) + m_project.string() + std::string( "\" does not exist." ) ); 00217 00218 // give some feedback 00219 m_signalLoadDone( m_project, errors, warnings ); 00220 m_signalLoadDoneConnection.disconnect(); 00221 00222 // also throw an exception 00223 throw WFileNotFound( *errors.begin() ); 00224 } 00225 00226 // the comment 00227 static const boost::regex commentRe( "^ *//.*$" ); 00228 00229 // read it line by line 00230 std::string line; // the current line 00231 int i = 0; // line counter 00232 bool match = false; // true of a parser successfully parsed the line 00233 boost::smatch matches; // the list of matches 00234 00235 while( std::getline( input, line ) ) 00236 { 00237 ++i; // line number 00238 match = false; 00239 00240 // allow each parser to handle the line. 00241 for( std::list< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter ) 00242 { 00243 try 00244 { 00245 if( ( *iter )->parse( line, i ) ) 00246 { 00247 match = true; 00248 // the first parser matching this line -> next line 00249 break; 00250 } 00251 } 00252 catch( const std::exception& e ) 00253 { 00254 errors.push_back( "Parse error on line " + string_utils::toString( i ) + ": " + e.what() ); 00255 wlog::error( "Project Loader" ) << errors.back(); 00256 } 00257 } 00258 00259 // did someone match this line? Or is it empty or a comment? 00260 if( !match && !line.empty() && !boost::regex_match( line, matches, commentRe ) ) 00261 { 00262 // no it is something else -> warning! Not a critical error. 00263 wlog::warn( "Project Loader" ) << "Line " << i << ": Malformed. Skipping."; 00264 } 00265 } 00266 00267 input.close(); 00268 00269 // finally, let every one know that we have finished 00270 for( std::list< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter ) 00271 { 00272 try 00273 { 00274 ( *iter )->done(); 00275 // append errors and warnings 00276 std::copy( ( *iter )->getErrors().begin(), ( *iter )->getErrors().end(), std::back_inserter( errors ) ); 00277 std::copy( ( *iter )->getWarnings().begin(), ( *iter )->getWarnings().end(), std::back_inserter( warnings ) ); 00278 } 00279 catch( const std::exception& e ) 00280 { 00281 errors.push_back( "Exception while applying settings: " + std::string( e.what() ) ); 00282 wlog::error( "Project Loader" ) << errors.back(); 00283 } 00284 } 00285 00286 // give some feedback 00287 m_signalLoadDone( m_project, errors, warnings ); 00288 m_signalLoadDoneConnection.disconnect(); 00289 00290 // remove from thread list 00291 WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() ); 00292 } 00293 00294 void WProjectFile::onThreadException( const WException& e ) 00295 { 00296 // let WThreadedRunner do the remaining tasks. 00297 handleDeadlyException( e, "Project Loader" ); 00298 00299 // remove from thread list. Please note: this NEEDS to be done after handleDeadlyException - if done before, the thread pointer might be 00300 // deleted already. 00301 WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() ); 00302 } 00303 00304 void WProjectFile::registerParser( WProjectFileIO::SPtr parser ) 00305 { 00306 ParserList::WriteTicket w = m_additionalParsers.getWriteTicket(); 00307 00308 // find item if still inside 00309 ParserList::Iterator it = std::find( w->get().begin(), w->get().end(), parser ); 00310 // item not inside? Add! 00311 if( it == w->get().end() ) 00312 { 00313 // add 00314 w->get().push_back( parser ); 00315 } 00316 // ticket unlocked automatically upon its destruction 00317 } 00318 00319 void WProjectFile::deregisterParser( WProjectFileIO::SPtr parser ) 00320 { 00321 m_additionalParsers.remove( parser ); 00322 } 00323 00324 boost::shared_ptr< WModule > WProjectFile::mapToModule( unsigned int id ) const 00325 { 00326 return m_moduleIO->mapToModule( id ); 00327 } 00328 00329 unsigned int WProjectFile::mapFromModule( boost::shared_ptr< WModule > module ) const 00330 { 00331 return m_moduleIO->mapFromModule( module ); 00332 } 00333