bes  Updated for version 3.20.6
DapRequestHandler.cc
1 // DapRequestHandler.cc
2 
3 // Copyright (c) 2013 OPeNDAP, Inc. Author: James Gallagher
4 // <jgallagher@opendap.org>, Patrick West <pwest@opendap.org>
5 // Nathan Potter <npotter@opendap.org>
6 //
7 // modify it under the terms of the GNU Lesser General Public License
8 // as published by the Free Software Foundation; either version 2.1 of
9 // the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
15 //
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 U\ SA
19 //
20 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI.
21 // 02874-0112.
22 #include "config.h"
23 
24 #include <string>
25 #include <memory>
26 
27 #include "DapRequestHandler.h"
28 
29 #include <BESResponseHandler.h>
30 #include <BESResponseNames.h>
31 #include <BESVersionInfo.h>
32 #include <BESTextInfo.h>
33 #include <BESDapNames.h>
34 
35 #include <BESDataDDSResponse.h>
36 #include <BESDDSResponse.h>
37 #include <BESDASResponse.h>
38 #include <BESDMRResponse.h>
39 
40 #include <BESConstraintFuncs.h>
41 #include <BESServiceRegistry.h>
42 #include <BESUtil.h>
43 #include <TheBESKeys.h>
44 
45 #include <BESDapError.h>
46 #include <BESInternalFatalError.h>
47 #include <BESDebug.h>
48 
49 #include <BaseTypeFactory.h>
50 #include <test/TestTypeFactory.h>
51 #include <D4BaseTypeFactory.h>
52 #include <test/D4TestTypeFactory.h>
53 #include <test/TestCommon.h>
54 
55 #include <DMR.h>
56 #include <D4Group.h>
57 #include <D4Connect.h>
58 #include <D4ParserSax2.h>
59 
60 #include <Ancillary.h>
61 #include <Connect.h>
62 #include <Response.h>
63 #include <InternalErr.h>
64 #include <mime_util.h>
65 
66 using namespace libdap;
67 
68 int test_variable_sleep_interval = 0;
69 
70 bool DapRequestHandler::d_use_series_values = true;
71 bool DapRequestHandler::d_use_series_values_set = false;
72 
73 bool DapRequestHandler::d_use_test_types = true;
74 bool DapRequestHandler::d_use_test_types_set = false;
75 
76 const string module = "dapreader";
77 
78 static void read_key_value(const std::string &key_name, bool &key_value, bool &is_key_set)
79 {
80  if (is_key_set == false) {
81  bool key_found = false;
82  string doset;
83  TheBESKeys::TheKeys()->get_value(key_name, doset, key_found);
84  if (key_found) {
85  // It was set in the conf file
86  is_key_set = true;
87 
88  doset = BESUtil::lowercase(doset);
89  key_value = (doset == "true" || doset == "yes");
90  }
91  }
92 }
93 
94 static bool extension_match(const string &data_source, const string &extension)
95 {
96  string::size_type pos = data_source.rfind(extension);
97  return pos != string::npos && pos + extension.length() == data_source.length();
98 }
99 
100 DapRequestHandler::DapRequestHandler(const string &name) :
101  BESRequestHandler(name)
102 {
103  add_method(DAS_RESPONSE, dap_build_das);
104  add_method(DDS_RESPONSE, dap_build_dds);
105  add_method(DATA_RESPONSE, dap_build_data);
106 
107  add_method(DMR_RESPONSE, dap_build_dmr);
108  add_method(DAP4DATA_RESPONSE, dap_build_dap4data);
109 
110  add_method(VERS_RESPONSE, dap_build_vers);
111  add_method(HELP_RESPONSE, dap_build_help);
112 
113  read_key_value("DR.UseTestTypes", d_use_test_types, d_use_test_types_set);
114  read_key_value("DR.UseSeriesValues", d_use_series_values, d_use_series_values_set);
115 }
116 
123 void DapRequestHandler::load_dds_from_data_file(const string &accessed, DDS &dds)
124 {
125  BESDEBUG("dapreader", "In DapRequestHandler::load_dds_from_data_file; accessed: " << accessed << endl);
126 
127  TestTypeFactory t_factory;
128  BaseTypeFactory b_factory;
129  if (d_use_test_types)
130  dds.set_factory(&t_factory);
131  //valgrind shows the leaking caused by the following line. KY 2019-12-12
132  //dds.set_factory(new TestTypeFactory); // DDS deletes the factory
133  else
134  dds.set_factory(&b_factory);
135  //valgrind shows the leaking caused by the following line. KY 2019-12-12
136  //dds.set_factory(new BaseTypeFactory);
137 
138  auto_ptr<Connect> url(new Connect(accessed));
139  Response r(fopen(accessed.c_str(), "r"), 0);
140  if (!r.get_stream()) throw Error(string("The input source: ") + accessed + string(" could not be opened"));
141  url->read_data_no_mime(dds, &r);
142 
143  auto_ptr<DAS> das(new DAS);
144  Ancillary::read_ancillary_das(*das, accessed);
145 
146  if (das->get_size() > 0) dds.transfer_attributes(das.get());
147 
148  // This is needed for the values read to show up. Without it the default
149  // behavior of the TestTypes will take over and the values from the data files
150  // will be ignored.
151  for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; i++) {
152  (*i)->set_read_p(true);
153  }
154 }
155 
163 void DapRequestHandler::build_dds_from_file(const string &accessed, bool explicit_containers, DDS *dds)
164 {
165  BESDEBUG("dapreader", "In DapRequestHandler::build_dds_from_file; accessed: " << accessed << endl);
166 
167  if (extension_match(accessed, ".dds") && d_use_test_types) {
168  dds->set_factory(new TestTypeFactory);
169  dds->parse(accessed); // This sets the dataset name based on what's in the file
170 
171  DAS *das = new DAS;
172  Ancillary::read_ancillary_das(*das, accessed);
173 
174  if (das->get_size() > 0) dds->transfer_attributes(das);
175  }
176  else if (extension_match(accessed, ".dods") || extension_match(accessed, ".data")) {
177  if (explicit_containers) {
178  BESDEBUG("dapreader", "In DapRequestHandler::build_dds_from_file; in container code" << endl);
179  DDS local_dds(0);
180 
181  // This function reads from a .dods, ..., 'frozen response' and loads
182  // the values into a DDS's variables. It then merges the Attributes read
183  // from a matching .das file into those variables. The code in Connect
184  // that reads the values is not 'container safe' so we use this function
185  // to read value into a 'local dds' and then transfer its variables to
186  // the real BESDDSResponseObject, which is the DDS passed to this function
187  load_dds_from_data_file(accessed, local_dds);
188 
189  // Transfer variables just read into BESDDSResponse/BESDataDDSResponse's DDS
190  for (DDS::Vars_iter i = local_dds.var_begin(), e = local_dds.var_end(); i != e; i++) {
191  dds->add_var((*i)); // copy the variables; figure out how to not copy them
192  }
193 
194  dds->set_dataset_name(name_path(accessed));
195  }
196  else {
197  BESDEBUG("dapreader", "In DapRequestHandler::build_dds_from_file; in plain code" << endl);
198  // In the non-container case, reading the values is pretty straightforward
199  load_dds_from_data_file(accessed, *dds);
200  }
201 
202  dds->filename(accessed);
203  }
204  else {
205  throw Error("The dapreader module can only return DDS/DODS responses for files ending in .dods, .data or .dds");
206  }
207 
208  BESDEBUG("dapreader2", "DDS/DDX in DapRequestHandler::build_dds_from_file: ");
209  if (BESDebug::IsSet("dapreader2")) dds->print_xml(*(BESDebug::GetStrm()), false);
210 }
211 
212 void DapRequestHandler::build_dmr_from_file(const string& accessed, bool explicit_containers, DMR* dmr)
213 {
214  BESDEBUG("dapreader", "In DapRequestHandler::build_dmr_from_file; accessed: " << accessed << endl);
215 
216  dmr->set_filename(accessed);
217  dmr->set_name(name_path(accessed));
218 
219  D4TestTypeFactory TestFactory;
220  D4BaseTypeFactory BaseFactory;
221  if (d_use_test_types) {
222  dmr->set_factory(&TestFactory);
223  }
224  else {
225  dmr->set_factory(&BaseFactory);
226  }
227 
228  if ((extension_match(accessed, ".dmr") || extension_match(accessed, ".xml")) && d_use_test_types) {
229  D4ParserSax2 parser;
230  ifstream in(accessed.c_str(), ios::in);
231  parser.intern(in, dmr);
232  }
233  else if (extension_match(accessed, ".dap")) {
234  auto_ptr<D4Connect> url(new D4Connect(accessed));
235  fstream f(accessed.c_str(), std::ios_base::in);
236  if (!f.is_open() || f.bad() || f.eof()) throw Error((string) ("Could not open: ") + accessed);
237 
238  Response r(&f, 0);
239  // use the read_data...() method because we need to process the special
240  // binary glop in the data responses.
241  url->read_data_no_mime(*dmr, r);
242  }
243  else if (extension_match(accessed, ".dds") || extension_match(accessed, ".dods")
244  || extension_match(accessed, ".data")) {
245 
246  auto_ptr<DDS> dds(new DDS(0 /*factory*/));
247 
248  build_dds_from_file(accessed, explicit_containers, dds.get());
249 
250  dmr->build_using_dds(*dds);
251  }
252  else {
253  dmr->set_factory(0);
254  throw Error("The dapreader module can only return DMR/DAP responses for files ending in .dmr, .xml or .dap");
255  }
256 
257  dmr->set_factory(0);
258 }
259 
272 {
273  BESDEBUG(module, "Entering dap_build_dmr..." << endl);
274 
275  BESResponseObject *response = dhi.response_handler->get_response_object();
276  BESDMRResponse *bdmr = dynamic_cast<BESDMRResponse *>(response);
277  if (!bdmr) throw BESInternalError("BESDMRResponse cast error", __FILE__, __LINE__);
278 
279  try {
280  build_dmr_from_file(dhi.container->access(), bdmr->get_explicit_containers(), bdmr->get_dmr());
281 
282  bdmr->set_dap4_constraint(dhi);
283  bdmr->set_dap4_function(dhi);
284  }
285  catch (BESError &e) {
286  throw e;
287  }
288  catch (InternalErr & e) {
289  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
290  }
291  catch (Error & e) {
292  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
293  }
294  catch (...) {
295  throw BESInternalFatalError("Unknown exception caught building a DMR", __FILE__, __LINE__);
296  }
297 
298  BESDEBUG(module, "Leaving dap_build_dmr..." << endl);
299 
300  return true;
301 }
302 
303 // This method sets the stage for the BES DAP service to return a data
304 // response. Unlike the DAP2 data response returned by this module, the
305 // data are not read from a 'freeze-dried' DAP data response. Instead
306 // they are generated by the D4TestTypeFactory types. So, for now, asking
307 // for a DAP4 data response from this handler w/o setting UseTestTypes
308 // is an error.
309 bool DapRequestHandler::dap_build_dap4data(BESDataHandlerInterface &dhi)
310 {
311  BESDEBUG(module, "Entering dap_build_dap4data..." << endl);
312 
313  BESResponseObject *response = dhi.response_handler->get_response_object();
314  BESDMRResponse *bdmr = dynamic_cast<BESDMRResponse *>(response);
315  if (!bdmr) throw BESInternalError("BESDMRResponse cast error", __FILE__, __LINE__);
316 
317  try {
318  DMR *dmr = bdmr->get_dmr();
319  build_dmr_from_file(dhi.container->access(), bdmr->get_explicit_containers(), dmr);
320 
321  if (d_use_series_values) {
322  dmr->root()->set_read_p(false);
323 
324  TestCommon *tc = dynamic_cast<TestCommon*>(dmr->root());
325  if (tc)
326  tc->set_series_values(true);
327  else
328  throw Error("In the reader handler: Could not set UseSeriesValues");
329  }
330 
331  bdmr->set_dap4_constraint(dhi);
332  bdmr->set_dap4_function(dhi);
333  }
334  catch (BESError &e) {
335  throw e;
336  }
337  catch (InternalErr & e) {
338  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
339  }
340  catch (Error & e) {
341  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
342  }
343  catch (...) {
344  throw BESInternalFatalError("Unknown exception caught building DAP4 Data response", __FILE__, __LINE__);
345  }
346 
347  BESDEBUG(module, "Leaving dap_build_dap4data..." << endl);
348 
349  return false;
350 }
351 
360 {
361  BESResponseObject *response = dhi.response_handler->get_response_object();
362  BESDASResponse *bdas = dynamic_cast<BESDASResponse *>(response);
363  if (!bdas) throw BESInternalError("DAS cast error", __FILE__, __LINE__);
364  try {
366  DAS *das = bdas->get_das();
367  string accessed = dhi.container->access();
368 
369  if (extension_match(accessed, ".das")) {
370  das->parse(accessed);
371  }
372  else if (extension_match(accessed, ".dods") || extension_match(accessed, ".data")) {
373  Ancillary::read_ancillary_das(*das, accessed);
374  }
375  else {
376  throw Error(
377  "The dapreader module can only return DAS responses for files ending in .das or .dods/.data.\nIn the latter case there must be an ancillary das file present.");
378  }
379 
380  bdas->clear_container();
381  }
382  catch (BESError &e) {
383  throw e;
384  }
385  catch (InternalErr & e) {
386  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
387  }
388  catch (Error & e) {
389  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
390  }
391  catch (...) {
392  throw BESInternalFatalError("Unknown exception caught building DAS", __FILE__, __LINE__);
393  }
394 
395  return true;
396 }
397 
398 
399 bool DapRequestHandler::dap_build_dds(BESDataHandlerInterface &dhi)
400 {
401  BESDEBUG(module, "Entering dap_build_dds..." << endl);
402 
403  BESResponseObject *response = dhi.response_handler->get_response_object();
404  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *>(response);
405  if (!bdds) throw BESInternalError("DDS cast error", __FILE__, __LINE__);
406 
407  try {
409 
410  build_dds_from_file(dhi.container->access(), bdds->get_explicit_containers(), bdds->get_dds());
411 
412  bdds->set_constraint(dhi);
413  bdds->clear_container();
414  }
415  catch (BESError &e) {
416  throw e;
417  }
418  catch (InternalErr & e) {
419  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
420  }
421  catch (Error & e) {
422  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
423  }
424  catch (...) {
425  throw BESInternalFatalError("Unknown exception caught building DDS", __FILE__, __LINE__);
426  }
427 
428  BESDEBUG(module, "Exiting dap_build_dds..." << endl);
429 
430  return true;
431 }
432 
433 bool DapRequestHandler::dap_build_data(BESDataHandlerInterface &dhi)
434 {
435  BESDEBUG(module, "Entering dap_build_data..." << endl);
436 
437  BESResponseObject *response = dhi.response_handler->get_response_object();
438  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(response);
439  if (!bdds) throw BESInternalError("DDS cast error", __FILE__, __LINE__);
440 
441  try {
443 
444  build_dds_from_file(dhi.container->access(), bdds->get_explicit_containers(), bdds->get_dds());
445 
446  bdds->set_constraint(dhi);
447  bdds->clear_container();
448  }
449  catch (BESError &e) {
450  throw e;
451  }
452  catch (InternalErr & e) {
453  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
454  }
455  catch (Error & e) {
456  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
457  }
458  catch (...) {
459  throw BESInternalFatalError("Unknown exception caught building a data response", __FILE__, __LINE__);
460  }
461 
462  BESDEBUG(module, "Exiting dap_build_data..." << endl);
463 
464  return true;
465 }
466 
467 #if 0
468 void DapRequestHandler::add_attributes(BESDataHandlerInterface &dhi) {
469 
470  BESResponseObject *response = dhi.response_handler->get_response_object();
471  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(response);
472  if (!bdds)
473  throw BESInternalError("cast error", __FILE__, __LINE__);
474 
475  DDS *dds = bdds->get_dds();
476  string container_name = bdds->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
477  string dataset_name = dhi.container->access();
478  DAS* das = 0;
479  {
480  das = new DAS;
481  // This looks at the 'use explicit containers' prop, and if true
482  // sets the current container for the DAS.
483  if (!container_name.empty()) das->container_name(container_name);
484 
485  nc_read_dataset_attributes(*das, dataset_name);
486  Ancillary::read_ancillary_das(*das, dataset_name);
487 
488  dds->transfer_attributes(das);
489 
490  // Only free the DAS if it's not added to the cache
491  if (das_cache) {
492  // add a copy
493  BESDEBUG(NC_NAME, "DAS added to the cache for : " << dataset_name << endl);
494  das_cache->add(das, dataset_name);
495  }
496  else {
497  delete das;
498  }
499  }
500 
501  BESDEBUG(NC_NAME, "Data ACCESS in add_attributes(): set the including attribute flag to true: "<<dataset_name << endl);
502  bdds->set_ia_flag(true);
503  return;
504 }
505 #endif
506 
507 bool DapRequestHandler::dap_build_vers(BESDataHandlerInterface &dhi)
508 {
509  BESVersionInfo *info = dynamic_cast<BESVersionInfo *>(dhi.response_handler->get_response_object());
510  if (!info) throw BESInternalFatalError("Expected a BESVersionInfo instance.", __FILE__, __LINE__);
511 
512  info->add_module(DAPREADER_PACKAGE, DAPREADER_VERSION);
513  return true;
514 }
515 
516 bool DapRequestHandler::dap_build_help(BESDataHandlerInterface &dhi)
517 {
518  BESInfo *info = dynamic_cast<BESInfo *>(dhi.response_handler->get_response_object());
519  if (!info) throw BESInternalFatalError("Expected a BESVersionInfo instance.", __FILE__, __LINE__);
520 
521  // This is an example. If you had a help file you could load it like
522  // this and if your handler handled the following responses.
523  map<string, string> attrs;
524  attrs["name"] = DAPREADER_PACKAGE /* PACKAGE_NAME */;
525  attrs["version"] = DAPREADER_VERSION /* PACKAGE_VERSION */;
526  list<string> services;
527  BESServiceRegistry::TheRegistry()->services_handled(module, services);
528  if (services.size() > 0) {
529  string handles = BESUtil::implode(services, ',');
530  attrs["handles"] = handles;
531  }
532  info->begin_tag("module", &attrs);
533  info->end_tag("module");
534 
535  return true;
536 }
537 
538 void DapRequestHandler::dump(ostream &strm) const
539 {
540  strm << BESIndent::LMarg << "DapRequestHandler::dump - (" << (void *) this << ")" << endl;
541  BESIndent::Indent();
543  BESIndent::UnIndent();
544 }
545 
BESRequestHandler
Represents a specific data type request handler.
Definition: BESRequestHandler.h:74
BESDataHandlerInterface::container
BESContainer * container
pointer to current container in this interface
Definition: BESDataHandlerInterface.h:75
DapRequestHandler::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: DapRequestHandler.cc:538
BESServiceRegistry::services_handled
virtual void services_handled(const std::string &handler, std::list< std::string > &services)
returns the list of servies provided by the handler in question
Definition: BESServiceRegistry.cc:334
BESDapResponse::set_dap4_constraint
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:137
BESDDSResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDDSResponse.cc:64
BESInternalFatalError
exception thrown if an internal error is found and is fatal to the BES
Definition: BESInternalFatalError.h:43
BESDataDDSResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDataDDSResponse.cc:50
BESDapResponse::set_dap4_function
virtual void set_dap4_function(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:154
BESContainer::get_symbolic_name
std::string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:221
BESDDSResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDDSResponse.cc:73
BESDDSResponse::get_dds
libdap::DDS * get_dds()
Definition: BESDDSResponse.h:80
BESDASResponse
Represents an OPeNDAP DAS DAP2 data object within the BES.
Definition: BESDASResponse.h:44
BESInfo
informational response object
Definition: BESInfo.h:63
DapRequestHandler::dap_build_dmr
static bool dap_build_dmr(BESDataHandlerInterface &dhi)
Definition: DapRequestHandler.cc:271
BESDASResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDASResponse.cc:49
libdap
Definition: BESDapFunctionResponseCache.h:35
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESResponseHandler::get_response_object
virtual BESResponseObject * get_response_object()
return the current response object
Definition: BESResponseHandler.cc:82
BESVersionInfo
Definition: BESVersionInfo.h:47
BESDebug::IsSet
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:157
BESContainer::access
virtual std::string access()=0
returns the true name of this container
BESDapResponse::get_explicit_containers
bool get_explicit_containers() const
Should containers be explicitly represented in the DD* responses?
Definition: BESDapResponse.h:70
BESDataDDSResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDataDDSResponse.cc:59
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
TheBESKeys::get_value
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:272
BESDDSResponse
Holds a DDS object within the BES.
Definition: BESDDSResponse.h:50
BESDASResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDASResponse.cc:58
BESDapResponse::set_constraint
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:115
BESDataDDSResponse
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
Definition: BESDataDDSResponse.h:46
BESRequestHandler::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: BESRequestHandler.cc:163
Error
BESUtil::lowercase
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:200
BESUtil::implode
static std::string implode(const std::list< std::string > &values, char delim)
Definition: BESUtil.cc:638
BESDebug::GetStrm
static std::ostream * GetStrm()
return the debug stream
Definition: BESDebug.h:176
DapRequestHandler::dap_build_das
static bool dap_build_das(BESDataHandlerInterface &dhi)
Definition: DapRequestHandler.cc:359
BESDapError
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
BESDataHandlerInterface
Structure storing information used by the BES to handle the request.
Definition: BESDataHandlerInterface.h:56
BESError
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
BESResponseObject
Abstract base class representing a specific set of information in response to a request to the BES.
Definition: BESResponseObject.h:45
BESDMRResponse
Represents an OPeNDAP DMR DAP4 data object within the BES.
Definition: BESDMRResponse.h:39