OpenWalnut 1.3.1
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 <string>
00028 #include <vector>
00029 #include <iterator>
00030 
00031 #include <boost/regex.hpp>
00032 
00033 #include "WKernel.h"
00034 #include "combiner/WModuleProjectFileCombiner.h"
00035 #include "WRoiProjectFileIO.h"
00036 #include "../graphicsEngine/WGEProjectFileIO.h"
00037 #include "../common/exceptions/WFileNotFound.h"
00038 #include "../common/exceptions/WFileOpenFailed.h"
00039 #include "../common/WStringUtils.h"
00040 
00041 #include "WProjectFile.h"
00042 
00043 WProjectFile::WProjectFile( boost::filesystem::path project ):
00044     WThreadedRunner(),
00045     boost::enable_shared_from_this< WProjectFile >(),
00046     m_project( project )
00047 {
00048     // initialize members
00049 
00050     // The module graph parser
00051     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WModuleProjectFileCombiner() ) );
00052 
00053     // The ROI parser
00054     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WRoiProjectFileIO() ) );
00055 
00056     // The Camera parser
00057     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WGEProjectFileIO() ) );
00058 }
00059 
00060 WProjectFile::WProjectFile( boost::filesystem::path project, ProjectLoadCallback doneCallback ):
00061     WThreadedRunner(),
00062     boost::enable_shared_from_this< WProjectFile >(),
00063     m_project( project ),
00064     m_signalLoadDoneConnection( m_signalLoadDone.connect( doneCallback ) )
00065 {
00066     // The module graph parser
00067     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WModuleProjectFileCombiner() ) );
00068 
00069     // The ROI parser
00070     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WRoiProjectFileIO() ) );
00071 
00072     // The Camera parser
00073     m_parsers.push_back( boost::shared_ptr< WProjectFileIO >( new WGEProjectFileIO() ) );
00074 }
00075 
00076 WProjectFile::~WProjectFile()
00077 {
00078     // cleanup
00079     m_parsers.clear();
00080     m_signalLoadDoneConnection.disconnect();
00081 }
00082 
00083 boost::shared_ptr< WProjectFileIO > WProjectFile::getCameraWriter()
00084 {
00085     return boost::shared_ptr< WProjectFileIO >( new WGEProjectFileIO() );
00086 }
00087 
00088 boost::shared_ptr< WProjectFileIO > WProjectFile::getModuleWriter()
00089 {
00090     return boost::shared_ptr< WProjectFileIO >( new WModuleProjectFileCombiner() );
00091 }
00092 
00093 boost::shared_ptr< WProjectFileIO > WProjectFile::getROIWriter()
00094 {
00095     return boost::shared_ptr< WProjectFileIO >( new WRoiProjectFileIO() );
00096 }
00097 
00098 void WProjectFile::load()
00099 {
00100     // the instance needs to be added here, as it else could be freed before the thread finishes ( remember: it is a shared_ptr ).
00101     WKernel::getRunningKernel()->getRootContainer()->addPendingThread( shared_from_this() );
00102 
00103     // actually run
00104     run();
00105 }
00106 
00107 void WProjectFile::save( const std::vector< boost::shared_ptr< WProjectFileIO > >& writer )
00108 {
00109     wlog::info( "Project File" ) << "Saving project file \"" << m_project.string() << "\".";
00110 
00111     // open the file for write
00112     std::ofstream output( m_project.string().c_str() );
00113     if( !output.is_open() )
00114     {
00115         throw WFileOpenFailed( std::string( "The project file \"" ) + m_project.string() +
00116                                std::string( "\" could not be opened for write access." ) );
00117     }
00118 
00119     // allow each parser to handle save request
00120     for( std::vector< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = writer.begin(); iter != writer.end(); ++iter )
00121     {
00122         ( *iter )->save( output );
00123         output << std::endl;
00124     }
00125 
00126     output.close();
00127 }
00128 
00129 void WProjectFile::save()
00130 {
00131     save( m_parsers );
00132 }
00133 
00134 void WProjectFile::threadMain()
00135 {
00136     // Parse the file
00137     wlog::info( "Project File" ) << "Loading project file \"" << m_project.string() << "\".";
00138 
00139     // store some errors
00140     std::vector< std::string > errors;
00141 
00142     // read the file
00143     std::ifstream input( m_project.string().c_str() );
00144     if( !input.is_open() )
00145     {
00146         errors.push_back( std::string( "The project file \"" ) + m_project.string() + std::string( "\" does not exist." ) );
00147 
00148         // give some feedback
00149         m_signalLoadDone( m_project, errors );
00150         m_signalLoadDoneConnection.disconnect();
00151 
00152         // also throw an exception
00153         throw WFileNotFound( *errors.begin() );
00154     }
00155 
00156     // the comment
00157     static const boost::regex commentRe( "^ *//.*$" );
00158 
00159     // read it line by line
00160     std::string line;       // the current line
00161     int i = 0;              // line counter
00162     bool match = false;     // true of a parser successfully parsed the line
00163     boost::smatch matches;  // the list of matches
00164 
00165     while( std::getline( input, line ) )
00166     {
00167         ++i;    // line number
00168         match = false;
00169 
00170         // allow each parser to handle the line.
00171         for( std::vector< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter )
00172         {
00173             try
00174             {
00175                 if( ( *iter )->parse( line, i ) )
00176                 {
00177                     match = true;
00178                     // the first parser matching this line -> next line
00179                     break;
00180                 }
00181             }
00182             catch( const std::exception& e )
00183             {
00184                 errors.push_back( "Parse error on line " + string_utils::toString( i ) + ": " + e.what() );
00185                 wlog::error( "Project Loader" ) << errors.back();
00186             }
00187         }
00188 
00189         // did someone match this line? Or is it empty or a comment?
00190         if( !match && !line.empty() && !boost::regex_match( line, matches, commentRe ) )
00191         {
00192             // no it is something else -> warning! Not a critical error.
00193             wlog::warn( "Project Loader" ) << "Line " << i << ": Malformed. Skipping.";
00194         }
00195     }
00196 
00197     input.close();
00198 
00199     // finally, let every one know that we have finished
00200     for( std::vector< boost::shared_ptr< WProjectFileIO > >::const_iterator iter = m_parsers.begin(); iter != m_parsers.end(); ++iter )
00201     {
00202         try
00203         {
00204             ( *iter )->done();
00205             // append errors
00206             std::copy( ( *iter )->getErrors().begin(), ( *iter )->getErrors().end(), std::back_inserter( errors ) );
00207         }
00208         catch( const std::exception& e )
00209         {
00210             errors.push_back( "Exception while applying settings: " + std::string( e.what() ) );
00211             wlog::error( "Project Loader" ) << errors.back();
00212         }
00213     }
00214 
00215     // give some feedback
00216     m_signalLoadDone( m_project, errors );
00217     m_signalLoadDoneConnection.disconnect();
00218 
00219     // remove from thread list
00220     WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() );
00221 }
00222 
00223 void WProjectFile::onThreadException( const WException& e )
00224 {
00225     // let WThreadedRunner do the remaining tasks.
00226     handleDeadlyException( e, "Project Loader" );
00227 
00228     // remove from thread list. Please note: this NEEDS to be done after handleDeadlyException - if done before, the thread pointer might be
00229     // deleted already.
00230     WKernel::getRunningKernel()->getRootContainer()->finishedPendingThread( shared_from_this() );
00231 }