OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
GDALRequestHandler.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of gdal_handler, a data handler for the OPeNDAP data
4 // server.
5 
6 // This file is part of the GDAL OPeNDAP Adapter
7 
8 // Copyright (c) 2004 OPeNDAP, Inc.
9 // Author: Frank Warmerdam <warmerdam@pobox.com>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 
28 // GDALRequestHandler.cc
29 
30 #include "config.h"
31 
32 #include <string>
33 #include <sstream>
34 
35 #include <DMR.h>
36 #include <mime_util.h>
37 #include <D4BaseTypeFactory.h>
38 #include <InternalErr.h>
39 #include <Ancillary.h>
40 #include <debug.h>
41 
42 #include <BESResponseHandler.h>
43 #include <BESResponseNames.h>
44 #include <BESDapNames.h>
45 #include <BESDASResponse.h>
46 #include <BESDDSResponse.h>
47 #include <BESDataDDSResponse.h>
48 #include <BESDMRResponse.h>
49 #include <BESVersionInfo.h>
50 #include <InternalErr.h>
51 #include <BESDapError.h>
52 #include <BESInternalFatalError.h>
53 #include <BESDataNames.h>
54 #include <TheBESKeys.h>
55 #include <BESUtil.h>
56 #include <Ancillary.h>
57 #include <BESServiceRegistry.h>
58 #include <BESUtil.h>
59 #include <BESContextManager.h>
60 
61 #include <BESDebug.h>
62 #include <TheBESKeys.h>
63 
64 #include "GDAL_DDS.h"
65 #include "GDAL_DMR.h"
66 #include "GDALRequestHandler.h"
67 
68 #define GDAL_NAME "gdal"
69 
70 using namespace libdap;
71 #if 0
72 bool GDALRequestHandler::_show_shared_dims = false;
73 bool GDALRequestHandler::_show_shared_dims_set = false;
74 bool GDALRequestHandler::_ignore_unknown_types = false;
75 bool GDALRequestHandler::_ignore_unknown_types_set = false;
76 #endif
77 
78 extern void gdal_read_dataset_attributes(DAS & das, const string & filename);
79 extern GDALDatasetH gdal_read_dataset_variables(DDS *dds, const string & filename);
80 
82  BESRequestHandler(name)
83 {
87 
90 
93 
94 #if 0
95  // See comments in the header about these... jhrg
96  if (GDALRequestHandler::_show_shared_dims_set == false) {
97  bool key_found = false, context_found = false;
98  // string key = "GDAL.ShowSharedDimensions";
99  string doset;
100  TheBESKeys::TheKeys()->get_value("GDAL.ShowSharedDimensions", doset, key_found);
101  // TODO Fix this so it works
102  string context_value = BESContextManager::TheManager()->get_context("xdap_accept", context_found);
103  //cerr << "context value: " << context_value << endl;
104  //cerr << "Testing values..." << endl;
105  if (key_found) {
106  //cerr << " Key found" << endl;
107  doset = BESUtil::lowercase(doset);
108  if (doset == "true" || doset == "yes") {
109  GDALRequestHandler::_show_shared_dims = true;
110  }
111  }
112  else if (context_found) {
113  //cerr << "context found" << endl;
114  if (version_ge(context_value, 3.2))
115  GDALRequestHandler::_show_shared_dims = false;
116  else
117  GDALRequestHandler::_show_shared_dims = true;
118  }
119  else {
120  //cerr << "Set default value" << endl;
121  GDALRequestHandler::_show_shared_dims = true;
122  }
123 
124  GDALRequestHandler::_show_shared_dims_set = true;
125  }
126 
127  if (GDALRequestHandler::_ignore_unknown_types_set == false) {
128  bool key_found = false;
129  string doset;
130  TheBESKeys::TheKeys()->get_value("GDAL.IgnoreUnknownTypes", doset, key_found);
131  if (key_found) {
132  doset = BESUtil::lowercase(doset);
133  if (doset == "true" || doset == "yes")
134  GDALRequestHandler::_ignore_unknown_types = true;
135  else
136  GDALRequestHandler::_ignore_unknown_types = false;
137  }
138  else {
139  // if the key is not found, set the default value
140  GDALRequestHandler::_ignore_unknown_types = false;
141  }
142 
143  GDALRequestHandler::_ignore_unknown_types_set = true;
144  }
145 #endif
146 }
147 
149 {
150 }
151 
153 {
155  BESDASResponse *bdas = dynamic_cast<BESDASResponse *> (response);
156  if (!bdas)
157  throw BESInternalError("cast error", __FILE__, __LINE__);
158  try {
160  DAS *das = bdas->get_das();
161  string accessed = dhi.container->access();
162  gdal_read_dataset_attributes(*das, accessed);
163  Ancillary::read_ancillary_das(*das, accessed);
164  bdas->clear_container();
165  }
166  catch (BESError &e) {
167  throw;
168  }
169  catch (InternalErr & e) {
170  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
171  }
172  catch (Error & e) {
173  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
174  }
175  catch (...) {
176  throw BESInternalFatalError("unknown exception caught building DAS", __FILE__, __LINE__);
177  }
178 
179  return true;
180 }
181 
183 {
184  DBG(cerr << "In GDALRequestHandler::gdal_build_dds" << endl);
185 
187  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *> (response);
188  if (!bdds)
189  throw BESInternalError("cast error", __FILE__, __LINE__);
190 
191  try {
193  DDS *dds = bdds->get_dds();
194 
195  string filename = dhi.container->access();
196  dds->filename(filename);
197  dds->set_dataset_name(filename.substr(filename.find_last_of('/') + 1));
198 
199  // Here the handler does not need the open dataset handle, so
200  // it closes it right away.
201  GDALDatasetH hDS = gdal_read_dataset_variables(dds, filename);
202  GDALClose(hDS);
203 
204  DAS *das = new DAS;
205  BESDASResponse bdas(das);
207  gdal_read_dataset_attributes(*das, filename);
208  Ancillary::read_ancillary_das(*das, filename);
209 
210  dds->transfer_attributes(das);
211  bdds->set_constraint(dhi);
212 
213  bdds->clear_container();
214  }
215  catch (BESError &e) {
216  throw;
217  }
218  catch (InternalErr & e) {
219  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
220  }
221  catch (Error & e) {
222  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
223  }
224  catch (...) {
225  throw BESInternalFatalError("unknown exception caught building DDS", __FILE__, __LINE__);
226  }
227 
228  return true;
229 }
230 
232 {
233  DBG(cerr << "In GDALRequestHandler::gdal_build_data" << endl);
234 
236  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *> (response);
237  if (!bdds)
238  throw BESInternalError("cast error", __FILE__, __LINE__);
239 
240  try {
242 
243  // This copies the vanilla DDS into a new GDALDDS object, where the
244  // handler can store extra information about the dataset.
245  GDALDDS *gdds = new GDALDDS(bdds->get_dds());
246 
247  // Now delete the old DDS object
248  delete bdds->get_dds();
249 
250  // Now make the BESDataDDSResponse object use our new object. When it
251  // deletes the GDALDDS, the GDAL library will be used to close the
252  // dataset.
253  bdds->set_dds(gdds);
254 
255  string filename = dhi.container->access();
256  gdds->filename(filename);
257  gdds->set_dataset_name(filename.substr(filename.find_last_of('/') + 1));
258 
259  // Save the dataset handle so that it can be closed later
260  // when the BES is done with the DDS (which is really a GDALDDS,
261  // spawn of DataDDS...)
262  GDALDatasetH hDS = gdal_read_dataset_variables(gdds, filename);
263  gdds->setGDALDataset(hDS);
264 
265  DAS *das = new DAS;
266  BESDASResponse bdas(das);
268  gdal_read_dataset_attributes(*das, filename);
269  Ancillary::read_ancillary_das(*das, filename);
270 
271  gdds->transfer_attributes(das);
272  bdds->set_constraint(dhi);
273 
274  bdds->clear_container();
275  }
276  catch (BESError &e) {
277  throw;
278  }
279  catch (InternalErr & e) {
280  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
281  }
282  catch (Error & e) {
283  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
284  }
285  catch (...) {
286  throw BESInternalFatalError("unknown exception caught building DAS", __FILE__, __LINE__);
287  }
288 
289  return true;
290 }
291 
293 {
294  // Because this code does not yet know how to build a DMR directly, use
295  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
296  // First step, build the 'full DDS'
297  string data_path = dhi.container->access();
298 
299  BaseTypeFactory factory;
300  DDS dds(&factory, name_path(data_path), "3.2");
301  dds.filename(data_path);
302 
303  GDALDatasetH hDS = 0; // Set in the following block but needed later.
304 
305  try {
306  hDS = gdal_read_dataset_variables(&dds, data_path);
307 
308  DAS das;
309  gdal_read_dataset_attributes(das, data_path);
310  Ancillary::read_ancillary_das(das, data_path);
311  dds.transfer_attributes(&das);
312  }
313  catch (InternalErr &e) {
314  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
315  }
316  catch (Error &e) {
317  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
318  }
319  catch (...) {
320  throw BESDapError("Caught unknown error building GDAL DMR response", true, unknown_error, __FILE__, __LINE__);
321  }
322 
323  // Extract the DMR Response object - this holds the DMR used by the
324  // other parts of the framework.
326  BESDMRResponse &bes_dmr = dynamic_cast<BESDMRResponse &>(*response);
327 
328  // In this handler we use a different pattern since the handler specializes the DDS/DMR.
329  // First, build the DMR adding the open handle to the GDAL dataset, then free the DMR
330  // the BES built and add this one. The GDALDMR object will close the open dataset when
331  // the BES runs the DMR's destructor.
332 
333  DMR *dmr = bes_dmr.get_dmr();
334  D4BaseTypeFactory d4_factory;
335  dmr->set_factory(&d4_factory);
336  dmr->build_using_dds(dds);
337 
338  GDALDMR *gdal_dmr = new GDALDMR(dmr);
339  gdal_dmr->setGDALDataset(hDS);
340  gdal_dmr->set_factory(0);
341 
342  delete dmr; // The call below will make 'dmr' unreachable; delete it now to avoid a leak.
343  bes_dmr.set_dmr(gdal_dmr); // BESDMRResponse will delete gdal_dmr
344 
345  // Instead of fiddling with the internal storage of the DHI object,
346  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
347  // methods to set the constraints. But, why? Ans: from Patrick is that
348  // in the 'container' mode of BES each container can have a different
349  // CE.
350  bes_dmr.set_dap4_constraint(dhi);
351  bes_dmr.set_dap4_function(dhi);
352 
353  return true;
354 }
355 
357 {
359  BESInfo *info = dynamic_cast<BESInfo *> (response);
360  if (!info)
361  throw BESInternalError("cast error", __FILE__, __LINE__);
362 
363  map < string, string > attrs;
364  attrs["name"] = MODULE_NAME ;
365  attrs["version"] = MODULE_VERSION ;
366 #if 0
367  attrs["name"] = PACKAGE_NAME;
368  attrs["version"] = PACKAGE_VERSION;
369 #endif
370  list < string > services;
372  if (services.size() > 0) {
373  string handles = BESUtil::implode(services, ',');
374  attrs["handles"] = handles;
375  }
376  info->begin_tag("module", &attrs);
377  info->end_tag("module");
378 
379  return true;
380 }
381 
383 {
385  BESVersionInfo *info = dynamic_cast<BESVersionInfo *> (response);
386  if (!info)
387  throw BESInternalError("cast error", __FILE__, __LINE__);
388 
389 #if 0
391 #endif
392  info->add_module(MODULE_NAME, MODULE_VERSION);
393 
394  return true;
395 }
brief represents simple text information in a response object, such as version and help inforamtion...
#define DAP4DATA_RESPONSE
Definition: BESDapNames.h:86
void set_dds(DataDDS *ddsIn)
Set the response object's DDS.
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
This specialization of DMR is used to manage the 'resource' of the open GDAL dataset handle so that t...
Definition: GDAL_DMR.h:41
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
This specialization of DDS is used to manage the 'resource' of the open GDAL dataset handle so that t...
Definition: GDAL_DDS.h:49
Represents an OPeNDAP DDS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
static bool gdal_build_das(BESDataHandlerInterface &dhi)
static bool gdal_build_dmr(BESDataHandlerInterface &dhi)
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
GDALRequestHandler(const string &name)
virtual string get_context(const string &name, bool &found)
retrieve the value of the specified context from the BES
static bool gdal_build_help(BESDataHandlerInterface &dhi)
virtual ~GDALRequestHandler(void)
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
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.
void setGDALDataset(const GDALDatasetH &hDSIn)
Definition: GDAL_DDS.h:77
virtual void clear_container()
clear the container in the DAP response object
Represents a specific data type request handler.
void gdal_read_dataset_attributes(DAS &das, const string &filename)
static BESContextManager * TheManager()
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
#define GDAL_NAME
void set_dmr(DMR *dmr)
Structure storing information used by the BES to handle the request.
GDALDatasetH gdal_read_dataset_variables(DDS *dds, const string &filename)
#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.
void setGDALDataset(const GDALDatasetH &hDSIn)
Definition: GDAL_DMR.h:70
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
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...
static bool gdal_build_version(BESDataHandlerInterface &dhi)
static bool gdal_build_data(BESDataHandlerInterface &dhi)
#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
static bool gdal_build_dds(BESDataHandlerInterface &dhi)