BESUncompressManager.cc

Go to the documentation of this file.
00001 // BESUncompressManager.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 // 
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025  
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #include <sstream>
00034 
00035 using std::istringstream ;
00036 
00037 #include "BESUncompressManager.h"
00038 #include "BESUncompressGZ.h"
00039 #include "BESUncompressBZ2.h"
00040 #include "BESUncompressZ.h"
00041 #include "BESCache.h"
00042 #include "BESInternalError.h"
00043 #include "BESDebug.h"
00044 #include "TheBESKeys.h"
00045 
00046 BESUncompressManager *BESUncompressManager::_instance = 0 ;
00047 
00057 BESUncompressManager::BESUncompressManager()
00058 {
00059     add_method( "gz", BESUncompressGZ::uncompress ) ;
00060     add_method( "bz2", BESUncompressBZ2::uncompress ) ;
00061     add_method( "z", BESUncompressZ::uncompress ) ;
00062 
00063     bool found = false ;
00064     string key = "BES.Uncompress.Retry" ;
00065     string val ;
00066     TheBESKeys::TheKeys()->get_value( key, val, found ) ;
00067     if( !found || val.empty() )
00068     {
00069         _retry = 2000 ;
00070     }
00071     else
00072     {
00073         istringstream is( val ) ;
00074         is >> _retry ;
00075     }
00076 
00077     key = "BES.Uncompress.NumTries" ;
00078     val = "" ;
00079     TheBESKeys::TheKeys()->get_value( key, val, found ) ;
00080     if( !found || val.empty() )
00081     {
00082         _num_tries = 10 ;
00083     }
00084     else
00085     {
00086         istringstream is( val ) ;
00087         is >> _num_tries ;
00088     }
00089 }
00090 
00100 bool
00101 BESUncompressManager::add_method( const string &name,
00102                                   p_bes_uncompress method )
00103 {
00104     BESUncompressManager::UCIter i ;
00105     i = _uncompress_list.find( name ) ;
00106     if( i == _uncompress_list.end() )
00107     {
00108         _uncompress_list[name] = method ;
00109         return true ;
00110     }
00111     return false ;
00112 }
00113 
00122 bool
00123 BESUncompressManager::remove_method( const string &name )
00124 {
00125     BESUncompressManager::UIter i ;
00126     i = _uncompress_list.find( name ) ;
00127     if( i != _uncompress_list.end() )
00128     {
00129         _uncompress_list.erase( i ) ;
00130         return true ;
00131     }
00132     return false ;
00133 }
00134 
00143 p_bes_uncompress
00144 BESUncompressManager::find_method( const string &name )
00145 {
00146     BESUncompressManager::UCIter i ;
00147     i = _uncompress_list.find( name ) ;
00148     if( i != _uncompress_list.end() )
00149     {
00150         return (*i).second ;
00151     }
00152     return 0 ;
00153 }
00154 
00160 string
00161 BESUncompressManager::get_method_names()
00162 {
00163     string ret ;
00164     bool first_name = true ;
00165     BESUncompressManager::UCIter i = _uncompress_list.begin() ;
00166     for( ; i != _uncompress_list.end(); i++ )
00167     {
00168         if( !first_name )
00169             ret += ", " ;
00170         ret += (*i).first ;
00171         first_name = false ;
00172     }
00173     return ret ;
00174 }
00175 
00212 bool
00213 BESUncompressManager::uncompress( const string &src, string &target,
00214                                   BESCache &cache )
00215 {
00216     BESDEBUG( "bes", "BESUncompressManager::uncompress - src = " << src << endl ) ;
00217     string::size_type dot = src.rfind( "." ) ;
00218     if( dot != string::npos )
00219     {
00220         string ext = src.substr( dot+1, src.length() - dot ) ;
00221         // Why fold the extension to lowercase? jhrg 5/9/07
00222         // The extension (Z, gz, bz2, GZ, BZ2, z) is used to determine which
00223         // uncompression engine to use. It is compared to the list, which is
00224         // all lower case. pcw 2/22/08
00225         for( int i = 0; i < ext.length(); i++ )
00226         {
00227             ext[i] = tolower( ext[i] ) ;
00228         }
00229 
00230         // if we find the method for this file then use it. If we don't find
00231         // it then assume that the file is not compressed and simply return
00232         // the src file at the end of the method.
00233         p_bes_uncompress p = find_method( ext ) ;
00234         if( p )
00235         {
00236             // the file is compressed so we either need to uncompress it or
00237             // we need to tell if it is already cached. To do this, lock the
00238             // cache so no one else can do anything
00239             if( cache.lock( _retry, _num_tries ) )
00240             {
00241                 try
00242                 {
00243                     // before calling uncompress on the file, see if the file
00244                     // has already been cached. If it has, then simply return
00245                     // the target, no need to cache.
00246                     BESDEBUG( "bes", "BESUncompressManager::uncompress - is cached? " << src << endl ) ;
00247                     if( cache.is_cached( src, target ) )
00248                     {
00249                         BESDEBUG( "bes", "BESUncompressManager::uncompress - "  << "is cached " << target << endl ) ;
00250                         cache.unlock() ;
00251                         return true ;
00252                     }
00253 
00254                     // the file is not cached, so we need to uncompress the
00255                     // file.  First determine if there is enough space in
00256                     // the cache to uncompress the file
00257                     BESDEBUG( "bes", "BESUncompressManager::uncompress - " << "purging cache" << endl ) ;
00258                     cache.purge() ;
00259 
00260                     // Now that we have some room ... uncompress the file
00261                     BESDEBUG( "bes", "BESUncompressManager::uncompress - "
00262                                      << "uncompress to " << target
00263                                      << " using " << ext << " uncompression"
00264                                      << endl ) ;
00265 
00266                     // we are now done in the cahce, unlock it
00267                     cache.unlock() ;
00268 
00269                     p( src, target ) ;
00270                     return true ;
00271                 }
00272                 catch( BESError & )
00273                 {
00274                     // a problem in the cache, unlock it and re-throw the
00275                     // exception
00276                     cache.unlock() ;
00277                     throw ;
00278                 }
00279                 catch( ... )
00280                 {
00281                     // an unknown problem in the cache, unlock it and throw a
00282                     // BES exception
00283                     cache.unlock() ;
00284                     string err = (string)"Problem working with the cache, "
00285                                  + "unknow error" ;
00286                     throw BESInternalError( err, __FILE__,__LINE__);
00287                 }
00288             }
00289             else
00290             {
00291                 string err = "Unable to lock the cache " 
00292                              + cache.cache_dir() ;
00293                 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00294             }
00295         }
00296         else
00297         {
00298             BESDEBUG( "bes", "BESUncompressManager::uncompress - not compressed " << endl ) ;
00299         }
00300     }
00301     else
00302     {
00303         BESDEBUG( "bes", "BESUncompressmanager::uncompress - not file extension" << endl ) ;
00304 #if 0
00305         // This could just mean that there is a README file here, so just
00306         // return the src file name and let the system run its course.
00307         string err = "Unable to determine type of file from "
00308                      + src ;
00309         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00310 #endif
00311     }
00312 
00313     return false ;
00314 }
00315 
00323 void
00324 BESUncompressManager::dump( ostream &strm ) const
00325 {
00326     strm << BESIndent::LMarg << "BESUncompressManager::dump - ("
00327                              << (void *)this << ")" << endl ;
00328     BESIndent::Indent() ;
00329     if( _uncompress_list.size() )
00330     {
00331         strm << BESIndent::LMarg << "registered uncompression methods:" << endl;
00332         BESIndent::Indent() ;
00333         BESUncompressManager::UCIter i = _uncompress_list.begin() ;
00334         BESUncompressManager::UCIter ie = _uncompress_list.end() ;
00335         for( ; i != ie; i++ )
00336         {
00337             strm << BESIndent::LMarg << (*i).first << endl ;
00338         }
00339         BESIndent::UnIndent() ;
00340     }
00341     else
00342     {
00343         strm << BESIndent::LMarg << "registered uncompress methods: none" << endl ;
00344     }
00345     BESIndent::UnIndent() ;
00346 }
00347 
00348 BESUncompressManager *
00349 BESUncompressManager::TheManager()
00350 {
00351     if( _instance == 0 )
00352     {
00353         _instance = new BESUncompressManager ;
00354     }
00355     return _instance ;
00356 }
Generated by  doxygen 1.6.2-20100208