bes  Updated for version 3.17.4
BESInterface.cc
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 <cstdlib>
36 
37 #include <signal.h>
38 #if HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 
42 #include <setjmp.h> // Used for the timeout processing
43 
44 #include <string>
45 #include <sstream>
46 #include <iostream>
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 #include "BESContextManager.h"
56 
57 #include "BESExceptionManager.h"
58 
59 #include "BESDataNames.h"
60 
61 #include "BESDebug.h"
62 #include "BESStopWatch.h"
63 #include "BESTimeoutError.h"
64 #include "BESInternalError.h"
65 #include "BESInternalFatalError.h"
66 
67 #include "BESLog.h"
68 
69 using namespace std;
70 
71 list<p_bes_init> BESInterface::_init_list;
72 list<p_bes_end> BESInterface::_end_list;
73 
74 static jmp_buf timeout_jump;
75 static bool timeout_jump_valid = false;
76 
77 // Define this to use sigwait() is a child thread to detect that SIGALRM
78 // has been raised (i.e., that the timeout interval has elapsed). This
79 // does not currently work, but could be a way to get information about
80 // a timeout back to the BES's client if the BES itslef were structured
81 // differently. See my comment further down. jhrg 12/28/15
82 #undef USE_SIGWAIT
83 
84 // timeout period in seconds; 0 --> no timeout. This is a static value so
85 // that it can be accessed by the signal handler. jhrg 1/4/16
86 static volatile int timeout = 0;
87 
88 #define BES_TIMEOUT_KEY "BES.TimeOutInSeconds"
89 
90 // This function uses the static variables timeout_jump_valid and timeout_jump
91 // The code looks at the value of BES.TimeOutInSeconds and/or the timeout
92 // context sent in the current request and, if that is greater than zero,
93 // uses that as the maximum amount of time for the request. The system alarm
94 // is set and this function is registered as the handler. If timeout_jump_valid
95 // is true, then it will use longjmp() (yes, really...) to end the request. Look
96 // below in execute_request() for the call to setjump() to see how this works.
97 // See the SIGWAIT code that's commented out below for an alternative impl.
98 // jhrg 5/31/16
99 static void catch_sig_alarm(int sig)
100 {
101  if (sig == SIGALRM) {
102  LOG("Child listener timeout after " << timeout << " seconds, exiting." << endl);
103 
104  // Causes setjmp() below to return 1; see the call to
105  // execute_data_request_plan() in execute_request() below.
106  // jhrg 12/29/15
107  if (timeout_jump_valid)
108  longjmp(timeout_jump, 1);
109  else {
110  // This is the old version of this code; it forces the BES child
111  // listener to exit without returning an error message to the
112  // OLFS/client. jhrg 12/29/15
113  signal(SIGTERM, SIG_DFL);
114  raise(SIGTERM);
115  }
116  }
117 }
118 
119 static void register_signal_handler()
120 {
121  struct sigaction act;
122  sigemptyset(&act.sa_mask);
123  sigaddset(&act.sa_mask, SIGALRM);
124  act.sa_flags = 0;
125 
126  // Note that we do not set SA_RESTART so an interrupted system call
127  // will return with an error and errno set to EINTR.
128 
129  act.sa_handler = catch_sig_alarm;
130  if (sigaction(SIGALRM, &act, 0))
131  throw BESInternalFatalError("Could not register a handler to catch alarm/timeout.", __FILE__, __LINE__);
132 }
133 
134 #if USE_SIGWAIT
135 
136 // If the BES is changed so that the plan built here is run in a child thread,
137 // then we can have a much more flexible signal catching scheme, including catching
138 // the alarm signal used for the timeout. It's not possible to throw from a child
139 // thread to a parent thread, but if the parent thread sees that SIGALRM is
140 // raised, then it can stop the child thread (which is running the 'plan') and
141 // return a suitable message to the front end. Similarly, the BES could also
142 // handle a number of other signals using this scheme. These signals (SIGPIPE, ...)
143 // are currently processed using while/for loop(s) in the bes/server code. It may
144 // be that these signals are caught only in the master listener, but I can't
145 // quite figure that out now... jhrg 12/28/15
146 //
147 // NB: It might be possible to edit this so that it writes info to the OLFS and
148 // then uses the 'raise SIGTERM' technique to exit. That way the OLFS will at least
149 // get a message about the timeout. I'm not sure how to close up the PPT part
150 // of the conversation, however. The idea would be that the current command's DHI
151 // would be passed in as an arg and then the stream accessed that way. The BESError
152 // would be written to the stream and the child process killed. jhrg 12/2/9/15
153 
154 #include <pthread.h>
155 
156 // An alternative to a function that catches the signal; use sigwait()
157 // in a child thread after marking the signal as blocked. When/if sigwait()
158 // returns, look at the signal number and if it is the alarm, sort out
159 // what to do (throw an exception, ...). NB: A signal handler cannot
160 // portably throw an exception, but this code can.
161 
162 static pthread_t alarm_thread;
163 
164 static void* alarm_wait(void * /* arg */)
165 {
166  BESDEBUG("bes", "Starting: " << __PRETTY_FUNCTION__ << endl);
167 
168  // block SIGALRM
169  sigset_t sigset;
170  sigemptyset(&sigset);
171  sigaddset(&sigset, SIGALRM);
172  sigprocmask(SIG_BLOCK, &sigset, NULL);
173 
174  // Might replace this with a while loop. Not sure about interactions
175  // with other signal processing code in the BES. jhrg 12/28/15
176  int sig;
177  int result = sigwait(&sigset, &sig);
178  if (result != 0) {
179  BESDEBUG("bes", "Fatal error establishing timeout: " << strerror(result) << endl);
180  throw BESInternalFatalError(string("Fatal error establishing timeout: ") + strerror(result), __FILE__, __LINE__);
181  }
182  else if (result == 0 && sig == SIGALRM) {
183  BESDEBUG("bes", "Timeout found in " << __PRETTY_FUNCTION__ << endl);
184  throw BESTimeoutError("Timeout", __FILE__, __LINE__);
185  }
186  else {
187  stringstream oss;
188  oss << "While waiting for a timeout, found signal '" << result << "' in " << __PRETTY_FUNCTION__ << ends;
189  BESDEBUG("bes", oss.str() << endl);
190  throw BESInternalFatalError(oss.str(), __FILE__, __LINE__);
191  }
192 }
193 
194 static void wait_for_timeout()
195 {
196  BESDEBUG("bes", "Entering: " << __PRETTY_FUNCTION__ << endl);
197 
198  pthread_attr_t thread_attr;
199 
200  if (pthread_attr_init(&thread_attr) != 0)
201  throw BESInternalFatalError("Failed to initialize pthread attributes.", __FILE__, __LINE__);
202  if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED /*PTHREAD_CREATE_JOINABLE*/) != 0)
203  throw BESInternalFatalError("Failed to complete pthread attribute initialization.", __FILE__, __LINE__);
204 
205  int status = pthread_create(&alarm_thread, &thread_attr, alarm_wait, NULL);
206  if (status != 0)
207  throw BESInternalFatalError("Failed to start the timeout wait thread.", __FILE__, __LINE__);
208 }
209 #endif
210 
211 BESInterface::BESInterface(ostream *output_stream) :
212  _strm(output_stream), _timeout_from_keys(0), _dhi(0), _transmitter(0)
213 {
214  if (!output_stream) {
215  throw BESInternalError("output stream must be set in order to output responses", __FILE__, __LINE__);
216  }
217 
218  // Grab the BES Key for the timeout. Note that the Hyrax server generally
219  // overrides this value using a 'context' that is set/sent by the OLFS.
220  // Also note that a value of zero means no timeout, but that the context
221  // can override that too. jhrg 1/4/16
222  bool found;
223  string timeout_key_value;
224  TheBESKeys::TheKeys()->get_value(BES_TIMEOUT_KEY, timeout_key_value, found);
225  if (found) {
226  istringstream iss(timeout_key_value);
227  iss >> _timeout_from_keys;
228  }
229 
230  // Install signal handler for alarm() here
231  register_signal_handler();
232 
233 #if USE_SIGWAIT
234  wait_for_timeout();
235 #endif
236 }
237 
238 BESInterface::~BESInterface()
239 {
240 }
241 
280 extern BESStopWatch *bes_timing::elapsedTimeToReadStart;
281 extern BESStopWatch *bes_timing::elapsedTimeToTransmitStart;
282 
283 int BESInterface::execute_request(const string &from)
284 {
285  BESDEBUG("bes", "Entering: " << __PRETTY_FUNCTION__ << endl);
286 
287  if (!_dhi) {
288  throw BESInternalError("DataHandlerInterface can not be null", __FILE__, __LINE__);
289  }
290 
291  BESStopWatch sw;
292  if (BESISDEBUG(TIMING_LOG)) {
293  sw.start("BESInterface::execute_request", _dhi->data[REQUEST_ID]);
294 
295  bes_timing::elapsedTimeToReadStart = new BESStopWatch();
296  bes_timing::elapsedTimeToReadStart->start("TIME_TO_READ_START", _dhi->data[REQUEST_ID]);
297 
298  bes_timing::elapsedTimeToTransmitStart = new BESStopWatch();
299  bes_timing::elapsedTimeToTransmitStart->start("TIME_TO_TRANSMIT_START", _dhi->data[REQUEST_ID]);
300  }
301 
302  if (!_dhi) {
303  throw BESInternalError("DataHandlerInterface can not be null", __FILE__, __LINE__);
304  }
305 
306  _dhi->set_output_stream(_strm);
307  _dhi->data[REQUEST_FROM] = from;
308 
309  pid_t thepid = getpid();
310  ostringstream ss;
311  ss << thepid;
312  _dhi->data[SERVER_PID] = ss.str();
313 
314  // This is never used except as an arg to finish. jhrg 12/23/15
315  //int status = 0;
316 
317  // We split up the calls for the reason that if we catch an
318  // exception during the initialization, building, execution, or response
319  // transmit of the request then we can transmit the exception/error
320  // information.
321  try {
322  initialize();
323 
324  *(BESLog::TheLog()) << _dhi->data[SERVER_PID] << " from " << _dhi->data[REQUEST_FROM] << " request received"
325  << endl;
326 
327  // This does not do anything here or in BESBasicInterface or BESXMLInterface.
328  // Remove it? jhrg 12/23/15
329  validate_data_request();
330 
331  build_data_request_plan();
332 
333  if (!_transmitter)
334  throw BESInternalError("Unable to transmit the response, no transmitter", __FILE__, __LINE__);
335 
336  // This method does two key things: Calls the request handler to make a
337  // 'response object' (the C++ object that will hold the response) and
338  // then calls the transmitter to actually send it or build and send it.
339  //
340  // The timeout is also set in execute_data_request_plan(). The alarm signal
341  // handler (above), run when the timeout expires, will call longjmp with a
342  // return value of 1.
343  if (setjmp(timeout_jump) == 0) {
344  timeout_jump_valid = true;
345  execute_data_request_plan();
346  // Once we exit the block where setjmp() was called, the jump_buf is not valid
347  timeout_jump_valid = false;
348  }
349  else {
350  ostringstream oss;
351  oss << "BES listener timeout after " << timeout << " seconds." << ends;
352  throw BESTimeoutError(oss.str(), __FILE__, __LINE__);
353  }
354 
355  _dhi->executed = true;
356  }
357  catch (BESError & ex) {
358  timeout_jump_valid = false;
359  return exception_manager(ex);
360  }
361  catch (bad_alloc &e) {
362  timeout_jump_valid = false;
363  BESInternalFatalError ex(string("BES out of memory: ") + e.what(), __FILE__, __LINE__);
364  return exception_manager(ex);
365  }
366  catch (exception &e) {
367  timeout_jump_valid = false;
368  BESInternalFatalError ex(string("C++ Exception: ") + e.what(), __FILE__, __LINE__);
369  return exception_manager(ex);
370  }
371  catch (...) {
372  timeout_jump_valid = false;
373  BESInternalError ex("An undefined exception has been thrown", __FILE__, __LINE__);
374  return exception_manager(ex);
375  }
376 
377  delete bes_timing::elapsedTimeToReadStart;
378  bes_timing::elapsedTimeToReadStart = 0;
379 
380  delete bes_timing::elapsedTimeToTransmitStart;
381  bes_timing::elapsedTimeToTransmitStart = 0;
382 
383  return finish(0 /* status */);;
384 }
385 
386 // I think this code was written when execute_request() called transmit_data()
387 // (and invoke_aggregation()). I think that the code up to the log_status()
388 // call is redundant. This means that so is the param 'status'. jhrg 12/23/15
389 int BESInterface::finish(int /*status*/)
390 {
391  BESDEBUG("bes", "Entering: " << __PRETTY_FUNCTION__ << " ***" << endl);
392 
393 #if 0
394  int status = 0;
395  try {
396  // if there was an error during initialization, validation,
397  // execution or transmit of the response then we need to transmit
398  // the error information. Once printed, delete the error
399  // information since we are done with it.
400  if (_dhi->error_info) {
401  transmit_data();
402  delete _dhi->error_info;
403  _dhi->error_info = 0;
404  }
405  }
406  catch (BESError &ex) {
407  status = exception_manager(ex);
408  }
409  catch (bad_alloc &) {
410  string serr = "BES out of memory";
411  BESInternalFatalError ex(serr, __FILE__, __LINE__);
412  status = exception_manager(ex);
413  }
414  catch (...) {
415  string serr = "An undefined exception has been thrown";
416  BESInternalError ex(serr, __FILE__, __LINE__);
417  status = exception_manager(ex);
418  }
419 #endif
420 
421  // If there is error information then the transmit of the error failed,
422  // print it to standard out. Once printed, delete the error
423  // information since we are done with it.
424  if (_dhi->error_info) {
425  _dhi->error_info->print(cout);
426  delete _dhi->error_info;
427  _dhi->error_info = 0;
428  }
429 
430  // if there is a problem with the rest of these steps then all we will
431  // do is log it to the BES log file and not handle the exception with
432  // the exception manager.
433  try {
434  log_status();
435  }
436  catch (BESError &ex) {
437  (*BESLog::TheLog()) << "Problem logging status: " << ex.get_message() << endl;
438  }
439  catch (...) {
440  (*BESLog::TheLog()) << "Unknown problem logging status" << endl;
441  }
442 
443  try {
444  report_request();
445  }
446  catch (BESError &ex) {
447  (*BESLog::TheLog()) << "Problem reporting request: " << ex.get_message() << endl;
448  }
449  catch (...) {
450  (*BESLog::TheLog()) << "Unknown problem reporting request" << endl;
451  }
452 
453  try {
454  end_request();
455  }
456  catch (BESError &ex) {
457  (*BESLog::TheLog()) << "Problem ending request: " << ex.get_message() << endl;
458  }
459  catch (...) {
460  (*BESLog::TheLog()) << "Unknown problem ending request" << endl;
461  }
462 
463  return 0/*status*/;
464 }
465 
466 int BESInterface::finish_with_error(int status)
467 {
468  if (!_dhi->error_info) {
469  // there wasn't an error ... so now what?
470  string serr = "Finish_with_error called with no error object";
471  BESInternalError ex(serr, __FILE__, __LINE__);
472  status = exception_manager(ex);
473  }
474 
475  return finish(status);
476 }
477 
478 void BESInterface::add_init_callback(p_bes_init init)
479 {
480  _init_list.push_back(init);
481 }
482 
489 {
490  BESStopWatch sw;
491  if (BESISDEBUG(TIMING_LOG)) sw.start("BESInterface::initialize", _dhi->data[REQUEST_ID]);
492 
493  BESDEBUG("bes", "Initializing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl);
494  bool do_continue = true;
495  init_iter i = _init_list.begin();
496 
497  for (; i != _init_list.end() && do_continue == true; i++) {
498  p_bes_init p = *i;
499  do_continue = p(*_dhi);
500  }
501 
502  if (!do_continue) {
503  BESDEBUG("bes", "FAILED" << endl);
504  string se = "Initialization callback failed, exiting";
505  throw BESInternalError(se, __FILE__, __LINE__);
506  }
507  else {
508  BESDEBUG("bes", "OK" << endl);
509  }
510 }
511 
515 {
516 }
517 
535 {
536  BESStopWatch sw;
537  if (BESISDEBUG(TIMING_LOG))
538  sw.start("BESInterface::execute_data_request_plan(\"" + _dhi->data[DATA_REQUEST] + "\")",
539  _dhi->data[REQUEST_ID]);
540 
541  // Set timeout if the 'bes_timeout' context value was passed in with the
542  // command.
543  bool found = false;
544  string context = BESContextManager::TheManager()->get_context("bes_timeout", found);
545  if (found) {
546  timeout = strtol(context.c_str(), NULL, 10);
547  VERBOSE("Set request timeout to " << timeout << " seconds (from context)." << endl);
548  alarm(timeout);
549  }
550  else if (_timeout_from_keys != 0) {
551  timeout = _timeout_from_keys;
552  VERBOSE("Set request timeout to " << timeout << " seconds (from keys)." << endl);
553  alarm(timeout);
554  }
555 
556  try {
557  BESDEBUG("bes",
558  "Executing request: " << _dhi->data[DATA_REQUEST] << " ... " << endl);
559  BESResponseHandler *rh = _dhi->response_handler;
560  if (rh) {
561  rh->execute(*_dhi);
562  } else {
563  BESDEBUG("bes", "FAILED" << endl);
564  string se = "The response handler \"" + _dhi->action
565  + "\" does not exist";
566  throw BESInternalError(se, __FILE__, __LINE__);
567  }
568  BESDEBUG("bes", "OK" << endl);
569 
570  // Now we need to do the post processing piece of executing the request
571  invoke_aggregation();
572 
573  // And finally, transmit the response of this request
574  transmit_data();
575 #if 0
576  // Only clear the timeout if it has been set.
577  if (timeout != 0) {
578 #endif
579  timeout = 0;
580  alarm(0);
581 #if 0
582  }
583 #endif
584  } catch (...) {
585  timeout = 0;
586  alarm(0);
587 
588  throw;
589  }
590 }
591 
595 {
596  BESStopWatch sw;
597  if (BESISDEBUG(TIMING_LOG)) sw.start("BESInterface::invoke_aggregation", _dhi->data[REQUEST_ID]);
598 
599  if (_dhi->data[AGG_CMD] != "") {
600  BESDEBUG("bes", "aggregating with: " << _dhi->data[AGG_CMD] << " ... "<< endl);
601  BESAggregationServer *agg = BESAggFactory::TheFactory()->find_handler(_dhi->data[AGG_HANDLER]);
602  if (agg) {
603  agg->aggregate(*_dhi);
604  }
605  else {
606  BESDEBUG("bes", "FAILED" << endl);
607  string se = "The aggregation handler " + _dhi->data[AGG_HANDLER] + "does not exist";
608  throw BESInternalError(se, __FILE__, __LINE__);
609  }
610  BESDEBUG("bes", "OK" << endl);
611  }
612 }
613 
628 {
629  BESStopWatch sw;
630  if (BESISDEBUG(TIMING_LOG)) sw.start("BESInterface::transmit_data", _dhi->data[REQUEST_ID]);
631 
632  BESDEBUG("bes", "BESInterface::transmit_data() - Transmitting request: " << _dhi->data[DATA_REQUEST] << endl);
633 #if 0
634  if (_transmitter) {
635 #endif
636  if (_dhi->error_info) {
637  ostringstream strm;
638  _dhi->error_info->print(strm);
639  (*BESLog::TheLog()) << strm.str() << endl;
640  BESDEBUG("bes", " transmitting error info using transmitter ... " << endl << strm.str() << endl);
641 
642  _dhi->error_info->transmit(_transmitter, *_dhi);
643  }
644  else if (_dhi->response_handler) {
645  BESDEBUG("bes", " BESInterface::transmit_data() - Response handler " << _dhi->response_handler->get_name() << endl);
646 
647  _dhi->response_handler->transmit(_transmitter, *_dhi);
648  }
649 #if 0
650  }
651  else {
652 
653  if (_dhi->error_info) {
654  BESDEBUG("bes", "BESInterface::transmit_data() - Transmitting error info using cout ... " << endl);
655  _dhi->error_info->print(cout);
656  delete _dhi->error_info;
657  _dhi->error_info = 0;
658  }
659  else {
660  BESDEBUG("bes", "BESInterface::transmit_data() - Unable to transmit the response ... FAILED " << endl);
661  //string err = ;
662  throw BESInternalError("Unable to transmit the response, no transmitter", __FILE__, __LINE__);
663  }
664  }
665 #endif
666 
667  BESDEBUG("bes", "BESInterface::transmit_data() - OK" << endl);
668 }
669 
673 {
674 }
675 
688 {
689  BESDEBUG("bes", "Reporting on request: " << _dhi->data[DATA_REQUEST] << " ... " << endl);
690 
691  BESReporterList::TheList()->report(*_dhi);
692 
693  BESDEBUG("bes", "OK" << endl);
694 }
695 
696 void BESInterface::add_end_callback(p_bes_end end)
697 {
698  _end_list.push_back(end);
699 }
700 
707 {
708  BESDEBUG("bes", "Ending request: " << _dhi->data[DATA_REQUEST] << " ... " << endl);
709  end_iter i = _end_list.begin();
710  for (; i != _end_list.end(); i++) {
711  p_bes_end p = *i;
712  p(*_dhi);
713  }
714 
715  // now clean up any containers that were used in the request, release
716  // the resource
717  _dhi->first_container();
718  while (_dhi->container) {
719  BESDEBUG("bes", "Calling BESContainer::release()" << endl);
720  _dhi->container->release();
721  _dhi->next_container();
722  }
723 
724  BESDEBUG("bes", "OK" << endl);
725 }
726 
730 {
731  if (_dhi) _dhi->clean();
732 }
733 
747 {
748  return BESExceptionManager::TheEHM()->handle_exception(e, *_dhi);
749 }
750 
759 void BESInterface::dump(ostream & strm) const
760 {
761  strm << BESIndent::LMarg << "BESInterface::dump - (" << (void *) this << ")" << endl;
762  BESIndent::Indent();
763 
764  if (_init_list.size()) {
765  strm << BESIndent::LMarg << "termination functions:" << endl;
766  BESIndent::Indent();
767  init_iter i = _init_list.begin();
768  for (; i != _init_list.end(); i++) {
769  // TODO ISO C++ forbids casting between pointer-to-function and pointer-to-object
770  // ...also below
771  strm << BESIndent::LMarg << (void *) (*i) << endl;
772  }
773  BESIndent::UnIndent();
774  }
775  else {
776  strm << BESIndent::LMarg << "termination functions: none" << endl;
777  }
778 
779  if (_end_list.size()) {
780  strm << BESIndent::LMarg << "termination functions:" << endl;
781  BESIndent::Indent();
782  end_iter i = _end_list.begin();
783  for (; i != _end_list.end(); i++) {
784  strm << BESIndent::LMarg << (void *) (*i) << endl;
785  }
786  BESIndent::UnIndent();
787  }
788  else {
789  strm << BESIndent::LMarg << "termination functions: none" << endl;
790  }
791 
792  strm << BESIndent::LMarg << "data handler interface:" << endl;
793  BESIndent::Indent();
794  _dhi->dump(strm);
795  BESIndent::UnIndent();
796 
797  if (_transmitter) {
798  strm << BESIndent::LMarg << "transmitter:" << endl;
799  BESIndent::Indent();
800  _transmitter->dump(strm);
801  BESIndent::UnIndent();
802  }
803  else {
804  strm << BESIndent::LMarg << "transmitter: not set" << endl;
805  }
806  BESIndent::UnIndent();
807 }
virtual void dump(ostream &strm) const
dumps information about this object
error thrown if there is a user syntax error in the request or any other user error ...
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
virtual void initialize()
Initialize the BES object.
virtual std::string get_message()
get the error message for this exception
Definition: BESError.h:97
virtual void execute(BESDataHandlerInterface &dhi)=0
knows how to build a requested response object
STL namespace.
virtual int exception_manager(BESError &e)
Manage any exceptions thrown during the whole process.
virtual void aggregate(BESDataHandlerInterface &dhi)=0
aggregate the response object
virtual string get_context(const string &name, bool &found)
retrieve the value of the specified context from the BES
virtual bool start(string name)
Definition: BESStopWatch.cc:57
virtual void transmit_data()
Transmit the resulting response object.
handler object that knows how to create a specific response object
Abstract exception class for the BES with basic string message.
Definition: BESError.h:56
virtual void report_request()
Report the request and status of the request to BESReporterList::TheList()
virtual void validate_data_request()
Validate the incoming request information.
virtual void clean()
Clean up after the request.
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:483
virtual void invoke_aggregation()
Aggregate the resulting response object.
virtual void end_request()
End the BES request.
virtual BESAggregationServer * find_handler(const string &handler_name)
returns the aggregation handler with the given name in the list
virtual void log_status()
Log the status of the request.
virtual int handle_exception(BESError &e, BESDataHandlerInterface &dhi)
Manage any exceptions thrown during the handling of a request.
Abstraction representing mechanism for aggregating data.
virtual void execute_data_request_plan()
Execute the data request plan.
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:43