bes  Updated for version 3.20.6
GDALRequestHandler.cc
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 
34 #include <gdal.h>
35 
36 #include <DMR.h>
37 #include <mime_util.h> // name_path
38 #include <D4BaseTypeFactory.h>
39 #include <InternalErr.h>
40 #include <Ancillary.h>
41 
42 #include <BESResponseHandler.h>
43 #include <BESServiceRegistry.h>
44 
45 #include <BESResponseNames.h>
46 #include <BESDapNames.h>
47 
48 #include <BESDASResponse.h>
49 #include <BESDDSResponse.h>
50 #include <BESDataDDSResponse.h>
51 #include <BESDMRResponse.h>
52 #include <BESVersionInfo.h>
53 
54 #include <BESDapError.h>
55 #include <BESInternalFatalError.h>
56 #include <BESUtil.h>
57 
58 #include <BESDebug.h>
59 
60 #include "GDALRequestHandler.h"
61 #include "gdal_utils.h"
62 
63 #define GDAL_NAME "gdal"
64 
65 using namespace libdap;
66 
67 GDALRequestHandler::GDALRequestHandler(const string &name) :
68  BESRequestHandler(name)
69 {
70  add_method(DAS_RESPONSE, GDALRequestHandler::gdal_build_das);
71  add_method(DDS_RESPONSE, GDALRequestHandler::gdal_build_dds);
72  add_method(DATA_RESPONSE, GDALRequestHandler::gdal_build_data);
73 
74  add_method(DMR_RESPONSE, GDALRequestHandler::gdal_build_dmr);
75  add_method(DAP4DATA_RESPONSE, GDALRequestHandler::gdal_build_dmr);
76 
77  add_method(HELP_RESPONSE, GDALRequestHandler::gdal_build_help);
78  add_method(VERS_RESPONSE, GDALRequestHandler::gdal_build_version);
79 
80  GDALAllRegister();
81 }
82 
83 GDALRequestHandler::~GDALRequestHandler()
84 {
85 }
86 
87 bool GDALRequestHandler::gdal_build_das(BESDataHandlerInterface & dhi)
88 {
89  BESResponseObject *response = dhi.response_handler->get_response_object();
90  BESDASResponse *bdas = dynamic_cast<BESDASResponse *> (response);
91  if (!bdas)
92  throw BESInternalError("cast error", __FILE__, __LINE__);
93 
94  GDALDatasetH hDS = 0;
95  try {
97  DAS *das = bdas->get_das();
98  string filename = dhi.container->access();
99 
100  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
101 
102  if (hDS == NULL)
103  throw Error(string(CPLGetLastErrorMsg()));
104 
105  gdal_read_dataset_attributes(*das, hDS);
106 
107  GDALClose(hDS);
108  hDS = 0;
109 
110  Ancillary::read_ancillary_das(*das, filename);
111 
112  bdas->clear_container();
113  }
114  catch (BESError &e) {
115  if (hDS) GDALClose(hDS);
116  throw;
117  }
118  catch (InternalErr & e) {
119  if (hDS) GDALClose(hDS);
120  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
121  }
122  catch (Error & e) {
123  if (hDS) GDALClose(hDS);
124  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
125  }
126  catch (...) {
127  if (hDS) GDALClose(hDS);
128  throw BESInternalFatalError("unknown exception caught building DAS", __FILE__, __LINE__);
129  }
130 
131  return true;
132 }
133 
134 bool GDALRequestHandler::gdal_build_dds(BESDataHandlerInterface & dhi)
135 {
136  BESResponseObject *response = dhi.response_handler->get_response_object();
137  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *> (response);
138  if (!bdds)
139  throw BESInternalError("cast error", __FILE__, __LINE__);
140 
141  GDALDatasetH hDS = 0;
142  try {
144  DDS *dds = bdds->get_dds();
145 
146  string filename = dhi.container->access();
147  dds->filename(filename);
148  dds->set_dataset_name(name_path(filename)/*filename.substr(filename.find_last_of('/') + 1)*/);
149 
150  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
151 
152  if (hDS == NULL)
153  throw Error(string(CPLGetLastErrorMsg()));
154 
155  gdal_read_dataset_variables(dds, hDS, filename,true);
156 
157  GDALClose(hDS);
158  hDS = 0;
159 
160  bdds->set_constraint(dhi);
161  bdds->clear_container();
162  }
163  catch (BESError &e) {
164  if (hDS) GDALClose(hDS);
165  throw;
166  }
167  catch (InternalErr & e) {
168  if (hDS) GDALClose(hDS);
169  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
170  }
171  catch (Error & e) {
172  if (hDS) GDALClose(hDS);
173  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
174  }
175  catch (...) {
176  if (hDS) GDALClose(hDS);
177  throw BESInternalFatalError("unknown exception caught building DDS", __FILE__, __LINE__);
178  }
179 
180  return true;
181 }
182 
183 bool GDALRequestHandler::gdal_build_data(BESDataHandlerInterface & dhi)
184 {
185  BESResponseObject *response = dhi.response_handler->get_response_object();
186  // This lines is the sole difference between this static method and
187  // gdal_build_dds(...). jhrg 6/1/17
188  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *> (response);
189  if (!bdds)
190  throw BESInternalError("cast error", __FILE__, __LINE__);
191 
192  GDALDatasetH hDS = 0;
193  try {
195  DDS *dds = bdds->get_dds();
196 
197  string filename = dhi.container->access();
198  dds->filename(filename);
199  dds->set_dataset_name(name_path(filename)/*filename.substr(filename.find_last_of('/') + 1)*/);
200 
201  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
202 
203  if (hDS == NULL)
204  throw Error(string(CPLGetLastErrorMsg()));
205 
206  // The das will not be generated. KY 10/30/19
207  gdal_read_dataset_variables(dds, hDS, filename,false);
208 
209  GDALClose(hDS);
210  hDS = 0;
211 
212  bdds->set_constraint(dhi);
213  BESDEBUG("gdal", "Data ACCESS build_data(): set the including attribute flag to false: "<<filename << endl);
214  bdds->set_ia_flag(false);
215  bdds->clear_container();
216  }
217  catch (BESError &e) {
218  if (hDS) GDALClose(hDS);
219  throw;
220  }
221  catch (InternalErr & e) {
222  if (hDS) GDALClose(hDS);
223  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
224  }
225  catch (Error & e) {
226  if (hDS) GDALClose(hDS);
227  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
228  }
229  catch (...) {
230  if (hDS) GDALClose(hDS);
231  throw BESInternalFatalError("unknown exception caught building DAS", __FILE__, __LINE__);
232  }
233 
234  return true;
235 }
236 
243 {
244  // Because this code does not yet know how to build a DMR directly, use
245  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
246  // First step, build the 'full DDS'
247  string filename = dhi.container->access();
248 
249  BaseTypeFactory factory;
250  DDS dds(&factory, name_path(filename), "3.2");
251  dds.filename(filename);
252 
253  GDALDatasetH hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
254 
255  if (hDS == NULL)
256  throw Error(string(CPLGetLastErrorMsg()));
257 
258  try {
259  gdal_read_dataset_variables(&dds, hDS, filename,true);
260 
261  GDALClose(hDS);
262  hDS = 0;
263  }
264  catch (InternalErr &e) {
265  if (hDS) GDALClose(hDS);
266  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
267  }
268  catch (Error &e) {
269  if (hDS) GDALClose(hDS);
270  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
271  }
272  catch (...) {
273  if (hDS) GDALClose(hDS);
274  throw BESDapError("Caught unknown error building GDAL DMR response", true, unknown_error, __FILE__, __LINE__);
275  }
276 
277  // Extract the DMR Response object - this holds the DMR used by the
278  // other parts of the framework.
279  BESResponseObject *response = dhi.response_handler->get_response_object();
280  BESDMRResponse &bes_dmr = dynamic_cast<BESDMRResponse &>(*response);
281 
282  DMR *dmr = bes_dmr.get_dmr();
283  D4BaseTypeFactory d4_factory;
284  dmr->set_factory(&d4_factory);
285  dmr->build_using_dds(dds);
286 
287  // Instead of fiddling with the internal storage of the DHI object,
288  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
289  // methods to set the constraints. But, why? Ans: from Patrick is that
290  // in the 'container' mode of BES each container can have a different
291  // CE.
292  bes_dmr.set_dap4_constraint(dhi);
293  bes_dmr.set_dap4_function(dhi);
294 
295  return true;
296 }
297 
298 bool GDALRequestHandler::gdal_build_dmr(BESDataHandlerInterface &dhi)
299 {
300  // Extract the DMR Response object - this holds the DMR used by the
301  // other parts of the framework.
302  BESResponseObject *response = dhi.response_handler->get_response_object();
303  BESDMRResponse &bes_dmr = dynamic_cast<BESDMRResponse &>(*response);
304 
305  string filename = dhi.container->access();
306 
307  DMR *dmr = bes_dmr.get_dmr();
308  D4BaseTypeFactory d4_factory;
309  dmr->set_factory(&d4_factory);
310  dmr->set_filename(filename);
311  dmr->set_name(name_path(filename)/*filename.substr(filename.find_last_of('/') + 1)*/);
312 
313  GDALDatasetH hDS = 0;
314 
315  try {
316  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
317  if (hDS == NULL) throw Error(string(CPLGetLastErrorMsg()));
318 
319  gdal_read_dataset_variables(dmr, hDS, filename);
320 
321  GDALClose(hDS);
322  hDS = 0;
323  }
324  catch (InternalErr &e) {
325  if (hDS) GDALClose(hDS);
326  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
327  }
328  catch (Error &e) {
329  if (hDS) GDALClose(hDS);
330  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
331  }
332  catch (...) {
333  if (hDS) GDALClose(hDS);
334  throw BESDapError("Caught unknown error building GDAL DMR response", true, unknown_error, __FILE__, __LINE__);
335  }
336 
337  // Instead of fiddling with the internal storage of the DHI object,
338  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
339  // methods to set the constraints. But, why? Ans: from Patrick is that
340  // in the 'container' mode of BES each container can have a different
341  // CE.
342  bes_dmr.set_dap4_constraint(dhi);
343  bes_dmr.set_dap4_function(dhi);
344 
345  return true;
346 }
347 
348 bool GDALRequestHandler::gdal_build_help(BESDataHandlerInterface & dhi)
349 {
350  BESResponseObject *response = dhi.response_handler->get_response_object();
351  BESInfo *info = dynamic_cast<BESInfo *> (response);
352  if (!info)
353  throw BESInternalError("cast error", __FILE__, __LINE__);
354 
355  map < string, string > attrs;
356  attrs["name"] = MODULE_NAME ;
357  attrs["version"] = MODULE_VERSION ;
358  list < string > services;
359  BESServiceRegistry::TheRegistry()->services_handled(GDAL_NAME, services);
360  if (services.size() > 0) {
361  string handles = BESUtil::implode(services, ',');
362  attrs["handles"] = handles;
363  }
364  info->begin_tag("module", &attrs);
365  info->end_tag("module");
366 
367  return true;
368 }
369 
370 bool GDALRequestHandler::gdal_build_version(BESDataHandlerInterface & dhi)
371 {
372  BESResponseObject *response = dhi.response_handler->get_response_object();
373  BESVersionInfo *info = dynamic_cast<BESVersionInfo *> (response);
374  if (!info)
375  throw BESInternalError("cast error", __FILE__, __LINE__);
376 
377  info->add_module(MODULE_NAME, MODULE_VERSION);
378 
379  return true;
380 }
381 
382 void GDALRequestHandler::add_attributes(BESDataHandlerInterface &dhi) {
383 
384  BESResponseObject *response = dhi.response_handler->get_response_object();
385  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(response);
386  if (!bdds)
387  throw BESInternalError("cast error", __FILE__, __LINE__);
388  DDS *dds = bdds->get_dds();
389 
390  string container_name = bdds->get_explicit_containers() ? dhi.container->get_symbolic_name(): "";
391  string filename = dhi.container->access();
392 
393  GDALDatasetH hDS = 0;
394  DAS *das = NULL;
395 
396  try {
397 
398  das = new DAS;
399  // sets the current container for the DAS.
400  if (!container_name.empty()) das->container_name(container_name);
401 
402  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
403  if (hDS == NULL)
404  throw Error(string(CPLGetLastErrorMsg()));
405 
406  gdal_read_dataset_attributes(*das,hDS);
407  Ancillary::read_ancillary_das(*das, filename);
408 
409  dds->transfer_attributes(das);
410 
411  delete das;
412  GDALClose(hDS);
413  hDS = 0;
414  BESDEBUG("gdal", "Data ACCESS in add_attributes(): set the including attribute flag to true: "<<filename << endl);
415  bdds->set_ia_flag(true);
416 
417  }
418 
419  catch (BESError &e) {
420  if (hDS) GDALClose(hDS);
421  if (das) delete das;
422  throw;
423  }
424  catch (InternalErr & e) {
425  if (hDS) GDALClose(hDS);
426  if (das) delete das;
427  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
428  }
429  catch (Error & e) {
430  if (hDS) GDALClose(hDS);
431  if (das) delete das;
432  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
433  }
434  catch (...) {
435  if (hDS) GDALClose(hDS);
436  if (das) delete das;
437  throw BESInternalFatalError("unknown exception caught building DDS", __FILE__, __LINE__);
438  }
439 
440  return;
441 }
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
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
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
BESResponseHandler::get_response_object
virtual BESResponseObject * get_response_object()
return the current response object
Definition: BESResponseHandler.cc:82
BESVersionInfo
Definition: BESVersionInfo.h:47
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
GDALRequestHandler::gdal_build_dmr_using_dds
static bool gdal_build_dmr_using_dds(BESDataHandlerInterface &dhi)
Unused.
Definition: GDALRequestHandler.cc:242
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
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
Error
BESUtil::implode
static std::string implode(const std::list< std::string > &values, char delim)
Definition: BESUtil.cc:638
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