bes  Updated for version 3.20.5
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);
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  gdal_read_dataset_variables(dds, hDS, filename);
207 
208  GDALClose(hDS);
209  hDS = 0;
210 
211  bdds->set_constraint(dhi);
212  bdds->clear_container();
213  }
214  catch (BESError &e) {
215  if (hDS) GDALClose(hDS);
216  throw;
217  }
218  catch (InternalErr & e) {
219  if (hDS) GDALClose(hDS);
220  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
221  }
222  catch (Error & e) {
223  if (hDS) GDALClose(hDS);
224  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
225  }
226  catch (...) {
227  if (hDS) GDALClose(hDS);
228  throw BESInternalFatalError("unknown exception caught building DAS", __FILE__, __LINE__);
229  }
230 
231  return true;
232 }
233 
240 {
241  // Because this code does not yet know how to build a DMR directly, use
242  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
243  // First step, build the 'full DDS'
244  string filename = dhi.container->access();
245 
246  BaseTypeFactory factory;
247  DDS dds(&factory, name_path(filename), "3.2");
248  dds.filename(filename);
249 
250  GDALDatasetH hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
251 
252  if (hDS == NULL)
253  throw Error(string(CPLGetLastErrorMsg()));
254 
255  try {
256  gdal_read_dataset_variables(&dds, hDS, filename);
257 
258  GDALClose(hDS);
259  hDS = 0;
260  }
261  catch (InternalErr &e) {
262  if (hDS) GDALClose(hDS);
263  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
264  }
265  catch (Error &e) {
266  if (hDS) GDALClose(hDS);
267  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
268  }
269  catch (...) {
270  if (hDS) GDALClose(hDS);
271  throw BESDapError("Caught unknown error building GDAL DMR response", true, unknown_error, __FILE__, __LINE__);
272  }
273 
274  // Extract the DMR Response object - this holds the DMR used by the
275  // other parts of the framework.
276  BESResponseObject *response = dhi.response_handler->get_response_object();
277  BESDMRResponse &bes_dmr = dynamic_cast<BESDMRResponse &>(*response);
278 
279  DMR *dmr = bes_dmr.get_dmr();
280  D4BaseTypeFactory d4_factory;
281  dmr->set_factory(&d4_factory);
282  dmr->build_using_dds(dds);
283 
284  // Instead of fiddling with the internal storage of the DHI object,
285  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
286  // methods to set the constraints. But, why? Ans: from Patrick is that
287  // in the 'container' mode of BES each container can have a different
288  // CE.
289  bes_dmr.set_dap4_constraint(dhi);
290  bes_dmr.set_dap4_function(dhi);
291 
292  return true;
293 }
294 
295 bool GDALRequestHandler::gdal_build_dmr(BESDataHandlerInterface &dhi)
296 {
297  // Extract the DMR Response object - this holds the DMR used by the
298  // other parts of the framework.
299  BESResponseObject *response = dhi.response_handler->get_response_object();
300  BESDMRResponse &bes_dmr = dynamic_cast<BESDMRResponse &>(*response);
301 
302  string filename = dhi.container->access();
303 
304  DMR *dmr = bes_dmr.get_dmr();
305  D4BaseTypeFactory d4_factory;
306  dmr->set_factory(&d4_factory);
307  dmr->set_filename(filename);
308  dmr->set_name(name_path(filename)/*filename.substr(filename.find_last_of('/') + 1)*/);
309 
310  GDALDatasetH hDS = 0;
311 
312  try {
313  hDS = GDALOpen(filename.c_str(), GA_ReadOnly);
314  if (hDS == NULL) throw Error(string(CPLGetLastErrorMsg()));
315 
316  gdal_read_dataset_variables(dmr, hDS, filename);
317 
318  GDALClose(hDS);
319  hDS = 0;
320  }
321  catch (InternalErr &e) {
322  if (hDS) GDALClose(hDS);
323  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
324  }
325  catch (Error &e) {
326  if (hDS) GDALClose(hDS);
327  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
328  }
329  catch (...) {
330  if (hDS) GDALClose(hDS);
331  throw BESDapError("Caught unknown error building GDAL DMR response", true, unknown_error, __FILE__, __LINE__);
332  }
333 
334  // Instead of fiddling with the internal storage of the DHI object,
335  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
336  // methods to set the constraints. But, why? Ans: from Patrick is that
337  // in the 'container' mode of BES each container can have a different
338  // CE.
339  bes_dmr.set_dap4_constraint(dhi);
340  bes_dmr.set_dap4_function(dhi);
341 
342  return true;
343 }
344 
345 bool GDALRequestHandler::gdal_build_help(BESDataHandlerInterface & dhi)
346 {
347  BESResponseObject *response = dhi.response_handler->get_response_object();
348  BESInfo *info = dynamic_cast<BESInfo *> (response);
349  if (!info)
350  throw BESInternalError("cast error", __FILE__, __LINE__);
351 
352  map < string, string > attrs;
353  attrs["name"] = MODULE_NAME ;
354  attrs["version"] = MODULE_VERSION ;
355  list < string > services;
356  BESServiceRegistry::TheRegistry()->services_handled(GDAL_NAME, services);
357  if (services.size() > 0) {
358  string handles = BESUtil::implode(services, ',');
359  attrs["handles"] = handles;
360  }
361  info->begin_tag("module", &attrs);
362  info->end_tag("module");
363 
364  return true;
365 }
366 
367 bool GDALRequestHandler::gdal_build_version(BESDataHandlerInterface & dhi)
368 {
369  BESResponseObject *response = dhi.response_handler->get_response_object();
370  BESVersionInfo *info = dynamic_cast<BESVersionInfo *> (response);
371  if (!info)
372  throw BESInternalError("cast error", __FILE__, __LINE__);
373 
374  info->add_module(MODULE_NAME, MODULE_VERSION);
375 
376  return true;
377 }
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
Holds a DDS object within the BES.
virtual void clear_container()
clear the container in the DAP response object
libdap::DDS * get_dds()
static bool gdal_build_dmr_using_dds(BESDataHandlerInterface &dhi)
Unused.
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
virtual void set_container(const std::string &cn)
set the container in the DAP response object
virtual string access()=0
returns the true name of this container
virtual void clear_container()
clear the container in the DAP response object
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)
Definition: BESUtil.cc:635
virtual BESResponseObject * get_response_object()
return the current response object
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
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
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.
Structure storing information used by the BES to handle the request.
virtual void set_container(const string &cn)
set the container in the DAP response object
Represents an OPeNDAP DAS DAP2 data object within the BES.
virtual void set_container(const string &cn)
set the container in the DAP response object
Abstract base class representing a specific set of information in response to a request to the BES.
BESContainer * container
pointer to current container in this interface
virtual void services_handled(const string &handler, list< string > &services)
returns the list of servies provided by the handler in question
string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:224