OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESCatalogUtils.cc
Go to the documentation of this file.
00001 // BESCatalogUtils.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 "config.h"
00034 
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037 #include <dirent.h>
00038 
00039 #include <iostream>
00040 using std::cout ;
00041 using std::endl ;
00042 
00043 #include "BESCatalogUtils.h"
00044 #include "TheBESKeys.h"
00045 #include "BESInternalError.h"
00046 #include "BESSyntaxUserError.h"
00047 #include "BESNotFoundError.h"
00048 #include "BESRegex.h"
00049 #include "BESUtil.h"
00050 
00051 map<string, BESCatalogUtils *> BESCatalogUtils::_instances ;
00052 
00053 BESCatalogUtils::
00054 BESCatalogUtils( const string &n )
00055     : _follow_syms( false )
00056 {
00057     string key = "BES.Catalog." + n + ".RootDirectory" ;
00058     bool found = false ;
00059     TheBESKeys::TheKeys()->get_value( key, _root_dir, found ) ;
00060     if( !found || _root_dir == "" )
00061     {
00062         string s = key + " not defined in BES configuration file" ;
00063         throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
00064     }
00065     DIR *dip = opendir( _root_dir.c_str() ) ;
00066     if( dip == NULL )
00067     {
00068         string serr = "BESCatalogDirectory - root directory "
00069                       + _root_dir + " does not exist" ;
00070         throw BESNotFoundError( serr, __FILE__, __LINE__ ) ;
00071     }
00072     closedir( dip ) ;
00073 
00074     found = false ;
00075     key = (string)"BES.Catalog." + n + ".Exclude" ;
00076     vector<string> vals ;
00077     TheBESKeys::TheKeys()->get_values( key, vals, found ) ;
00078     vector<string>::iterator ei = vals.begin() ;
00079     vector<string>::iterator ee = vals.end() ;
00080     for( ; ei != ee; ei++ )
00081     {
00082         string e_str = (*ei) ;
00083         if( !e_str.empty() && e_str != ";" )
00084             BESUtil::explode( ';', e_str, _exclude ) ;
00085     }
00086 
00087     key = (string)"BES.Catalog." + n + ".Include" ;
00088     vals.clear() ;
00089     TheBESKeys::TheKeys()->get_values( key, vals, found ) ;
00090     vector<string>::iterator ii = vals.begin() ;
00091     vector<string>::iterator ie = vals.end() ;
00092     for( ; ii != ie; ii++ )
00093     {
00094         string i_str = (*ii) ;
00095         if( !i_str.empty() && i_str != ";" )
00096             BESUtil::explode( ';', i_str, _include ) ;
00097     }
00098 
00099     key = "BES.Catalog." + n + ".TypeMatch" ;
00100     list<string> match_list ;
00101     vals.clear() ;
00102     TheBESKeys::TheKeys()->get_values( key, vals, found ) ;
00103     if( !found || vals.size() == 0 )
00104     {
00105         string s = key + " not defined in key file" ;
00106         throw BESInternalError( s, __FILE__, __LINE__ ) ;
00107     }
00108     vector<string>::iterator vi = vals.begin() ;
00109     vector<string>::iterator ve = vals.end() ;
00110     for( ; vi != ve; vi++ )
00111     {
00112         BESUtil::explode( ';', (*vi), match_list ) ;
00113     }
00114 
00115     list<string>::iterator mli = match_list.begin() ;
00116     list<string>::iterator mle = match_list.end() ;
00117     for( ; mli != mle; mli++ )
00118     {
00119         if( !((*mli).empty()) && *(mli) != ";" )
00120         {
00121             list<string> amatch ;
00122             BESUtil::explode( ':', (*mli), amatch ) ;
00123             if( amatch.size() != 2 )
00124             {
00125                 string s = (string)"Catalog type match malformed, "
00126                            + "looking for type:regexp;[type:regexp;]" ;
00127                 throw BESInternalError( s, __FILE__, __LINE__ ) ;
00128             }
00129             list<string>::iterator ami = amatch.begin() ;
00130             type_reg newval ;
00131             newval.type = (*ami) ;
00132             ami++ ;
00133             newval.reg = (*ami) ;
00134             _match_list.push_back( newval ) ;
00135         }
00136     }
00137 
00138     key = (string)"BES.Catalog." + n + ".FollowSymLinks" ;
00139     string s_str ;
00140     TheBESKeys::TheKeys()->get_value( key, s_str, found ) ;
00141     s_str = BESUtil::lowercase( s_str ) ;
00142     if( s_str == "yes" || s_str == "on" || s_str == "true" )
00143     {
00144         _follow_syms = true ;
00145     }
00146 }
00147 
00148 bool
00149 BESCatalogUtils::include( const string &inQuestion ) const
00150 {
00151     bool toInclude = false ;
00152 
00153     // First check the file against the include list. If the file should be
00154     // included then check the exclude list to see if there are exceptions
00155     // to the include list.
00156     if( _include.size() == 0 )
00157     {
00158         toInclude = true ;
00159     }
00160     else
00161     {
00162         list<string>::const_iterator i_iter = _include.begin() ;
00163         list<string>::const_iterator i_end = _include.end() ;
00164         for( ; i_iter != i_end; i_iter++ )
00165         {
00166             string reg = *i_iter ;
00167             if( !reg.empty() )
00168             {
00169                 try
00170                 {
00171                     // must match exactly, meaing result is = to length of string
00172                     // in question
00173                     BESRegex reg_expr( reg.c_str() ) ;
00174                     if( reg_expr.match( inQuestion.c_str(),
00175                                         inQuestion.length() ) ==
00176                         static_cast<int>(inQuestion.length()) )
00177                     {
00178                         toInclude = true ;
00179                     }
00180                 }
00181                 catch( BESError &e )
00182                 {
00183                     string serr = (string)"Unable to get catalog information, "
00184                                   + "malformed Catalog Include parameter "
00185                                   + "in bes configuration file around " 
00186                                   + reg + ": " + e.get_message() ;
00187                     throw BESInternalError( serr, __FILE__, __LINE__ ) ;
00188                 }
00189             }
00190         }
00191     }
00192 
00193     if( toInclude == true )
00194     {
00195         if( exclude( inQuestion ) )
00196         {
00197             toInclude = false ;
00198         }
00199     }
00200 
00201     return toInclude ;
00202 }
00203 
00204 bool
00205 BESCatalogUtils::exclude( const string &inQuestion ) const
00206 {
00207     list<string>::const_iterator e_iter = _exclude.begin() ;
00208     list<string>::const_iterator e_end = _exclude.end() ;
00209     for( ; e_iter != e_end; e_iter++ )
00210     {
00211         string reg = *e_iter ;
00212         if( !reg.empty() )
00213         {
00214             try
00215             {
00216                 BESRegex reg_expr( reg.c_str() ) ;
00217                 if( reg_expr.match( inQuestion.c_str(), inQuestion.length() ) ==
00218                     static_cast<int>(inQuestion.length()) )
00219                 {
00220                     return true ;
00221                 }
00222             }
00223             catch( BESError &e )
00224             {
00225                 string serr = (string)"Unable to get catalog information, "
00226                               + "malformed Catalog Exclude parameter " 
00227                               + "in bes configuration file around " 
00228                               + reg + ": " + e.get_message() ;
00229                 throw BESInternalError( serr, __FILE__, __LINE__ ) ;
00230             }
00231         }
00232     }
00233     return false ;
00234 }
00235 
00236 BESCatalogUtils::match_citer
00237 BESCatalogUtils::match_list_begin() const
00238 {
00239     return _match_list.begin() ;
00240 }
00241 
00242 BESCatalogUtils::match_citer
00243 BESCatalogUtils::match_list_end() const
00244 {
00245     return _match_list.end() ;
00246 }
00247 
00248 void
00249 BESCatalogUtils::dump( ostream &strm ) const
00250 {
00251     strm << BESIndent::LMarg << "BESCatalogUtils::dump - ("
00252                              << (void *)this << ")" << endl ;
00253     BESIndent::Indent() ;
00254 
00255     strm << BESIndent::LMarg << "root directory: " << _root_dir << endl ;
00256 
00257     if( _include.size() )
00258     {
00259         strm << BESIndent::LMarg << "include list:" << endl ;
00260         BESIndent::Indent() ;
00261         list<string>::const_iterator i_iter = _include.begin() ;
00262         list<string>::const_iterator i_end = _include.end() ;
00263         for( ; i_iter != i_end; i_iter++ )
00264         {
00265             if( !(*i_iter).empty() )
00266             {
00267                 strm << BESIndent::LMarg << *i_iter << endl ;
00268             }
00269         }
00270         BESIndent::UnIndent() ;
00271     }
00272     else
00273     {
00274         strm << BESIndent::LMarg << "include list: empty" << endl ;
00275     }
00276 
00277     if( _exclude.size() )
00278     {
00279         strm << BESIndent::LMarg << "exclude list:" << endl ;
00280         BESIndent::Indent() ;
00281         list<string>::const_iterator e_iter = _exclude.begin() ;
00282         list<string>::const_iterator e_end = _exclude.end() ;
00283         for( ; e_iter != e_end; e_iter++ )
00284         {
00285             if( !(*e_iter).empty() )
00286             {
00287                 strm << BESIndent::LMarg << *e_iter << endl ;
00288             }
00289         }
00290         BESIndent::UnIndent() ;
00291     }
00292     else
00293     {
00294         strm << BESIndent::LMarg << "exclude list: empty" << endl ;
00295     }
00296 
00297     if( _match_list.size() )
00298     {
00299         strm << BESIndent::LMarg << "type matches:" << endl ;
00300         BESIndent::Indent() ;
00301         BESCatalogUtils::match_citer i = _match_list.begin() ;
00302         BESCatalogUtils::match_citer ie = _match_list.end() ;
00303         for( ; i != ie; i++ )
00304         {
00305             type_reg match = (*i) ;
00306             strm << BESIndent::LMarg << match.type << " : "
00307                                      << match.reg << endl ;
00308         }
00309         BESIndent::UnIndent() ;
00310     }
00311     else
00312     {
00313         strm << BESIndent::LMarg << "    type matches: empty" << endl ;
00314     }
00315 
00316     if( _follow_syms )
00317     {
00318         strm << BESIndent::LMarg << "    follow symbolic links: on" << endl ;
00319     }
00320     else
00321     {
00322         strm << BESIndent::LMarg << "    follow symbolic links: off" << endl ;
00323     }
00324 
00325     BESIndent::UnIndent() ;
00326 }
00327 
00328 const BESCatalogUtils *
00329 BESCatalogUtils::Utils( const string &cat_name )
00330 {
00331     BESCatalogUtils *utils = BESCatalogUtils::_instances[cat_name] ;
00332     if( !utils )
00333     {
00334         utils = new BESCatalogUtils( cat_name );
00335         BESCatalogUtils::_instances[cat_name] = utils ;
00336     }
00337     return utils ;
00338 }
00339