OpenWalnut  1.4.0
WProjectFile.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 <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