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