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
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 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
137bool 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
186bool 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
301bool 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
351bool 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
373bool 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
385void 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.