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