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