bes Updated for version 3.20.10
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 <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
65using namespace libdap;
66
67GDALRequestHandler::GDALRequestHandler(const string &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
83GDALRequestHandler::~GDALRequestHandler()
84{
85}
86
87bool 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
134bool 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
183bool 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
298bool 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
348bool 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
370bool 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
382void 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}
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
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
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:657
static bool gdal_build_dmr_using_dds(BESDataHandlerInterface &dhi)
Unused.