bes  Updated for version 3.20.5
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 <Error.h>
49 
50 #include "BESInterface.h"
51 
52 #include "TheBESKeys.h"
53 #include "BESResponseHandler.h"
54 #include "BESContextManager.h"
55 
56 #include "BESDapError.h"
57 
58 #include "BESTransmitterNames.h"
59 #include "BESDataNames.h"
60 #include "BESTransmitterNames.h"
61 #include "BESReturnManager.h"
62 #include "BESSyntaxUserError.h"
63 
64 #include "BESInfoList.h"
65 #include "BESXMLInfo.h"
66 
67 #include "BESDebug.h"
68 #include "BESStopWatch.h"
69 #include "BESTimeoutError.h"
70 #include "BESInternalError.h"
71 #include "BESInternalFatalError.h"
72 #include "ServerAdministrator.h"
73 
74 #include "BESLog.h"
75 
76 // If not defined, this is false (source code file names are logged). jhrg 10/4/18
77 #define EXCLUDE_FILE_INFO_FROM_LOG "BES.DoNotLogSourceFilenames"
78 
79 using namespace std;
80 
81 static jmp_buf timeout_jump;
82 static bool timeout_jump_valid = false;
83 
84 // Define this to use sigwait() in a child thread to detect that SIGALRM
85 // has been raised (i.e., that the timeout interval has elapsed). This
86 // does not currently work, but could be a way to get information about
87 // a timeout back to the BES's client if the BES itslef were structured
88 // differently. See my comment further down. jhrg 12/28/15
89 #undef USE_SIGWAIT
90 
91 // timeout period in seconds; 0 --> no timeout. This is a static value so
92 // that it can be accessed by the signal handler. jhrg 1/4/16
93 // I've made this globally visible so that other code that might want to
94 // alter the time out value can do so and this variable can be kept consistent.
95 // See BESStreamResponseHandler::execute() for an example. jhrg 1/24/17
96 volatile int bes_timeout = 0;
97 
98 #define BES_TIMEOUT_KEY "BES.TimeOutInSeconds"
99 
100 // This function uses the static variables timeout_jump_valid and timeout_jump
101 // The code looks at the value of BES.TimeOutInSeconds and/or the timeout
102 // context sent in the current request and, if that is greater than zero,
103 // uses that as the maximum amount of time for the request. The system alarm
104 // is set and this function is registered as the handler. If timeout_jump_valid
105 // is true, then it will use longjmp() (yes, really...) to end the request. Look
106 // below in execute_request() for the call to setjump() to see how this works.
107 // See the SIGWAIT code that's commented out below for an alternative impl.
108 // jhrg 5/31/16
109 static void catch_sig_alarm(int sig)
110 {
111  if (sig == SIGALRM) {
112  LOG("BES timeout after " << bes_timeout << " seconds." << endl);
113 
114  // Causes setjmp() below to return 1; see the call to
115  // execute_data_request_plan() in execute_request() below.
116  // jhrg 12/29/15
117  if (timeout_jump_valid)
118  longjmp(timeout_jump, 1);
119  else {
120  // This is the old version of this code; it forces the BES child
121  // listener to exit without returning an error message to the
122  // OLFS/client. jhrg 12/29/15
123  signal(SIGTERM, SIG_DFL);
124  raise(SIGTERM);
125  }
126  }
127 }
128 
129 static void register_signal_handler()
130 {
131  struct sigaction act;
132  sigemptyset(&act.sa_mask);
133  sigaddset(&act.sa_mask, SIGALRM);
134  act.sa_flags = 0;
135 
136  // Note that we do not set SA_RESTART so an interrupted system call
137  // will return with an error and errno set to EINTR.
138 
139  act.sa_handler = catch_sig_alarm;
140  if (sigaction(SIGALRM, &act, 0))
141  throw BESInternalFatalError("Could not register a handler to catch alarm/timeout.", __FILE__, __LINE__);
142 }
143 
144 static inline void downcase(string &s)
145 {
146  for (unsigned int i = 0; i < s.length(); i++)
147  s[i] = tolower(s[i]);
148 }
149 
150 static void log_error(BESError &e)
151 {
152  string error_name = "";
153 #if 0
154  // TODO This should be configurable; I'm changing the values below to always log all errors.
155  // I'm also confused about the actual intention. jhrg 11/14/17
156  //
157  // Simplified. jhrg 10/03/18
158  bool only_log_to_verbose = false;
159 #endif
160  switch (e.get_bes_error_type()) {
161  case BES_INTERNAL_FATAL_ERROR:
162  error_name = "BES Internal Fatal Error";
163  break;
164 
165  case BES_INTERNAL_ERROR:
166  error_name = "BES Internal Error";
167  break;
168 
169  case BES_SYNTAX_USER_ERROR:
170  error_name = "BES User Syntax Error";
171  // only_log_to_verbose = false; // TODO Was 'true.' jhrg 11/14/17
172  break;
173 
174  case BES_FORBIDDEN_ERROR:
175  error_name = "BES Forbidden Error";
176  break;
177 
178  case BES_NOT_FOUND_ERROR:
179  error_name = "BES Not Found Error";
180  // only_log_to_verbose = false; // TODO was 'true.' jhrg 11/14/17
181  break;
182 
183  default:
184  error_name = "BES Error";
185  break;
186  }
187 
188  if (TheBESKeys::TheKeys()->read_bool_key(EXCLUDE_FILE_INFO_FROM_LOG, false)) {
189  LOG("ERROR: " << error_name << ": " << e.get_message() << endl);
190  }
191  else {
192  LOG("ERROR: " << error_name << ": " << e.get_message() << " (" << e.get_file() << ":" << e.get_line() << ")" << endl);
193  }
194 
195 #if 0
196  if (only_log_to_verbose) {
197  VERBOSE("ERROR: " << error_name << ", error code: " << e.get_bes_error_type() << ", file: " << e.get_file() << ":"
198  << e.get_line() << ", message: " << e.get_message() << endl);
199 
200  }
201  else {
202  LOG("ERROR: " << error_name << ": " << e.get_message() << " (BES error code: " << e.get_bes_error_type() << ")." << endl);
203  VERBOSE(" at: " << e.get_file() << ":" << e.get_line() << endl);
204  }
205 #endif
206 
207 }
208 
209 #if USE_SIGWAIT
210 
211 // If the BES is changed so that the plan built here is run in a child thread,
212 // then we can have a much more flexible signal catching scheme, including catching
213 // the alarm signal used for the timeout. It's not possible to throw from a child
214 // thread to a parent thread, but if the parent thread sees that SIGALRM is
215 // raised, then it can stop the child thread (which is running the 'plan') and
216 // return a suitable message to the front end. Similarly, the BES could also
217 // handle a number of other signals using this scheme. These signals (SIGPIPE, ...)
218 // are currently processed using while/for loop(s) in the bes/server code. It may
219 // be that these signals are caught only in the master listener, but I can't
220 // quite figure that out now... jhrg 12/28/15
221 //
222 // NB: It might be possible to edit this so that it writes info to the OLFS and
223 // then uses the 'raise SIGTERM' technique to exit. That way the OLFS will at least
224 // get a message about the timeout. I'm not sure how to close up the PPT part
225 // of the conversation, however. The idea would be that the current command's DHI
226 // would be passed in as an arg and then the stream accessed that way. The BESError
227 // would be written to the stream and the child process killed. jhrg 12/2/9/15
228 
229 #include <pthread.h>
230 
231 // An alternative to a function that catches the signal; use sigwait()
232 // in a child thread after marking the signal as blocked. When/if sigwait()
233 // returns, look at the signal number and if it is the alarm, sort out
234 // what to do (throw an exception, ...). NB: A signal handler cannot
235 // portably throw an exception, but this code can.
236 
237 static pthread_t alarm_thread;
238 
239 static void* alarm_wait(void * /* arg */)
240 {
241  BESDEBUG("bes", "Starting: " << __PRETTY_FUNCTION__ << endl);
242 
243  // block SIGALRM
244  sigset_t sigset;
245  sigemptyset(&sigset);
246  sigaddset(&sigset, SIGALRM);
247  sigprocmask(SIG_BLOCK, &sigset, NULL);
248 
249  // Might replace this with a while loop. Not sure about interactions
250  // with other signal processing code in the BES. jhrg 12/28/15
251  int sig;
252  int result = sigwait(&sigset, &sig);
253  if (result != 0) {
254  BESDEBUG("bes", "Fatal error establishing timeout: " << strerror(result) << endl);
255  throw BESInternalFatalError(string("Fatal error establishing timeout: ") + strerror(result), __FILE__, __LINE__);
256  }
257  else if (result == 0 && sig == SIGALRM) {
258  BESDEBUG("bes", "Timeout found in " << __PRETTY_FUNCTION__ << endl);
259  throw BESTimeoutError("Timeout", __FILE__, __LINE__);
260  }
261  else {
262  stringstream oss;
263  oss << "While waiting for a timeout, found signal '" << result << "' in " << __PRETTY_FUNCTION__ << ends;
264  BESDEBUG("bes", oss.str() << endl);
265  throw BESInternalFatalError(oss.str(), __FILE__, __LINE__);
266  }
267 }
268 
269 static void wait_for_timeout()
270 {
271  BESDEBUG("bes", "Entering: " << __PRETTY_FUNCTION__ << endl);
272 
273  pthread_attr_t thread_attr;
274 
275  if (pthread_attr_init(&thread_attr) != 0)
276  throw BESInternalFatalError("Failed to initialize pthread attributes.", __FILE__, __LINE__);
277  if (pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED /*PTHREAD_CREATE_JOINABLE*/) != 0)
278  throw BESInternalFatalError("Failed to complete pthread attribute initialization.", __FILE__, __LINE__);
279 
280  int status = pthread_create(&alarm_thread, &thread_attr, alarm_wait, NULL);
281  if (status != 0)
282  throw BESInternalFatalError("Failed to start the timeout wait thread.", __FILE__, __LINE__);
283 }
284 #endif
285 
286 BESInterface::BESInterface(ostream *output_stream) :
287  d_strm(output_stream), d_timeout_from_keys(0), d_dhi_ptr(0), d_transmitter(0)
288 {
289  if (!d_strm) {
290  throw BESInternalError("Output stream must be set in order to output responses", __FILE__, __LINE__);
291  }
292 
293  // Grab the BES Key for the timeout. Note that the Hyrax server generally
294  // overrides this value using a 'context' that is set/sent by the OLFS.
295  // Also note that a value of zero means no timeout, but that the context
296  // can override that too. jhrg 1/4/16
297  bool found;
298  string timeout_key_value;
299  TheBESKeys::TheKeys()->get_value(BES_TIMEOUT_KEY, timeout_key_value, found);
300  if (found) {
301  istringstream iss(timeout_key_value);
302  iss >> d_timeout_from_keys;
303  }
304 
305  // Install signal handler for alarm() here
306  register_signal_handler();
307 
308 #if USE_SIGWAIT
309  wait_for_timeout();
310 #endif
311 }
312 
313 #if 0
314 extern BESStopWatch *bes_timing::elapsedTimeToReadStart;
315 extern BESStopWatch *bes_timing::elapsedTimeToTransmitStart;
316 #endif
317 
329 {
330  bool found = false;
331  string context = BESContextManager::TheManager()->get_context("errors", found);
332  downcase(context);
333  if (found && context == XML_ERRORS)
334  dhi.error_info = new BESXMLInfo();
335  else
336  dhi.error_info = BESInfoList::TheList()->build_info();
337 
338 #if 0
339  dhi.error_info = new BESXMLInfo();
340 // #else
341  dhi.error_info = BESInfoList::TheList()->build_info();
342 #endif
343 
344  log_error(e);
345 
346  string admin_email = "";
347  try {
349  admin_email = sd.get_email();
350  }
351  catch (...) {
352  admin_email = "support@opendap.org";
353  }
354  if (admin_email.empty()) {
355  admin_email = "support@opendap.org";
356  }
357 
358  dhi.error_info->begin_response(dhi.action_name.empty() ? "BES" : dhi.action_name, dhi);
359 
360  dhi.error_info->add_exception(e, admin_email);
361 
362  dhi.error_info->end_response();
363 
364  return e.get_bes_error_type();
365 }
366 
367 
368 #if 0
370 {
371  // If we are handling errors in a dap2 context, then create a
372  // DapErrorInfo object to transmit/print the error as a dap2
373  // response.
374  bool found = false;
375  // I changed 'dap_format' to 'errors' in the following line. jhrg 10/6/08
376  string context = BESContextManager::TheManager()->get_context("errors", found);
377  if (context == "dap2" || context == "dap") {
378  libdap::ErrorCode ec = unknown_error;
379  BESDapError *de = dynamic_cast<BESDapError*>(&e);
380  if (de) {
381  ec = de->get_error_code();
382  }
384  dhi.error_info = new BESDapErrorInfo(ec, e.get_message());
385 
386  return e.get_bes_error_type();
387  }
388  else {
389  // If we are not in a dap2 context and the exception is a dap
390  // handler exception, then convert the error message to include the
391  // error code. If it is or is not a dap exception, we simply return
392  // that the exception was not handled.
393  BESError *e_p = &e;
394  BESDapError *de = dynamic_cast<BESDapError*>(e_p);
395  if (de) {
396  ostringstream s;
397  s << "libdap exception building response: error_code = " << de->get_error_code() << ": "
398  << de->get_message();
399  e.set_message(s.str());
401  }
402  }
403  return 0;
404 }
405 #endif
406 
407 
446 int BESInterface::execute_request(const string &from)
447 {
448  BESDEBUG("bes", "Entering: " << __PRETTY_FUNCTION__ << endl);
449 
450  if (!d_dhi_ptr) {
451  throw BESInternalError("DataHandlerInterface can not be null", __FILE__, __LINE__);
452  }
453 
454  BESStopWatch sw;
455  if (BESISDEBUG(TIMING_LOG)) {
456  // It would be great to have more info to put here, but that is buried in
457  // BESXMLInterface::build_data_request_plan() where the XML document is
458  // parsed. jhrg 11/9/17
459  sw.start("BESInterface::execute_request", d_dhi_ptr->data[REQUEST_ID]);
460 #if 0
461  bes_timing::elapsedTimeToReadStart = new BESStopWatch();
462  bes_timing::elapsedTimeToReadStart->start("TIME_TO_READ_START", d_dhi_ptr->data[REQUEST_ID]);
463 
464  bes_timing::elapsedTimeToTransmitStart = new BESStopWatch();
465  bes_timing::elapsedTimeToTransmitStart->start("TIME_TO_TRANSMIT_START", d_dhi_ptr->data[REQUEST_ID]);
466 #endif
467  }
468 
469  // TODO These never change for the life of a BES, so maybe they can move out of
470  // code that runs for every request? jhrg 11/8/17
471  d_dhi_ptr->set_output_stream(d_strm);
472  d_dhi_ptr->data[REQUEST_FROM] = from;
473 
474  // TODO If this is only used for logging, it is not needed since the log has a copy
475  // of the BES PID. jhrg 11/13/17
476  ostringstream ss;
477  ss << getpid();
478  d_dhi_ptr->data[SERVER_PID] = ss.str();
479 
480  // We split up the calls for the reason that if we catch an
481  // exception during the initialization, building, execution, or response
482  // transmit of the request then we can transmit the exception/error
483  // information.
484  //
485  // TODO status is not used. jhrg 11/9/17
486  int status = 0; // save the return status from exception_manager() and return that.
487  try {
488  VERBOSE(d_dhi_ptr->data[REQUEST_FROM] << " request received" << endl);
489 
490  // Initialize the transmitter for this interface instance to the BASIC
491  // TRANSMITTER. This ensures that a simple response, such as an error,
492  // can be sent back to the OLFS should that be needed.
493  d_transmitter = BESReturnManager::TheManager()->find_transmitter(BASIC_TRANSMITTER);
494  if (!d_transmitter)
495  throw BESInternalError(string("Unable to find transmitter '") + BASIC_TRANSMITTER + "'", __FILE__, __LINE__);
496 
497  build_data_request_plan();
498 
499  // This method does two key things: Calls the request handler to make a
500  // 'response object' (the C++ object that will hold the response) and
501  // then calls the transmitter to actually send it or build and send it.
502  //
503  // The timeout is also set in execute_data_request_plan(). The alarm signal
504  // handler (above), run when the timeout expires, will call longjmp with a
505  // return value of 1.
506  if (setjmp(timeout_jump) == 0) {
507  timeout_jump_valid = true;
508 
509  // Set timeout? Use either the value from the keys or a context
510  bool found = false;
511  string context = BESContextManager::TheManager()->get_context("bes_timeout", found);
512  if (found) {
513  bes_timeout = strtol(context.c_str(), NULL, 10);
514  VERBOSE(d_dhi_ptr->data[REQUEST_FROM] << "Set request timeout to " << bes_timeout << " seconds (from context)." << endl);
515  alarm(bes_timeout);
516  }
517  else if (d_timeout_from_keys != 0) {
518  bes_timeout = d_timeout_from_keys;
519  VERBOSE(d_dhi_ptr->data[REQUEST_FROM] << "Set request timeout to " << bes_timeout << " seconds (from keys)." << endl);
520  alarm(bes_timeout);
521  }
522 
523  execute_data_request_plan();
524 
525  // Only clear the timeout if it has been set.
526  if (bes_timeout != 0) {
527  bes_timeout = 0;
528  alarm(0);
529  }
530 
531  // Once we exit the block where setjmp() was called, the jump_buf is not valid
532  timeout_jump_valid = false;
533  }
534  else {
535  ostringstream oss;
536  oss << "BES listener timeout after " << bes_timeout << " seconds." << ends;
537  throw BESTimeoutError(oss.str(), __FILE__, __LINE__);
538  }
539 
540  d_dhi_ptr->executed = true;
541  }
542  catch (libdap::Error &e) {
543  timeout_jump_valid = false;
544  BESInternalFatalError ex(string("BES caught a libdap exception: ") + e.get_error_message(), __FILE__, __LINE__);
545  status = handleException(ex, *d_dhi_ptr);
546  }
547  catch (BESError &e) {
548  timeout_jump_valid = false;
549  status = handleException(e, *d_dhi_ptr);
550 
551 #if 0
552  /*We switched between one or the other. kln 05/31/18
553  Leaving both in just in case someone comes back to this.
554  The top one used a singleton to try and find a handler that could handle the exception before
555  moving on to the handleException function.We tried to get it so that the singleton wasn't
556  needed and all 4 catch blocks only called handleException.
557  */
558  status = BESDapError::TheDapHandler()->handleBESError(ex, *d_dhi_ptr);
559 
560  status = BESDapError::handleException(ex, *d_dhi_ptr);
561 #endif
562 
563  }
564  catch (bad_alloc &e) {
565  timeout_jump_valid = false;
566  BESInternalFatalError ex(string("BES out of memory: ") + e.what(), __FILE__, __LINE__);
567  status = handleException(ex, *d_dhi_ptr);
568  }
569  catch (exception &e) {
570  timeout_jump_valid = false;
571  BESInternalFatalError ex(string("C++ Exception: ") + e.what(), __FILE__, __LINE__);
572  status = handleException(ex, *d_dhi_ptr);
573  }
574  catch (...) {
575  timeout_jump_valid = false;
576  BESInternalError ex("An unidentified exception has been thrown", __FILE__, __LINE__);
577  status = handleException(ex, *d_dhi_ptr);
578  }
579 
580 #if 0
581  delete bes_timing::elapsedTimeToReadStart;
582  bes_timing::elapsedTimeToReadStart = 0;
583 
584  delete bes_timing::elapsedTimeToTransmitStart;
585  bes_timing::elapsedTimeToTransmitStart = 0;
586 
587 #endif
588 
589  return status;
590 }
591 
598 int BESInterface::finish(int status)
599 {
600 #if 0
601  if (status != 0 && d_dhi_ptr->error_info == 0) {
602  // there wasn't an error ... so now what?
603  BESInternalError ex("Finish_with_error called with no error object", __FILE__, __LINE__);
604  status = exception_manager(ex);
605  }
606 #endif
607 
608  if (d_dhi_ptr->error_info) {
609  d_dhi_ptr->error_info->print(*d_strm /*cout*/);
610  delete d_dhi_ptr->error_info;
611  d_dhi_ptr->error_info = 0;
612  }
613 
614  // if there is a problem with the rest of these steps then all we will
615  // do is log it to the BES log file and not handle the exception with
616  // the exception manager.
617  try {
618  log_status();
619  end_request();
620  }
621  catch (BESError &ex) {
622  LOG("Problem logging status or running end of request cleanup: " << ex.get_message() << endl);
623  }
624  catch (...) {
625  LOG("Unknown problem logging status or running end of request cleanup" << endl);
626  }
627 
628  return status;
629 }
630 
637 {
638  // now clean up any containers that were used in the request, release
639  // the resource
641  while (d_dhi_ptr->container) {
642  d_dhi_ptr->container->release();
644  }
645 }
646 
659 #if 0
660 int BESInterface::exception_manager(BESError &e)
661 {
662  return BESExceptionManager::TheEHM()->handle_exception(e, *d_dhi_ptr);
663 }
664 #endif
665 
674 void BESInterface::dump(ostream & strm) const
675 {
676  strm << BESIndent::LMarg << "BESInterface::dump - (" << (void *) this << ")" << endl;
677  BESIndent::Indent();
678 
679  strm << BESIndent::LMarg << "data handler interface:" << endl;
680  BESIndent::Indent();
681  d_dhi_ptr->dump(strm);
682  BESIndent::UnIndent();
683 
684  if (d_transmitter) {
685  strm << BESIndent::LMarg << "transmitter:" << endl;
686  BESIndent::Indent();
687  d_transmitter->dump(strm);
688  BESIndent::UnIndent();
689  }
690  else {
691  strm << BESIndent::LMarg << "transmitter: not set" << endl;
692  }
693 
694  BESIndent::UnIndent();
695 }
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
int convert_error_code(int error_code, int current_error_type)
converts the libdap error code to the bes error type
Definition: BESDapError.cc:83
exception thrown if inernal error encountered
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 dump(std::ostream &strm) const
Manage any exceptions thrown during the whole process.
silent informational response object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual std::string get_message()
get the error message for this exception
Definition: BESError.h:99
BESDataHandlerInterface * d_dhi_ptr
Allocated by the child class.
Definition: BESInterface.h:124
BESTransmitter * d_transmitter
The Transmitter to use for the result.
Definition: BESInterface.h:125
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:420
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
A ServerAdministrator object from the TheBESKeys associated with the string SERVER_ADMIN_KEY.
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:61
virtual void add_exception(BESError &e, const string &admin)
add exception information to this informational object
Definition: BESInfo.cc:234
represents an xml formatted response object
Definition: BESXMLInfo.h:48
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
virtual void set_message(const std::string &msg)
set the error message for this exception
Definition: BESError.h:91
bool read_bool_key(const std::string &key, bool default_value)
Read a boolean-valued key from the bes.conf file.
Definition: TheBESKeys.cc:474
void dump(ostream &strm) const
dumps information about this object
Structure storing information used by the BES to handle the request.
virtual std::string get_file()
get the file name where the exception was thrown
Definition: BESError.h:107
map< string, string > data
the map of string data that will be required for the current request.
virtual void set_bes_error_type(int type)
Set the return code for this particular error class.
Definition: BESError.h:132
virtual void end_request()
End the BES request.
virtual int get_bes_error_type()
Return the return code for this error class.
Definition: BESError.h:143
virtual void begin_response(const string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESInfo.cc:124
void first_container()
set the container pointer to the first container in the containers list
static int handleException(BESError &e, BESDataHandlerInterface &dhi)
Make a BESXMLInfo object to hold the error information.
BESInfo * error_info
error information object
virtual void print(ostream &strm)
print the information from this informational object to the specified stream
Definition: BESInfo.cc:261
virtual int finish(int status)
BESContainer * container
pointer to current container in this interface
virtual int execute_request(const std::string &from)
The entry point for command execution; called by BESServerHandler::execute()
virtual int get_line()
get the line number where the exception was thrown
Definition: BESError.h:115