openModeller  Version 1.4.0
WcsProxyRaster.cpp
Go to the documentation of this file.
00001 
00027 #include <openmodeller/env_io/WcsProxyRaster.hh>
00028 #include <openmodeller/Log.hh>
00029 #include <openmodeller/Exceptions.hh>
00030 #include <openmodeller/MapFormat.hh>
00031 #include <openmodeller/CacheManager.hh>
00032 #include <openmodeller/Settings.hh>
00033 #include <openmodeller/env_io/RemoteRaster.hh>
00034 
00035 #include <gdal.h>
00036 
00037 #include <string.h>
00038 #include <sstream>
00039 
00040 using namespace std;
00041 
00042 #ifdef MPI_FOUND
00043 #include "mpi.h"
00044 #endif
00045 
00046 /****************************************************************/
00047 /*********************** WCS Proxy Raster ***********************/
00048 
00049 /******************/
00050 /*** Destructor ***/
00051 WcsProxyRaster::~WcsProxyRaster()
00052 {
00053 }
00054 
00055 /******************************/
00056 /*** create Raster Callback ***/
00057 Raster*
00058 WcsProxyRaster::CreateRasterCallback()
00059 {
00060   return new WcsProxyRaster();
00061 }
00062 
00063 /*********************/
00064 /*** create Raster ***/
00065 void 
00066 WcsProxyRaster::createRaster( const string& str, int categ )
00067 {
00068   string cache_id = CacheManager::getContentIdMd5( str );
00069 
00071 
00072   if ( CacheManager::isCachedMd5( str, OM_WCS_PROXY_SUBDIR ) ) {
00073 
00074     Log::instance()->debug( "WCS proxy raster %s already present in local cache (%s)\n", str.c_str(), cache_id.c_str() );
00075 
00076     string cached_ref = CacheManager::getContentLocationMd5( str, OM_WCS_PROXY_SUBDIR );
00077 
00078     GdalRaster::createRaster( cached_ref, categ );
00079   }
00080   else {
00081 
00082     Log::instance()->debug( "Setting up WCS proxy for %s (%s)\n", str.c_str(), cache_id.c_str() );
00083 
00084     // Extract tokens from identifier
00085     vector<string> tokens;
00086     stringstream ss(str);
00087     string token;
00088     while ( getline(ss, token, '>') ) {
00089 
00090       tokens.push_back(token);
00091     }
00092 
00093     if ( tokens.size() != 3 ) {
00094 
00095       std::string msg = "Invalid WCS identifier. Make sure it has 3 parts separated by \">\".\n";
00096       Log::instance()->error( msg.c_str() );
00097       throw RasterException( msg.c_str() );
00098     }
00099 
00100     if ( RemoteRaster::isFromRejectedSource( tokens[1] ) ) {
00101 
00102       std::string msg = "Untrusted source for WCS raster. Aborting operation.\n";
00103       Log::instance()->error( msg.c_str() );
00104       throw RasterException( msg.c_str() );
00105     }
00106 
00107     // Create GDAL WCS XML file
00108     ostringstream oss (ostringstream::out);
00109     oss<<"<WCS_GDAL>"<<std::endl;
00110     oss<<"<ServiceURL>"<<tokens[1]<<"</ServiceURL>"<<std::endl;
00111     oss<<"<CoverageName>"<<tokens[2]<<"</CoverageName>"<<std::endl;
00112     oss<<"</WCS_GDAL>";
00113 
00114     // Then cache it
00115     CacheManager::cacheMd5( str, oss, OM_WCS_PROXY_SUBDIR );
00116   }
00117 
00118   string cached_ref = CacheManager::getContentLocationMd5( str, OM_WCS_PROXY_SUBDIR );
00119 
00121   if ( Settings::count( "FETCH_WCS" ) == 1 && Settings::get( "FETCH_WCS" ) == "true" ) {
00122 
00123     Log::instance()->debug( "openModeller configured to work with local copies of WCS rasters\n" );
00124 
00125     std::string clone_id( cache_id );
00126     clone_id.append(".img");
00127 
00128     std::string clone_ref( cached_ref );
00129     clone_ref.append(".img");
00130 
00131     // Check if file is being downloaded (presence of lock file)
00132     std::string lock_file = cache_id;
00133     lock_file.append(".lock");
00134 
00135     if ( CacheManager::isCached( lock_file, OM_WCS_PROXY_SUBDIR ) ) {
00136 
00137       Log::instance()->debug( "Ongoing concurrent download\n" );
00138       throw RasterException( "Ongoing concurrent download", 1 );
00139     }
00140 
00141     if ( CacheManager::isCached( clone_id, OM_WCS_PROXY_SUBDIR ) ) {
00142 
00143       Log::instance()->debug( "Local WCS copy already present: %s\n", clone_ref.c_str() );
00144 
00145       GdalRaster::createRaster( cached_ref, categ );
00146     }
00147     else {
00148 
00149       Log::instance()->debug( "Local WCS copy does not exist\n" );
00150 
00151       std::string retries_file = cache_id;
00152       retries_file.append(".tries");
00153 
00154       std::string retries_fullpath = CacheManager::getContentLocation( retries_file, OM_WCS_PROXY_SUBDIR );
00155       int num_retries = 0;
00156 
00157       // Check number of previous attempts
00158       if ( CacheManager::isCached( retries_file, OM_WCS_PROXY_SUBDIR ) ) {
00159 
00160         fstream fin;
00161         fin.open( retries_fullpath.c_str(), ios::in );
00162 
00163         if ( fin.is_open() ) {
00164 
00165           ostringstream oss;
00166           string line;
00167 
00168           getline( fin, line );
00169           oss << line << endl;
00170 
00171           // Note: if the content is empty, atoi returns 0
00172           num_retries = atoi( oss.str().c_str() );
00173 
00174           fin.close();
00175         }
00176         else {
00177 
00178           throw RasterException( "Could not determine number of previous download retries." );
00179         }
00180 
00181         if ( num_retries > 3 ) {
00182 
00183           // Without removing the file, it will need to be manually removed before trying again!
00184           CacheManager::eraseCache( retries_file, OM_WCS_PROXY_SUBDIR );
00185           throw RasterException( "Too many attempts to fetch raster. Aborting." );
00186         }
00187       }
00188 
00189       // Fetch file
00190       try {
00191 
00192         // Last minute double check
00193         if ( CacheManager::isCached( lock_file, OM_WCS_PROXY_SUBDIR ) ) {
00194 
00195           throw RasterException( "Ongoing concurrent download", 1 );
00196         }
00197 
00198         // Create lock file
00199         ostringstream oss (ostringstream::out);
00200         CacheManager::cache( lock_file, oss, OM_WCS_PROXY_SUBDIR );
00201 
00202         // Increase number of retries
00203         FILE *p_file = NULL;
00204         p_file = fopen( retries_fullpath.c_str(), "w" );
00205 
00206         if ( p_file == NULL ) {
00207 
00208           // Could not open file
00209           throw RasterException( "Could not store number of download retries." );
00210         }
00211         else {
00212 
00213           ++num_retries;
00214           char buffer[2];
00215           sprintf( buffer, "%d", num_retries );
00216           fputs( buffer, p_file );
00217           fclose( p_file );
00218         }
00219 
00220         // Finally fetch raster
00221         Log::instance()->debug( "Fetching WCS raster...\n" );
00222 
00223         GDALAllRegister();
00224 
00225         // Open source raster 
00226         GDALDatasetH hDataset = GDALOpen( cached_ref.c_str(), GA_ReadOnly );
00227         if ( hDataset == NULL ) {
00228 
00229           std::string msg = "Failed to open WCS raster!\n";
00230           Log::instance()->error( msg.c_str() );
00231           throw RasterException( msg.c_str() );
00232         }
00233 
00234         GDALDriverH hDriver = GDALGetDriverByName( "HFA" ); // Use Erdas Imagine
00235         if ( hDriver == NULL ) {
00236 
00237           GDALClose( hDataset );
00238           GDALDestroyDriverManager();
00239 
00240           std::string msg = "Could not find GDAL HFA driver!\n";
00241           Log::instance()->error( msg.c_str() );
00242           throw RasterException( msg.c_str() );
00243         }
00244 
00245         // Copy WCS proxy to HFA
00246         GDALDatasetH hOutDS = GDALCreateCopy( hDriver, clone_ref.c_str(), hDataset, FALSE, NULL, NULL, NULL );
00247 
00248         if ( hOutDS == NULL ) {
00249 
00250           GDALClose( hDataset );
00251           GDALDestroyDriverManager();
00252 
00253           std::string msg = "Could not clone WCS raster!\n";
00254           Log::instance()->error( msg.c_str() );
00255           throw RasterException( msg.c_str() );
00256         }
00257 
00258         GDALClose( hOutDS );
00259         GDALClose( hDataset );
00260 
00261         Log::instance()->debug( "Done!\n" );
00262     
00263         GdalRaster::createRaster( clone_ref, categ );
00264 
00265         // Erase lock and retries
00266         CacheManager::eraseCache( lock_file, OM_WCS_PROXY_SUBDIR );
00267         CacheManager::eraseCache( retries_file, OM_WCS_PROXY_SUBDIR );
00268       }
00269       catch ( RasterException& e ) {
00270 
00271         if ( e.getCode() != 1 ) {
00272 
00273           // Erase lock
00274           CacheManager::eraseCache( lock_file, OM_WCS_PROXY_SUBDIR );
00275         }
00276 
00277         throw;
00278       }
00279       catch (...) {
00280 
00281         // Erase lock
00282         CacheManager::eraseCache( lock_file, OM_WCS_PROXY_SUBDIR );
00283         throw;
00284       }
00285     }
00286   }
00287   else {
00288 
00289     Log::instance()->debug( "openModeller configured to work with remote WCS rasters\n" );
00290 
00291     GdalRaster::createRaster( cached_ref, categ );
00292   }
00293 }
00294 
00295 #ifdef MPI_FOUND
00296 void
00297 WcsProxyRaster::createRaster( const string& output_file, const string& file, const MapFormat& format) {
00298 
00299   std::string msg = "Method createRaster() not available to create writable WCS rasters.\n";
00300   Log::instance()->error( msg.c_str() );
00301   throw RasterException( msg.c_str() );
00302 }
00303 
00304 #else
00305 void
00306 WcsProxyRaster::createRaster( const string& file, const MapFormat& format) {
00307 
00308   std::string msg = "Method createRaster() not available to create writable WCS rasters.\n";
00309   Log::instance()->warn( msg.c_str() );
00310   throw RasterException( msg.c_str() );
00311 }
00312 #endif
00313 
00314 /***********/
00315 /*** put ***/
00316 int
00317 WcsProxyRaster::put( Coord px, Coord py, Scalar val )
00318 {
00319   std::string msg = "Method put() not available for WCS rasters.\n";
00320   Log::instance()->warn( msg.c_str() );
00321   throw RasterException( msg.c_str() );
00322 }
00323 
00324 /***********/
00325 /*** put ***/
00326 int
00327 WcsProxyRaster::put( Coord px, Coord py )
00328 {
00329   std::string msg = "Method put() not available for WCS rasters.\n";
00330   Log::instance()->warn( msg.c_str() );
00331   throw RasterException( msg.c_str() );
00332 }
00333 
00334 /**************/
00335 /*** finish ***/
00336 void 
00337 WcsProxyRaster::finish()
00338 {
00339   std::string msg = "Method finish() not available for WCS rasters.\n";
00340   Log::instance()->warn( msg.c_str() );
00341   throw RasterException( msg.c_str() );
00342 }
00343 
00344 /*********************/
00345 /*** delete Raster ***/
00346 int
00347 WcsProxyRaster::deleteRaster()
00348 {
00349   std::string msg = "Method deleteRaster() not available for WCS rasters.\n";
00350   Log::instance()->warn( msg.c_str() );
00351   throw RasterException( msg.c_str() );
00352 }