BESInterface.cc

Go to the documentation of this file.
00001 // BESInterface.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,2005 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 <string>
00036 #include <sstream>
00037 #include <iostream>
00038 
00039 #if HAVE_UNISTD_H
00040 #include <unistd.h>
00041 #endif
00042 
00043 using std::string;
00044 using std::ostringstream;
00045 using std::bad_alloc;
00046 using std::cout;
00047 
00048 #include "BESInterface.h"
00049 
00050 #include "TheBESKeys.h"
00051 #include "BESResponseHandler.h"
00052 #include "BESAggFactory.h"
00053 #include "BESAggregationServer.h"
00054 #include "BESReporterList.h"
00055 
00056 #include "BESExceptionManager.h"
00057 
00058 #include "BESDataNames.h"
00059 
00060 #include "BESDebug.h"
00061 #include "BESInternalError.h"
00062 #include "BESInternalFatalError.h"
00063 
00064 #include "BESLog.h"
00065 
00066 list < p_bes_init > BESInterface::_init_list;
00067 list < p_bes_end > BESInterface::_end_list;
00068 
00069 BESInterface::BESInterface( ostream *output_stream )
00070 :  _transmitter(0)
00071 {
00072     if( !output_stream )
00073     {
00074         string err = "output stream must be set in order to output responses" ;
00075         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00076     }
00077     _dhi.set_output_stream( output_stream ) ;
00078 }
00079 
00080 BESInterface::~BESInterface()
00081 {
00082 }
00083 
00116 int
00117 BESInterface::execute_request( const string &from )
00118 {
00119     _dhi.data[REQUEST_FROM] = from ;
00120 
00121     pid_t thepid = getpid() ;
00122     ostringstream ss ;
00123     ss << thepid ;
00124     _dhi.data[SERVER_PID] = ss.str() ;
00125 
00126     *(BESLog::TheLog()) << _dhi.data[SERVER_PID]
00127                         << " from " << _dhi.data[REQUEST_FROM]
00128                         << " [" << _dhi.data[DATA_REQUEST] << "]"
00129                         << endl ;
00130 
00131     int status = 0;
00132 
00133     // We split up the calls for the reason that if we catch an
00134     // exception during the initialization, building, execution, or response
00135     // transmit of the request then we can transmit the exception/error
00136     // information.
00137     try {
00138         initialize();
00139         validate_data_request();
00140         build_data_request_plan();
00141         execute_data_request_plan();
00142         invoke_aggregation();
00143         transmit_data();
00144     }
00145     catch( BESError & ex )
00146     {
00147         return exception_manager( ex ) ;
00148     }
00149     catch( bad_alloc & )
00150     {
00151         string serr = "BES out of memory" ;
00152         BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
00153         return exception_manager( ex ) ;
00154     }
00155     catch(...) {
00156         string serr = "An undefined exception has been thrown" ;
00157         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00158         return exception_manager( ex ) ;
00159     }
00160 
00161     return finish( status ) ;
00162 }
00163 
00164 int
00165 BESInterface::finish( int status )
00166 {
00167     try
00168     {
00169         // if there was an error duriing initialization, validation,
00170         // execution or transmit of the response then we need to transmit
00171         // the error information.
00172         if( _dhi.error_info )
00173         {
00174             transmit_data();
00175             delete _dhi.error_info ;
00176             _dhi.error_info = 0 ;
00177         }
00178     }
00179     catch( BESError &ex )
00180     {
00181         status = exception_manager( ex ) ;
00182     }
00183     catch( bad_alloc & )
00184     {
00185         string serr = "BES out of memory" ;
00186         BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
00187         status = exception_manager( ex ) ;
00188     }
00189     catch(...)
00190     {
00191         string serr = "An undefined exception has been thrown" ;
00192         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00193         status = exception_manager( ex ) ;
00194     }
00195 
00196     // If there is error information then the transmit, log, report or end
00197     // failed, so just print the error information
00198     if( _dhi.error_info )
00199     {
00200         _dhi.error_info->print( cout ) ;
00201         delete _dhi.error_info ;
00202         _dhi.error_info = 0 ;
00203     }
00204 
00205     // if there is a problem with the rest of these steps then all we will
00206     // do is log it to the BES log file and not handle the exception with
00207     // the exception manager.
00208     try
00209     {
00210         log_status();
00211     }
00212     catch( BESError &ex )
00213     {
00214         (*BESLog::TheLog()) << "Problem logging status: " << ex.get_message()
00215                             << endl ;
00216     }
00217     catch( ... )
00218     {
00219         (*BESLog::TheLog()) << "Unknown problem logging status" << endl ;
00220     }
00221 
00222     try
00223     {
00224         report_request();
00225     }
00226     catch( BESError &ex )
00227     {
00228         (*BESLog::TheLog()) << "Problem reporting request: " << ex.get_message()
00229                             << endl ;
00230     }
00231     catch( ... )
00232     {
00233         (*BESLog::TheLog()) << "Unknown problem reporting request" << endl ;
00234     }
00235 
00236     try
00237     {
00238         end_request();
00239     }
00240     catch( BESError &ex )
00241     {
00242         (*BESLog::TheLog()) << "Problem ending request: " << ex.get_message()
00243                             << endl ;
00244     }
00245     catch( ... )
00246     {
00247         (*BESLog::TheLog()) << "Unknown problem ending request" << endl ;
00248     }
00249 
00250     return status ;
00251 }
00252 
00253 int
00254 BESInterface::finish_with_error( int status )
00255 {
00256     if( !_dhi.error_info )
00257     {
00258         // there wasn't an error ... so now what?
00259         string serr = "Finish_with_error called with no error object" ;
00260         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00261         status = exception_manager( ex ) ;
00262     }
00263 
00264     return finish( status ) ;
00265 }
00266 
00267 void
00268 BESInterface::add_init_callback(p_bes_init init)
00269 {
00270     _init_list.push_back(init);
00271 }
00272 
00278 void
00279 BESInterface::initialize()
00280 {
00281     BESDEBUG("bes", "Initializing request: " << _dhi.data[DATA_REQUEST] << " ... ")
00282     bool do_continue = true;
00283     init_iter i = _init_list.begin();
00284     
00285     for( ; i != _init_list.end() && do_continue == true; i++ )
00286     {
00287         p_bes_init p = *i ;
00288         do_continue = p( _dhi ) ;
00289     }
00290     
00291     if( !do_continue )
00292     {
00293         BESDEBUG("bes", "FAILED" << endl)
00294         string se = "Initialization callback failed, exiting";
00295         throw BESInternalError( se, __FILE__, __LINE__ ) ;
00296     }
00297     else
00298     {
00299         BESDEBUG("bes", "OK" << endl)
00300     }
00301 }
00302 
00305 void
00306 BESInterface::validate_data_request()
00307 {
00308 }
00309 
00318 void
00319 BESInterface::build_data_request_plan()
00320 {
00321 }
00322 
00336 void
00337 BESInterface::execute_data_request_plan()
00338 {
00339     BESDEBUG("bes", "Executing request: " << _dhi.data[DATA_REQUEST] << " ... ")
00340     BESResponseHandler *rh = _dhi.response_handler ;
00341     if( rh )
00342     {
00343         rh->execute( _dhi ) ;
00344     }
00345     else
00346     {
00347         BESDEBUG("bes", "FAILED" << endl)
00348         string se = "The response handler \"" + _dhi.action
00349                     + "\" does not exist" ;
00350         throw BESInternalError( se, __FILE__, __LINE__ ) ;
00351     }
00352     BESDEBUG("bes", "OK" << endl)
00353 }
00354 
00357 void
00358 BESInterface::invoke_aggregation()
00359 {
00360     if( _dhi.data[AGG_CMD] != "" )
00361     {
00362         BESDEBUG("bes", "aggregating with: " << _dhi.data[AGG_CMD] << " ... ")
00363         BESAggregationServer *agg =
00364             BESAggFactory::TheFactory()->find_handler(_dhi.
00365                                                       data[AGG_HANDLER]);
00366         if( agg )
00367         {
00368             agg->aggregate( _dhi ) ;
00369         }
00370         else
00371         {
00372             BESDEBUG("bes", "FAILED" << endl)
00373             string se = "The aggregation handler " + _dhi.data[AGG_HANDLER]
00374                 + "does not exist" ;
00375             throw BESInternalError( se, __FILE__, __LINE__ ) ;
00376         }
00377         BESDEBUG("bes", "OK" << endl)
00378     }
00379 }
00380 
00394 void
00395 BESInterface::transmit_data()
00396 {
00397     BESDEBUG("bes", "Transmitting request: " << _dhi.data[DATA_REQUEST] << endl)
00398     if (_transmitter)
00399     {
00400         if( _dhi.error_info )
00401         {
00402             BESDEBUG( "bes", "  transmitting error info using transmitter ... " )
00403             _dhi.error_info->transmit( _transmitter, _dhi ) ;
00404         }
00405         else if( _dhi.response_handler )
00406         {
00407             BESDEBUG( "bes", "  transmitting response using transmitter ... " )
00408             _dhi.response_handler->transmit( _transmitter, _dhi ) ;
00409         }
00410     }
00411     else
00412     {
00413         if( _dhi.error_info )
00414         {
00415             BESDEBUG( "bes", "  transmitting error info using cout ... " )
00416             _dhi.error_info->print( cout ) ;
00417         }
00418         else
00419         {
00420             BESDEBUG( "bes", "  Unable to transmit the response ... FAILED " )
00421             string err = "Unable to transmit the response, no transmitter" ;
00422             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00423         }
00424     }
00425     BESDEBUG("bes", "OK" << endl)
00426 }
00427 
00430 void
00431 BESInterface::log_status()
00432 {
00433 }
00434 
00446 void
00447 BESInterface::report_request()
00448 {
00449     BESDEBUG("bes", "Reporting on request: " << _dhi.
00450              data[DATA_REQUEST] << " ... ")
00451         BESReporterList::TheList()->report(_dhi);
00452     BESDEBUG("bes", "OK" << endl)
00453 }
00454 
00455 void
00456 BESInterface::add_end_callback(p_bes_end end)
00457 {
00458     _end_list.push_back(end);
00459 }
00460 
00466 void
00467 BESInterface::end_request()
00468 {
00469     BESDEBUG("bes", "Ending request: " << _dhi.data[DATA_REQUEST] << " ... ")
00470     end_iter i = _end_list.begin();
00471     for (; i != _end_list.end(); i++) {
00472         p_bes_end p = *i;
00473         p(_dhi);
00474     }
00475 
00476     // now clean up any containers that were used in the request, release
00477     // the resource
00478     _dhi.first_container() ;
00479     while( _dhi.container )
00480     {
00481         _dhi.container->release() ;
00482         _dhi.next_container() ;
00483     }
00484 
00485     BESDEBUG("bes", "OK" << endl)
00486 }
00487 
00490 void
00491 BESInterface::clean()
00492 {
00493     if (_dhi.response_handler)
00494         delete _dhi.response_handler;
00495     _dhi.response_handler = 0;
00496 }
00497 
00510 int
00511 BESInterface::exception_manager( BESError &e )
00512 {
00513     return BESExceptionManager::TheEHM()->handle_exception( e, _dhi ) ;
00514 }
00515 
00524 void
00525 BESInterface::dump(ostream & strm) const
00526 {
00527     strm << BESIndent::LMarg << "BESInterface::dump - ("
00528         << (void *) this << ")" << endl;
00529     BESIndent::Indent();
00530 
00531     if (_init_list.size()) {
00532         strm << BESIndent::LMarg << "termination functions:" << endl;
00533         BESIndent::Indent();
00534         init_iter i = _init_list.begin();
00535         for (; i != _init_list.end(); i++) {
00536             strm << BESIndent::LMarg << (void *) (*i) << endl;
00537         }
00538         BESIndent::UnIndent();
00539     } else {
00540         strm << BESIndent::LMarg << "termination functions: none" << endl;
00541     }
00542 
00543     if (_end_list.size()) {
00544         strm << BESIndent::LMarg << "termination functions:" << endl;
00545         BESIndent::Indent();
00546         end_iter i = _end_list.begin();
00547         for (; i != _end_list.end(); i++) {
00548             strm << BESIndent::LMarg << (void *) (*i) << endl;
00549         }
00550         BESIndent::UnIndent();
00551     } else {
00552         strm << BESIndent::LMarg << "termination functions: none" << endl;
00553     }
00554 
00555     strm << BESIndent::LMarg << "data handler interface:" << endl;
00556     BESIndent::Indent();
00557     _dhi.dump(strm);
00558     BESIndent::UnIndent();
00559 
00560     if (_transmitter) {
00561         strm << BESIndent::LMarg << "transmitter:" << endl;
00562         BESIndent::Indent();
00563         _transmitter->dump(strm);
00564         BESIndent::UnIndent();
00565     } else {
00566         strm << BESIndent::LMarg << "transmitter: not set" << endl;
00567     }
00568     BESIndent::UnIndent();
00569 }

Generated on Tue Mar 4 23:13:35 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1