OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESInterface.cc
Go to the documentation of this file.
1 // BESInterface.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include "config.h"
34 
35 #include <string>
36 #include <sstream>
37 #include <iostream>
38 
39 #if HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 
43 using std::string;
44 using std::ostringstream;
45 using std::bad_alloc;
46 using std::cout;
47 
48 #include "BESInterface.h"
49 
50 #include "TheBESKeys.h"
51 #include "BESResponseHandler.h"
52 #include "BESAggFactory.h"
53 #include "BESAggregationServer.h"
54 #include "BESReporterList.h"
55 
56 #include "BESExceptionManager.h"
57 
58 #include "BESDataNames.h"
59 
60 #include "BESDebug.h"
61 #include "BESInternalError.h"
62 #include "BESInternalFatalError.h"
63 
64 #include "BESLog.h"
65 
66 list < p_bes_init > BESInterface::_init_list;
67 list < p_bes_end > BESInterface::_end_list;
68 
69 BESInterface::BESInterface( ostream *output_stream )
70  : _strm( output_stream ),
71  _transmitter( 0 )
72 {
73  if( !output_stream )
74  {
75  string err = "output stream must be set in order to output responses" ;
76  throw BESInternalError( err, __FILE__, __LINE__ ) ;
77  }
78 }
79 
81 {
82 }
83 
116 int
117 BESInterface::execute_request( const string &from )
118 {
119  if( !_dhi )
120  {
121  string err = "DataHandlerInterface can not be null" ;
122  throw BESInternalError( err, __FILE__, __LINE__ ) ;
123  }
124  _dhi->set_output_stream( _strm ) ;
125  _dhi->data[REQUEST_FROM] = from ;
126 
127  pid_t thepid = getpid() ;
128  ostringstream ss ;
129  ss << thepid ;
130  _dhi->data[SERVER_PID] = ss.str() ;
131 
132  int status = 0;
133 
134  // We split up the calls for the reason that if we catch an
135  // exception during the initialization, building, execution, or response
136  // transmit of the request then we can transmit the exception/error
137  // information.
138  try {
139  initialize();
140 
142  << " from " << _dhi->data[REQUEST_FROM]
143  << " request received" << endl ;
144 
148  /* These two functions are now being called inside
149  * execute_data_request_plan as they are really a part of executing
150  * the request and not separate.
151  invoke_aggregation();
152  transmit_data();
153  */
154  _dhi->executed = true ;
155  }
156  catch( BESError & ex )
157  {
158  return exception_manager( ex ) ;
159  }
160  catch( bad_alloc & )
161  {
162  string serr = "BES out of memory" ;
163  BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
164  return exception_manager( ex ) ;
165  }
166  catch(...) {
167  string serr = "An undefined exception has been thrown" ;
168  BESInternalError ex( serr, __FILE__, __LINE__ ) ;
169  return exception_manager( ex ) ;
170  }
171 
172  return finish( status ) ;
173 }
174 
175 int
176 BESInterface::finish( int status )
177 {
178  try
179  {
180  // if there was an error duriing initialization, validation,
181  // execution or transmit of the response then we need to transmit
182  // the error information. Once printed, delete the error
183  // information since we are done with it.
184  if( _dhi->error_info )
185  {
186  transmit_data();
187  delete _dhi->error_info ;
188  _dhi->error_info = 0 ;
189  }
190  }
191  catch( BESError &ex )
192  {
193  status = exception_manager( ex ) ;
194  }
195  catch( bad_alloc & )
196  {
197  string serr = "BES out of memory" ;
198  BESInternalFatalError ex( serr, __FILE__, __LINE__ ) ;
199  status = exception_manager( ex ) ;
200  }
201  catch(...)
202  {
203  string serr = "An undefined exception has been thrown" ;
204  BESInternalError ex( serr, __FILE__, __LINE__ ) ;
205  status = exception_manager( ex ) ;
206  }
207 
208  // If there is error information then the transmit of the error failed,
209  // print it to standard out. Once printed, delete the error
210  // information since we are done with it.
211  if( _dhi->error_info )
212  {
213  _dhi->error_info->print( cout ) ;
214  delete _dhi->error_info ;
215  _dhi->error_info = 0 ;
216  }
217 
218  // if there is a problem with the rest of these steps then all we will
219  // do is log it to the BES log file and not handle the exception with
220  // the exception manager.
221  try
222  {
223  log_status();
224  }
225  catch( BESError &ex )
226  {
227  (*BESLog::TheLog()) << "Problem logging status: " << ex.get_message()
228  << endl ;
229  }
230  catch( ... )
231  {
232  (*BESLog::TheLog()) << "Unknown problem logging status" << endl ;
233  }
234 
235  try
236  {
237  report_request();
238  }
239  catch( BESError &ex )
240  {
241  (*BESLog::TheLog()) << "Problem reporting request: " << ex.get_message()
242  << endl ;
243  }
244  catch( ... )
245  {
246  (*BESLog::TheLog()) << "Unknown problem reporting request" << endl ;
247  }
248 
249  try
250  {
251  end_request();
252  }
253  catch( BESError &ex )
254  {
255  (*BESLog::TheLog()) << "Problem ending request: " << ex.get_message()
256  << endl ;
257  }
258  catch( ... )
259  {
260  (*BESLog::TheLog()) << "Unknown problem ending request" << endl ;
261  }
262 
263  return status ;
264 }
265 
266 int
268 {
269  if( !_dhi->error_info )
270  {
271  // there wasn't an error ... so now what?
272  string serr = "Finish_with_error called with no error object" ;
273  BESInternalError ex( serr, __FILE__, __LINE__ ) ;
274  status = exception_manager( ex ) ;
275  }
276 
277  return finish( status ) ;
278 }
279 
280 void
282 {
283  _init_list.push_back(init);
284 }
285 
291 void
293 {
294  BESDEBUG("bes", "Initializing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl ) ;
295  bool do_continue = true;
296  init_iter i = _init_list.begin();
297 
298  for( ; i != _init_list.end() && do_continue == true; i++ )
299  {
300  p_bes_init p = *i ;
301  do_continue = p( *_dhi ) ;
302  }
303 
304  if( !do_continue )
305  {
306  BESDEBUG("bes", "FAILED" << endl) ;
307  string se = "Initialization callback failed, exiting";
308  throw BESInternalError( se, __FILE__, __LINE__ ) ;
309  }
310  else
311  {
312  BESDEBUG("bes", "OK" << endl) ;
313  }
314 }
315 
318 void
320 {
321 }
322 
336 void
338 {
339  BESDEBUG("bes", "Executing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl ) ;
341  if( rh )
342  {
343  rh->execute( *_dhi ) ;
344  }
345  else
346  {
347  BESDEBUG("bes", "FAILED" << endl) ;
348  string se = "The response handler \"" + _dhi->action
349  + "\" does not exist" ;
350  throw BESInternalError( se, __FILE__, __LINE__ ) ;
351  }
352  BESDEBUG("bes", "OK" << endl) ;
353 
354  // Now we need to do the post processing piece of executing the request
356 
357  // And finally, transmit the response of this request
358  transmit_data();
359 }
360 
363 void
365 {
366  if( _dhi->data[AGG_CMD] != "" )
367  {
368  BESDEBUG("bes", "aggregating with: " << _dhi->data[AGG_CMD] << " ... "<< endl ) ;
369  BESAggregationServer *agg =
371  if( agg )
372  {
373  agg->aggregate( *_dhi ) ;
374  }
375  else
376  {
377  BESDEBUG("bes", "FAILED" << endl) ;
378  string se = "The aggregation handler " + _dhi->data[AGG_HANDLER]
379  + "does not exist" ;
380  throw BESInternalError( se, __FILE__, __LINE__ ) ;
381  }
382  BESDEBUG("bes", "OK" << endl) ;
383  }
384 }
385 
399 void
401 {
402  BESDEBUG("bes", "Transmitting request: " << _dhi->data[DATA_REQUEST] << endl) ;
403  if (_transmitter)
404  {
405  if( _dhi->error_info )
406  {
407  ostringstream strm ;
408  _dhi->error_info->print( strm ) ;
409  (*BESLog::TheLog()) << strm.str() << endl ;
410  BESDEBUG( "bes", " transmitting error info using transmitter ... "
411  << endl << strm.str() << endl ) ;
413  }
414  else if( _dhi->response_handler )
415  {
416  BESDEBUG( "bes", " transmitting response using transmitter ... " << endl ) ;
418  }
419  }
420  else
421  {
422  if( _dhi->error_info )
423  {
424  BESDEBUG( "bes", " transmitting error info using cout ... " << endl ) ;
425  _dhi->error_info->print( cout ) ;
426  }
427  else
428  {
429  BESDEBUG( "bes", " Unable to transmit the response ... FAILED " << endl ) ;
430  string err = "Unable to transmit the response, no transmitter" ;
431  throw BESInternalError( err, __FILE__, __LINE__ ) ;
432  }
433  }
434  BESDEBUG("bes", "OK" << endl) ;
435 }
436 
439 void
441 {
442 }
443 
455 void
457 {
458  BESDEBUG( "bes", "Reporting on request: " << _dhi->data[DATA_REQUEST]
459  << " ... " << endl ) ;
460 
462 
463  BESDEBUG( "bes", "OK" << endl ) ;
464 }
465 
466 void
468 {
469  _end_list.push_back( end ) ;
470 }
471 
477 void
479 {
480  BESDEBUG("bes", "Ending request: " << _dhi->data[DATA_REQUEST] << " ... " << endl ) ;
481  end_iter i = _end_list.begin();
482  for( ; i != _end_list.end(); i++ )
483  {
484  p_bes_end p = *i ;
485  p( *_dhi ) ;
486  }
487 
488  // now clean up any containers that were used in the request, release
489  // the resource
490  _dhi->first_container() ;
491  while( _dhi->container )
492  {
493  _dhi->container->release() ;
494  _dhi->next_container() ;
495  }
496 
497  BESDEBUG("bes", "OK" << endl) ;
498 }
499 
502 void
504 {
505  if( _dhi )
506  _dhi->clean() ;
507 }
508 
521 int
523 {
525 }
526 
535 void
536 BESInterface::dump(ostream & strm) const
537 {
538  strm << BESIndent::LMarg << "BESInterface::dump - ("
539  << (void *) this << ")" << endl;
541 
542  if (_init_list.size()) {
543  strm << BESIndent::LMarg << "termination functions:" << endl;
545  init_iter i = _init_list.begin();
546  for (; i != _init_list.end(); i++) {
547  strm << BESIndent::LMarg << (void *) (*i) << endl;
548  }
550  } else {
551  strm << BESIndent::LMarg << "termination functions: none" << endl;
552  }
553 
554  if (_end_list.size()) {
555  strm << BESIndent::LMarg << "termination functions:" << endl;
557  end_iter i = _end_list.begin();
558  for (; i != _end_list.end(); i++) {
559  strm << BESIndent::LMarg << (void *) (*i) << endl;
560  }
562  } else {
563  strm << BESIndent::LMarg << "termination functions: none" << endl;
564  }
565 
566  strm << BESIndent::LMarg << "data handler interface:" << endl;
568  _dhi->dump(strm);
570 
571  if (_transmitter) {
572  strm << BESIndent::LMarg << "transmitter:" << endl;
574  _transmitter->dump(strm);
576  } else {
577  strm << BESIndent::LMarg << "transmitter: not set" << endl;
578  }
580 }
static BESReporterList * TheList()
void clean()
clean up any information created within this data handler interface
void(* p_bes_end)(BESDataHandlerInterface &dhi)
Definition: BESInterface.h:48
#define DATA_REQUEST
Definition: BESDataNames.h:36
void dump(ostream &strm) const
dumps information about this object
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
void set_output_stream(ostream *strm)
virtual void report(BESDataHandlerInterface &dhi)
static BESAggFactory * TheFactory()
virtual void initialize()
Initialize the BES object.
void next_container()
set the container pointer to the next * container in the list, null if at the end or no containers in...
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)=0
transmit the response object built by the execute command using the specified transmitter object ...
static void add_end_callback(p_bes_end end)
#define SERVER_PID
Definition: BESDataNames.h:51
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)=0
transmit the informational object
#define AGG_CMD
Definition: BESDataNames.h:40
virtual ~BESInterface()
Definition: BESInterface.cc:80
virtual void execute(BESDataHandlerInterface &dhi)=0
knows how to build a requested response object
virtual int exception_manager(BESError &e)
Manage any exceptions thrown during the whole process.
virtual void aggregate(BESDataHandlerInterface &dhi)=0
aggregate the response object
static void add_init_callback(p_bes_init init)
static BESExceptionManager * TheEHM()
virtual void transmit_data()
Transmit the resulting response object.
BESTransmitter * _transmitter
Definition: BESInterface.h:137
static void Indent()
Definition: BESIndent.cc:38
bool(* p_bes_init)(BESDataHandlerInterface &dhi)
Definition: BESInterface.h:47
virtual string get_message()
get the error message for this exception
Definition: BESError.h:91
handler object that knows how to create a specific response object
virtual int finish_with_error(int status)
Abstract exception class for the BES with basic string message.
Definition: BESError.h:51
virtual void dump(ostream &strm) const
dumps information about this object
virtual void report_request()
Report the request and status of the request to BESReporterList::TheList()
virtual bool release()=0
BESResponseHandler * response_handler
static ostream & LMarg(ostream &strm)
Definition: BESIndent.cc:73
virtual BESAggregationServer * find_handler(string handler_name)
returns the aggregation handler with the given name in the list
#define AGG_HANDLER
Definition: BESDataNames.h:41
virtual void validate_data_request()
Validate the incoming request information.
virtual void build_data_request_plan()=0
Build the data request plan.
virtual void clean()
Clean up after the request.
#define REQUEST_FROM
Definition: BESDataNames.h:38
virtual void invoke_aggregation()
Aggregate the resulting response object.
map< string, string > data
the map of string data that will be required for the current request.
virtual void end_request()
End the BES request.
virtual void dump(ostream &strm) const
dumps information about this object
static BESLog * TheLog()
Definition: BESLog.cc:347
virtual void log_status()
Log the status of the request.
void first_container()
set the container pointer to the first container in the containers list
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
BESInfo * error_info
error information object
virtual int handle_exception(BESError &e, BESDataHandlerInterface &dhi)
Manage any exceptions thrown during the handling of a request.
BESInterface(ostream *strm)
Definition: BESInterface.cc:69
static void UnIndent()
Definition: BESIndent.cc:44
Abstraction representing mechanism for aggregating data.
virtual void execute_data_request_plan()
Execute the data request plan.
virtual int execute_request(const string &from)
Executes the given request to generate a specified response object.
virtual void print(ostream &strm)
print the information from this informational object to the specified stream
Definition: BESInfo.cc:283
virtual int finish(int status)
BESDataHandlerInterface * _dhi
Definition: BESInterface.h:136
string action
the response object requested, e.g.
BESContainer * container
pointer to current container in this interface