OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
NCRequestHandler.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of nc_handler, a data handler for the OPeNDAP data
4 // server.
5 
6 // Copyright (c) 2002,2003 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This is free software; you can redistribute it and/or modify it under the
10 // terms of the GNU Lesser General Public License as published by the Free
11 // Software Foundation; either version 2.1 of the License, or (at your
12 // option) any later version.
13 //
14 // This software is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 // 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 OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 // NCRequestHandler.cc
26 
27 #include "config_nc.h"
28 
29 #include <string>
30 #include <sstream>
31 #include <exception>
32 
33 #include <DMR.h>
34 #include <mime_util.h>
35 #include <D4BaseTypeFactory.h>
36 
37 #include <BESResponseHandler.h>
38 #include <BESResponseNames.h>
39 #include <BESDapNames.h>
40 #include <BESDASResponse.h>
41 #include <BESDDSResponse.h>
42 #include <BESDataDDSResponse.h>
43 #include <BESVersionInfo.h>
44 
45 #include <BESDapError.h>
46 #include <BESInternalFatalError.h>
47 #include <BESDataNames.h>
48 #include <TheBESKeys.h>
49 #include <BESServiceRegistry.h>
50 #include <BESUtil.h>
51 #include <BESDebug.h>
52 #include <BESContextManager.h>
53 #include <BESDMRResponse.h>
54 
55 #include <InternalErr.h>
56 #include <Ancillary.h>
57 
58 #include "NCRequestHandler.h"
59 #if 0
60 #include "gridfields_functions.h"
61 #endif
62 
63 #define NC_NAME "nc"
64 
65 using namespace libdap;
66 
67 bool NCRequestHandler::_show_shared_dims = true;
68 bool NCRequestHandler::_show_shared_dims_set = false;
69 
70 bool NCRequestHandler::_ignore_unknown_types = false;
71 bool NCRequestHandler::_ignore_unknown_types_set = false;
72 
73 bool NCRequestHandler::_promote_byte_to_short = false;
74 bool NCRequestHandler::_promote_byte_to_short_set = false;
75 
76 extern void nc_read_dataset_attributes(DAS & das, const string & filename);
77 extern void nc_read_dataset_variables(DDS & dds, const string & filename);
78 
85 static bool version_ge(const string &version, float value)
86 {
87  try {
88  float v;
89  istringstream iss(version);
90  iss >> v;
91  //cerr << "version: " << v << ", value: " << value << endl;
92  return (v >= value);
93  }
94  catch (...) {
95  return false;
96  }
97 
98  return false; // quiet warnings...
99 }
100 
102  BESRequestHandler(name)
103 {
104  BESDEBUG("nc", "In NCRequestHandler::NCRequestHandler" << endl);
105 
109 
112 
115 
116  // Look for the SHowSharedDims property, if it has not been set
117  if (NCRequestHandler::_show_shared_dims_set == false) {
118  bool key_found = false;
119  string doset;
120  TheBESKeys::TheKeys()->get_value("NC.ShowSharedDimensions", doset, key_found);
121  if (key_found) {
122  // It was set in the conf file
123  NCRequestHandler::_show_shared_dims_set = true;
124 
125  doset = BESUtil::lowercase(doset);
126  if (doset == "true" || doset == "yes") {
127  NCRequestHandler::_show_shared_dims = true;
128  }
129  else
130  NCRequestHandler::_show_shared_dims = false;
131  }
132  }
133 
134  if (NCRequestHandler::_ignore_unknown_types_set == false) {
135  bool key_found = false;
136  string doset;
137  TheBESKeys::TheKeys()->get_value("NC.IgnoreUnknownTypes", doset, key_found);
138  if (key_found) {
139  doset = BESUtil::lowercase(doset);
140  if (doset == "true" || doset == "yes")
141  NCRequestHandler::_ignore_unknown_types = true;
142  else
143  NCRequestHandler::_ignore_unknown_types = false;
144 
145  NCRequestHandler::_ignore_unknown_types_set = true;
146  }
147  }
148 
149  if (NCRequestHandler::_promote_byte_to_short_set == false) {
150  bool key_found = false;
151  string doset;
152  TheBESKeys::TheKeys()->get_value("NC.PromoteByteToShort", doset, key_found);
153  if (key_found) {
154  doset = BESUtil::lowercase(doset);
155  if (doset == "true" || doset == "yes")
156  NCRequestHandler::_promote_byte_to_short = true;
157  else
158  NCRequestHandler::_promote_byte_to_short = false;
159 
160  NCRequestHandler::_promote_byte_to_short_set = true;
161  }
162  }
163 
164  BESDEBUG("nc", "Exiting NCRequestHandler::NCRequestHandler" << endl);
165 }
166 
168 {
169 }
170 
172 {
173  BESDEBUG("nc", "In NCRequestHandler::nc_build_das" << endl);
174 
176  BESDASResponse *bdas = dynamic_cast<BESDASResponse *> (response);
177  if (!bdas)
178  throw BESInternalError("cast error", __FILE__, __LINE__);
179  try {
181  DAS *das = bdas->get_das();
182  string accessed = dhi.container->access();
183  nc_read_dataset_attributes(*das, accessed);
184  Ancillary::read_ancillary_das(*das, accessed);
185  bdas->clear_container();
186  }
187  catch (BESError &e) {
188  throw;
189  }
190  catch (InternalErr & e) {
191  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
192  throw ex;
193  }
194  catch (Error & e) {
195  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
196  throw ex;
197  }
198  catch (std::exception &e) {
199  string s = string("C++ Exception: ") + e.what();
200  BESInternalFatalError ex(s, __FILE__, __LINE__);
201  throw ex;
202  }
203  catch (...) {
204  string s = "unknown exception caught building DAS";
205  BESInternalFatalError ex(s, __FILE__, __LINE__);
206  throw ex;
207  }
208 
209  BESDEBUG("nc", "Exiting NCRequestHandler::nc_build_das" << endl);
210  return true;
211 }
212 
214 {
216  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *> (response);
217  if (!bdds)
218  throw BESInternalError("cast error", __FILE__, __LINE__);
219 
220  try {
221  // If there's no value for this set in the conf file, look at the context
222  // and set the default behavior based on the protocol version clients say
223  // they will accept.
224  if (NCRequestHandler::_show_shared_dims_set == false) {
225  bool context_found = false;
226  string context_value = BESContextManager::TheManager()->get_context("xdap_accept", context_found);
227  if (context_found) {
228  BESDEBUG("nc", "xdap_accept: " << context_value << endl);
229  if (version_ge(context_value, 3.2))
230  NCRequestHandler::_show_shared_dims = false;
231  else
232  NCRequestHandler::_show_shared_dims = true;
233  }
234  }
235 
237  DDS *dds = bdds->get_dds();
238  string accessed = dhi.container->access();
239  dds->filename(accessed);
240 
241  nc_read_dataset_variables(*dds, accessed);
242 
243  BESDEBUG("nc", "NCRequestHandler::nc_build_dds, accessed: " << accessed << endl);
244 #if 0
245  Ancillary::read_ancillary_dds(*dds, accessed);
246 #endif
247 
248  DAS *das = new DAS;
249  BESDASResponse bdas(das);
251  nc_read_dataset_attributes(*das, accessed);
252  Ancillary::read_ancillary_das(*das, accessed);
253 
254  BESDEBUG("nc", "Prior to dds->transfer_attributes" << endl);
255 
256  dds->transfer_attributes(das);
257 
258 #if 0
259  ConstraintEvaluator & ce = bdds->get_ce();
260  ce.add_function("ugrid_restrict", function_ugrid_restrict);
261 #endif
262 
263  bdds->set_constraint(dhi);
264 
265  bdds->clear_container();
266  }
267  catch (BESError &e) {
268  throw e;
269  }
270  catch (InternalErr & e) {
271  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
272  throw ex;
273  }
274  catch (Error & e) {
275  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
276  throw ex;
277  }
278  catch (std::exception &e) {
279  string s = string("C++ Exception: ") + e.what();
280  BESInternalFatalError ex(s, __FILE__, __LINE__);
281  throw ex;
282  }
283  catch (...) {
284  string s = "unknown exception caught building DDS";
285  BESInternalFatalError ex(s, __FILE__, __LINE__);
286  throw ex;
287  }
288 
289  return true;
290 }
291 
293 {
295  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *> (response);
296  if (!bdds)
297  throw BESInternalError("cast error", __FILE__, __LINE__);
298 
299  try {
300  if (NCRequestHandler::_show_shared_dims_set == false) {
301  bool context_found = false;
302  string context_value = BESContextManager::TheManager()->get_context("xdap_accept", context_found);
303  if (context_found) {
304  BESDEBUG("nc", "xdap_accept: " << context_value << endl);
305  if (version_ge(context_value, 3.2))
306  NCRequestHandler::_show_shared_dims = false;
307  else
308  NCRequestHandler::_show_shared_dims = true;
309  }
310  }
311 
313  DataDDS *dds = bdds->get_dds();
314  string accessed = dhi.container->access();
315  dds->filename(accessed);
316 
317  nc_read_dataset_variables(*dds, accessed);
318 
319 #if 0
320  Ancillary::read_ancillary_dds(*dds, accessed);
321 #endif
322  DAS *das = new DAS;
323  BESDASResponse bdas(das);
325  nc_read_dataset_attributes(*das, accessed);
326  Ancillary::read_ancillary_das(*das, accessed);
327 
328  dds->transfer_attributes(das);
329 
330 #if 0
331  ConstraintEvaluator & ce = bdds->get_ce();
332  ce.add_function("ugrid_restrict", function_ugrid_restrict);
333 #endif
334 
335  bdds->set_constraint(dhi);
336  bdds->clear_container();
337  }
338  catch (BESError &e) {
339  throw;
340  }
341  catch (InternalErr & e) {
342  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
343  throw ex;
344  }
345  catch (Error & e) {
346  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
347  throw ex;
348  }
349  catch (std::exception &e) {
350  string s = string("C++ Exception: ") + e.what();
351  BESInternalFatalError ex(s, __FILE__, __LINE__);
352  throw ex;
353  }
354  catch (...) {
355  string s = "unknown exception caught building DAS";
356  BESInternalFatalError ex(s, __FILE__, __LINE__);
357  throw ex;
358  }
359 
360  return true;
361 }
362 
364 {
365  // Because this code does not yet know how to build a DMR directly, use
366  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
367  // First step, build the 'full DDS'
368  string data_path = dhi.container->access();
369 
370  BaseTypeFactory factory;
371  DDS dds(&factory, name_path(data_path), "3.2");
372  dds.filename(data_path);
373 
374  try {
375  nc_read_dataset_variables(dds, data_path);
376 
377  DAS das;
378  nc_read_dataset_attributes(das, data_path);
379  Ancillary::read_ancillary_das(das, data_path);
380  dds.transfer_attributes(&das);
381  }
382  catch (InternalErr &e) {
383  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
384  }
385  catch (Error &e) {
386  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
387  }
388  catch (...) {
389  throw BESDapError("Caught unknown error build NC DMR response", true, unknown_error, __FILE__, __LINE__);
390  }
391 
392  // Extract the DMR Response object - this holds the DMR used by the
393  // other parts of the framework.
395  BESDMRResponse &bdmr = dynamic_cast<BESDMRResponse &>(*response);
396 
397  // Get the DMR made by the BES in the BES/dap/BESDMRResponseHandler, make sure there's a
398  // factory we can use and then dump the DAP2 variables and attributes in using the
399  // BaseType::transform_to_dap4() method that transforms individual variables
400  DMR *dmr = bdmr.get_dmr();
401  dmr->set_factory(new D4BaseTypeFactory);
402  dmr->build_using_dds(dds);
403 
404  // Instead of fiddling with the internal storage of the DHI object,
405  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
406  // methods to set the constraints. But, why? Ans: from Patrick is that
407  // in the 'container' mode of BES each container can have a different
408  // CE.
409  bdmr.set_dap4_constraint(dhi);
410  bdmr.set_dap4_function(dhi);
411 
412  // What about async and store_result? See BESDapTransmit::send_dap4_data()
413 
414  return true;
415 }
416 
418 {
420  BESInfo *info = dynamic_cast<BESInfo *> (response);
421  if (!info)
422  throw BESInternalError("cast error", __FILE__, __LINE__);
423 
424  map < string, string > attrs;
425  attrs["name"] = MODULE_NAME ;
426  attrs["version"] = MODULE_VERSION ;
427 #if 0
428  attrs["name"] = PACKAGE_NAME;
429  attrs["version"] = PACKAGE_VERSION;
430 #endif
431  list < string > services;
433  if (services.size() > 0) {
434  string handles = BESUtil::implode(services, ',');
435  attrs["handles"] = handles;
436  }
437  info->begin_tag("module", &attrs);
438  info->end_tag("module");
439 
440  return true;
441 }
442 
444 {
446  BESVersionInfo *info = dynamic_cast<BESVersionInfo *> (response);
447  if (!info)
448  throw BESInternalError("cast error", __FILE__, __LINE__);
449 
450 #if 0
452 #endif
453  info->add_module(MODULE_NAME, MODULE_VERSION);
454 
455  return true;
456 }
static bool nc_build_version(BESDataHandlerInterface &dhi)
virtual ~NCRequestHandler(void)
brief represents simple text information in a response object, such as version and help inforamtion...
#define DAP4DATA_RESPONSE
Definition: BESDapNames.h:86
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
#define DMR_RESPONSE
Definition: BESDapNames.h:81
ConstraintEvaluator & get_ce()
string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:197
static string lowercase(const string &s)
Convert a string to all lower case.
Definition: BESUtil.cc:182
Represents an OPeNDAP DDS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
static bool nc_build_dds(BESDataHandlerInterface &dhi)
virtual string get_context(const string &name, bool &found)
retrieve the value of the specified context from the BES
static bool nc_build_das(BESDataHandlerInterface &dhi)
void nc_read_dataset_attributes(DAS &das, const string &filename)
Given a reference to an instance of class DAS and a filename that refers to a netcdf file...
Definition: ncdas.cc:548
static class NCMLUtil overview
virtual string access()=0
returns the true name of this container
virtual void clear_container()
clear the container in the DAP response object
#define HELP_RESPONSE
void nc_read_dataset_variables(DDS &dds, const string &filename)
Given a reference to an instance of class DDS and a filename that refers to a netcdf file...
Definition: ncdds.cc:610
virtual void set_dap4_function(BESDataHandlerInterface &dhi)
set the constraint depending on the context
informational response object
Definition: BESInfo.h:68
static string implode(const list< string > &values, char delim)
implode a list of values into a single string delimited by delim
Definition: BESUtil.cc:602
virtual BESResponseObject * get_response_object()
return the current response object
Abstract exception class for the BES with basic string message.
Definition: BESError.h:51
#define PACKAGE_NAME
Definition: config.h:244
#define DATA_RESPONSE
Definition: BESDapNames.h:70
static BESServiceRegistry * TheRegistry()
BESResponseHandler * response_handler
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
virtual void begin_tag(const string &tag_name, map< string, string > *attrs=0)
Definition: BESInfo.cc:127
Represents an OPeNDAP DMR DAP4 data object within the BES.
virtual void set_container(const string &cn)
set the container in the DAP response object
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:51
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
Represents a specific data type request handler.
static BESContextManager * TheManager()
NCRequestHandler(const string &name)
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
static bool nc_build_dmr(BESDataHandlerInterface &dhi)
ConstraintEvaluator & get_ce()
Structure storing information used by the BES to handle the request.
static bool nc_build_data(BESDataHandlerInterface &dhi)
static bool nc_build_help(BESDataHandlerInterface &dhi)
#define VERS_RESPONSE
virtual void set_container(const string &cn)
set the container in the DAP response object
virtual bool add_handler(const string &handler_name, p_request_handler handler_method)
add a handler method to the request handler that knows how to fill in a specific response object ...
#define PACKAGE_VERSION
Definition: config.h:256
Represents an OPeNDAP DAS DAP2 data object within the BES.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
#define NC_NAME
virtual void set_container(const string &cn)
set the container in the DAP response object
virtual void add_module(const string &n, const string &v)
Abstract base class representing a specific set of information in response to a request to the BES...
#define DDS_RESPONSE
Definition: BESDapNames.h:60
BESContainer * container
pointer to current container in this interface
#define DAS_RESPONSE
Definition: BESDapNames.h:55
virtual void end_tag(const string &tag_name)
Definition: BESInfo.cc:132
virtual void services_handled(const string &handler, list< string > &services)
returns the list of servies provided by the handler in question