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-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 <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     : _strm( output_stream ),
00071       _transmitter( 0 )
00072 {
00073     if( !output_stream )
00074     {
00075         string err = "output stream must be set in order to output responses" ;
00076         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00077     }
00078 }
00079 
00080 BESInterface::~BESInterface()
00081 {
00082 }
00083 
00116 int
00117 BESInterface::execute_request( const string &from )
00118 {
00119     if( !_dhi )
00120     {
00121         string err = "DataHandlerInterface can not be null" ;
00122         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00123     }
00124     _dhi->set_output_stream( _strm ) ;
00125     _dhi->data[REQUEST_FROM] = from ;
00126 
00127     pid_t thepid = getpid() ;
00128     ostringstream ss ;
00129     ss << thepid ;
00130     _dhi->data[SERVER_PID] = ss.str() ;
00131 
00132     int status = 0;
00133 
00134     // We split up the calls for the reason that if we catch an
00135     // exception during the initialization, building, execution, or response
00136     // transmit of the request then we can transmit the exception/error
00137     // information.
00138     try {
00139         initialize();
00140 
00141         *(BESLog::TheLog()) << _dhi->data[SERVER_PID]
00142                             << " from " << _dhi->data[REQUEST_FROM]
00143                             << " [" << _dhi->data[DATA_REQUEST] << "]"
00144                             << endl ;
00145 
00146         validate_data_request();
00147         build_data_request_plan() ;
00148         execute_data_request_plan();
00149         /* These two functions are now being called inside
00150          * execute_data_request_plan as they are really a part of executing
00151          * the request and not separate.
00152         invoke_aggregation();
00153         transmit_data();
00154         */
00155         _dhi->executed = true ;
00156     }
00157     catch( BESError & ex )
00158     {
00159         return exception_manager( ex ) ;
00160     }
00161     catch( bad_alloc & )
00162     {
00163         string serr = "BES out of memory" ;
00164         BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
00165         return exception_manager( ex ) ;
00166     }
00167     catch(...) {
00168         string serr = "An undefined exception has been thrown" ;
00169         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00170         return exception_manager( ex ) ;
00171     }
00172 
00173     return finish( status ) ;
00174 }
00175 
00176 int
00177 BESInterface::finish( int status )
00178 {
00179     try
00180     {
00181         // if there was an error duriing initialization, validation,
00182         // execution or transmit of the response then we need to transmit
00183         // the error information. Once printed, delete the error
00184         // information since we are done with it.
00185         if( _dhi->error_info )
00186         {
00187             transmit_data();
00188             delete _dhi->error_info ;
00189             _dhi->error_info = 0 ;
00190         }
00191     }
00192     catch( BESError &ex )
00193     {
00194         status = exception_manager( ex ) ;
00195     }
00196     catch( bad_alloc & )
00197     {
00198         string serr = "BES out of memory" ;
00199         BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
00200         status = exception_manager( ex ) ;
00201     }
00202     catch(...)
00203     {
00204         string serr = "An undefined exception has been thrown" ;
00205         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00206         status = exception_manager( ex ) ;
00207     }
00208 
00209     // If there is error information then the transmit of the error failed,
00210     // print it to standard out. Once printed, delete the error
00211     // information since we are done with it.
00212     if( _dhi->error_info )
00213     {
00214         _dhi->error_info->print( cout ) ;
00215         delete _dhi->error_info ;
00216         _dhi->error_info = 0 ;
00217     }
00218 
00219     // if there is a problem with the rest of these steps then all we will
00220     // do is log it to the BES log file and not handle the exception with
00221     // the exception manager.
00222     try
00223     {
00224         log_status();
00225     }
00226     catch( BESError &ex )
00227     {
00228         (*BESLog::TheLog()) << "Problem logging status: " << ex.get_message()
00229                             << endl ;
00230     }
00231     catch( ... )
00232     {
00233         (*BESLog::TheLog()) << "Unknown problem logging status" << endl ;
00234     }
00235 
00236     try
00237     {
00238         report_request();
00239     }
00240     catch( BESError &ex )
00241     {
00242         (*BESLog::TheLog()) << "Problem reporting request: " << ex.get_message()
00243                             << endl ;
00244     }
00245     catch( ... )
00246     {
00247         (*BESLog::TheLog()) << "Unknown problem reporting request" << endl ;
00248     }
00249 
00250     try
00251     {
00252         end_request();
00253     }
00254     catch( BESError &ex )
00255     {
00256         (*BESLog::TheLog()) << "Problem ending request: " << ex.get_message()
00257                             << endl ;
00258     }
00259     catch( ... )
00260     {
00261         (*BESLog::TheLog()) << "Unknown problem ending request" << endl ;
00262     }
00263 
00264     return status ;
00265 }
00266 
00267 int
00268 BESInterface::finish_with_error( int status )
00269 {
00270     if( !_dhi->error_info )
00271     {
00272         // there wasn't an error ... so now what?
00273         string serr = "Finish_with_error called with no error object" ;
00274         BESInternalError ex( serr, __FILE__, __LINE__ ) ;
00275         status = exception_manager( ex ) ;
00276     }
00277 
00278     return finish( status ) ;
00279 }
00280 
00281 void
00282 BESInterface::add_init_callback(p_bes_init init)
00283 {
00284     _init_list.push_back(init);
00285 }
00286 
00292 void
00293 BESInterface::initialize()
00294 {
00295     BESDEBUG("bes", "Initializing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl )
00296     bool do_continue = true;
00297     init_iter i = _init_list.begin();
00298     
00299     for( ; i != _init_list.end() && do_continue == true; i++ )
00300     {
00301         p_bes_init p = *i ;
00302         do_continue = p( *_dhi ) ;
00303     }
00304     
00305     if( !do_continue )
00306     {
00307         BESDEBUG("bes", "FAILED" << endl)
00308         string se = "Initialization callback failed, exiting";
00309         throw BESInternalError( se, __FILE__, __LINE__ ) ;
00310     }
00311     else
00312     {
00313         BESDEBUG("bes", "OK" << endl)
00314     }
00315 }
00316 
00319 void
00320 BESInterface::validate_data_request()
00321 {
00322 }
00323 
00337 void
00338 BESInterface::execute_data_request_plan()
00339 {
00340     BESDEBUG("bes", "Executing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl )
00341     BESResponseHandler *rh = _dhi->response_handler ;
00342     if( rh )
00343     {
00344         rh->execute( *_dhi ) ;
00345     }
00346     else
00347     {
00348         BESDEBUG("bes", "FAILED" << endl)
00349         string se = "The response handler \"" + _dhi->action
00350                     + "\" does not exist" ;
00351         throw BESInternalError( se, __FILE__, __LINE__ ) ;
00352     }
00353     BESDEBUG("bes", "OK" << endl)
00354 
00355     // Now we need to do the post processing piece of executing the request
00356     invoke_aggregation();
00357 
00358     // And finally, transmit the response of this request
00359     transmit_data();
00360 }
00361 
00364 void
00365 BESInterface::invoke_aggregation()
00366 {
00367     if( _dhi->data[AGG_CMD] != "" )
00368     {
00369         BESDEBUG("bes", "aggregating with: " << _dhi->data[AGG_CMD] << " ...  "<< endl )
00370         BESAggregationServer *agg =
00371             BESAggFactory::TheFactory()->find_handler( _dhi->data[AGG_HANDLER] );
00372         if( agg )
00373         {
00374             agg->aggregate( *_dhi ) ;
00375         }
00376         else
00377         {
00378             BESDEBUG("bes", "FAILED" << endl)
00379             string se = "The aggregation handler " + _dhi->data[AGG_HANDLER]
00380                 + "does not exist" ;
00381             throw BESInternalError( se, __FILE__, __LINE__ ) ;
00382         }
00383         BESDEBUG("bes", "OK" << endl)
00384     }
00385 }
00386 
00400 void
00401 BESInterface::transmit_data()
00402 {
00403     BESDEBUG("bes", "Transmitting request: " << _dhi->data[DATA_REQUEST] << endl)
00404     if (_transmitter)
00405     {
00406         if( _dhi->error_info )
00407         {
00408             BESDEBUG( "bes", "  transmitting error info using transmitter ... " << endl )
00409             _dhi->error_info->transmit( _transmitter, *_dhi ) ;
00410         }
00411         else if( _dhi->response_handler )
00412         {
00413             BESDEBUG( "bes", "  transmitting response using transmitter ...  " << endl )
00414             _dhi->response_handler->transmit( _transmitter, *_dhi ) ;
00415         }
00416     }
00417     else
00418     {
00419         if( _dhi->error_info )
00420         {
00421             BESDEBUG( "bes", "  transmitting error info using cout ... " << endl )
00422             _dhi->error_info->print( cout ) ;
00423         }
00424         else
00425         {
00426             BESDEBUG( "bes", "  Unable to transmit the response ... FAILED " << endl )
00427             string err = "Unable to transmit the response, no transmitter" ;
00428             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00429         }
00430     }
00431     BESDEBUG("bes", "OK" << endl)
00432 }
00433 
00436 void
00437 BESInterface::log_status()
00438 {
00439 }
00440 
00452 void
00453 BESInterface::report_request()
00454 {
00455     BESDEBUG( "bes", "Reporting on request: " << _dhi->data[DATA_REQUEST]
00456                      << " ... " << endl )
00457 
00458     BESReporterList::TheList()->report( *_dhi ) ;
00459 
00460     BESDEBUG( "bes", "OK" << endl )
00461 }
00462 
00463 void
00464 BESInterface::add_end_callback( p_bes_end end )
00465 {
00466     _end_list.push_back( end ) ;
00467 }
00468 
00474 void
00475 BESInterface::end_request()
00476 {
00477     BESDEBUG("bes", "Ending request: " << _dhi->data[DATA_REQUEST] << " ... " << endl )
00478     end_iter i = _end_list.begin();
00479     for( ; i != _end_list.end(); i++ )
00480     {
00481         p_bes_end p = *i ;
00482         p( *_dhi ) ;
00483     }
00484 
00485     // now clean up any containers that were used in the request, release
00486     // the resource
00487     _dhi->first_container() ;
00488     while( _dhi->container )
00489     {
00490         _dhi->container->release() ;
00491         _dhi->next_container() ;
00492     }
00493 
00494     BESDEBUG("bes", "OK" << endl)
00495 }
00496 
00499 void
00500 BESInterface::clean()
00501 {
00502     if( _dhi )
00503         _dhi->clean() ;
00504 }
00505 
00518 int
00519 BESInterface::exception_manager( BESError &e )
00520 {
00521     return BESExceptionManager::TheEHM()->handle_exception( e, *_dhi ) ;
00522 }
00523 
00532 void
00533 BESInterface::dump(ostream & strm) const
00534 {
00535     strm << BESIndent::LMarg << "BESInterface::dump - ("
00536         << (void *) this << ")" << endl;
00537     BESIndent::Indent();
00538 
00539     if (_init_list.size()) {
00540         strm << BESIndent::LMarg << "termination functions:" << endl;
00541         BESIndent::Indent();
00542         init_iter i = _init_list.begin();
00543         for (; i != _init_list.end(); i++) {
00544             strm << BESIndent::LMarg << (void *) (*i) << endl;
00545         }
00546         BESIndent::UnIndent();
00547     } else {
00548         strm << BESIndent::LMarg << "termination functions: none" << endl;
00549     }
00550 
00551     if (_end_list.size()) {
00552         strm << BESIndent::LMarg << "termination functions:" << endl;
00553         BESIndent::Indent();
00554         end_iter i = _end_list.begin();
00555         for (; i != _end_list.end(); i++) {
00556             strm << BESIndent::LMarg << (void *) (*i) << endl;
00557         }
00558         BESIndent::UnIndent();
00559     } else {
00560         strm << BESIndent::LMarg << "termination functions: none" << endl;
00561     }
00562 
00563     strm << BESIndent::LMarg << "data handler interface:" << endl;
00564     BESIndent::Indent();
00565     _dhi->dump(strm);
00566     BESIndent::UnIndent();
00567 
00568     if (_transmitter) {
00569         strm << BESIndent::LMarg << "transmitter:" << endl;
00570         BESIndent::Indent();
00571         _transmitter->dump(strm);
00572         BESIndent::UnIndent();
00573     } else {
00574         strm << BESIndent::LMarg << "transmitter: not set" << endl;
00575     }
00576     BESIndent::UnIndent();
00577 }

Generated on Sat Aug 22 06:06:26 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0