bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
FFRequestHandler.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of ff_handler, a data handler for the OPeNDAP data
4// server.
5
6// Copyright (c) 2002,2003 OPeNDAP, Inc.
7// Author: James Gallagher <jgallagher@opendap.org>
8//
9// This is free software; you can redistribute it and/or modify it under the
10// terms of the GNU Lesser General Public License as published by the Free
11// Software Foundation; either version 2.1 of the License, or (at your
12// option) any later version.
13//
14// This software is distributed in the hope that it will be useful, but
15// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17// License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// FFRequestHandler.cc
26
27#include "config_ff.h"
28
29#include <iostream>
30#include <string>
31#include <sstream>
32#include <exception>
33
34#include <libdap/DDS.h>
35#include <libdap/DataDDS.h>
36#include <libdap/DMR.h>
37#include <libdap/D4BaseTypeFactory.h>
38#include <libdap/Ancillary.h>
39#include <libdap/Error.h>
40#include <libdap/InternalErr.h>
41#include <libdap/mime_util.h>
42#include <libdap/escaping.h>
43
44#include <BESResponseHandler.h>
45#include <BESResponseNames.h>
46#include <BESDapNames.h>
47#include <BESDASResponse.h>
48#include <BESDDSResponse.h>
49#include <BESDataDDSResponse.h>
50#include <BESDMRResponse.h>
51#include <BESVersionInfo.h>
52
53#include <BESDapError.h>
54#include <BESInternalFatalError.h>
55#include <BESDataNames.h>
56#include <TheBESKeys.h>
57#include <BESServiceRegistry.h>
58#include <BESUtil.h>
59#include <BESDebug.h>
60#include <BESContextManager.h>
61
62#include "FFRequestHandler.h"
63//#include "D4FFTypeFactory.h"
64#include "ff_ce_functions.h"
65#include "util_ff.h"
66
67using namespace libdap;
68using namespace std;
69
70#define FF_NAME "ff"
71
72long BufPtr = 0; // cache pointer
73long BufSiz = 0; // Cache size
74char *BufVal = NULL; // cache buffer
75
76extern void ff_read_descriptors(DDS & dds, const string & filename);
77extern void ff_get_attributes(DAS & das, string filename);
78
79bool FFRequestHandler::d_RSS_format_support = false;
80string FFRequestHandler::d_RSS_format_files = "";
81
82bool FFRequestHandler::d_Regex_format_support = false;
83std::map<string,string> FFRequestHandler::d_fmt_regex_map;
84
85FFRequestHandler::FFRequestHandler(const string &name) :
87{
88 add_method(DAS_RESPONSE, FFRequestHandler::ff_build_das);
89 add_method(DDS_RESPONSE, FFRequestHandler::ff_build_dds);
90 add_method(DATA_RESPONSE, FFRequestHandler::ff_build_data);
91
92 add_method(DMR_RESPONSE, FFRequestHandler::ff_build_dmr);
93 add_method(DAP4DATA_RESPONSE, FFRequestHandler::ff_build_dmr);
94
95 add_method(HELP_RESPONSE, FFRequestHandler::ff_build_help);
96 add_method(VERS_RESPONSE, FFRequestHandler::ff_build_version);
97
98 ff_register_functions();
99
100 bool key_found = false;
101 string doset;
102 TheBESKeys::TheKeys()->get_value("FF.RSSFormatSupport", doset, key_found);
103 if (key_found) {
104 doset = BESUtil::lowercase(doset);
105 if (doset == "true" || doset == "yes")
106 FFRequestHandler::d_RSS_format_support = true;
107 else
108 FFRequestHandler::d_RSS_format_support = false;
109 }
110 else
111 FFRequestHandler::d_RSS_format_support = false;
112
113 key_found = false;
114 string path;
115 TheBESKeys::TheKeys()->get_value("FF.RSSFormatFiles", path, key_found);
116 if (key_found)
117 FFRequestHandler::d_RSS_format_files = path;
118 else
119 FFRequestHandler::d_RSS_format_files = "";
120
121 BESDEBUG("ff", "d_RSS_format_support: " << d_RSS_format_support << endl);
122 BESDEBUG("ff", "d_RSS_format_files: " << d_RSS_format_files << endl);
123
124 // Set regex support for format files
125 key_found = false;
126 string regex_doset;
127 TheBESKeys::TheKeys()->get_value("FF.RegexFormatSupport", regex_doset, key_found);
128 if (key_found) {
129 regex_doset = BESUtil::lowercase(regex_doset);
130 if (regex_doset == "true" || regex_doset == "yes")
131 FFRequestHandler::d_Regex_format_support = true;
132 else
133 FFRequestHandler::d_Regex_format_support = false;
134 }
135 else
136 FFRequestHandler::d_Regex_format_support = false;
137 BESDEBUG("ff", "d_Regex_format_support: " << d_Regex_format_support << endl);
138
139 // Fill a map with regex and format file path
140 key_found = false;
141 vector<string> regex_fmt_files;
142 TheBESKeys::TheKeys()->get_values("FF.Regex", regex_fmt_files, key_found);
144 for (it = regex_fmt_files.begin(); it != regex_fmt_files.end(); it++) {
145 string fmt_entry = *it;
146 int index = fmt_entry.find(":");
147 if (index > 0) {
148 string regex = fmt_entry.substr(0, index);
149 string file = fmt_entry.substr(index + 1);
150 BESDEBUG("ff", "regex: '" << regex << "' file: " << file << endl);
151 d_fmt_regex_map.insert(pair<string, string>(regex, file));
152 } else {
153 throw BESInternalError(
154 string("The configuration entry for the ")
155 + "FF.Regex"
156 + " was incorrectly formatted. entry: "
157 + fmt_entry, __FILE__, __LINE__);
158 }
159 }
160}
161
162FFRequestHandler::~FFRequestHandler()
163{
164}
165
166bool FFRequestHandler::ff_build_das(BESDataHandlerInterface & dhi)
167{
168 BESResponseObject *response = dhi.response_handler->get_response_object();
169 BESDASResponse *bdas = dynamic_cast<BESDASResponse *>(response);
170 if (!bdas)
171 throw BESInternalError("cast error", __FILE__, __LINE__);
172
173 try {
175 DAS *das = bdas->get_das();
176
177 string accessed = dhi.container->access();
178 ff_get_attributes(*das, accessed);
179
180 string name;
181 if (FFRequestHandler::get_RSS_format_support()) {
182 name = find_ancillary_rss_das(accessed);
183 }
184 else {
185 name = Ancillary::find_ancillary_file(dhi.container->get_real_name()/*accessed*/, "das", "", "");
186 }
187
188 struct stat st;
189 if (!name.empty() && (stat(name.c_str(), &st) == 0)) {
190 das->parse(name);
191 }
192
193 bdas->clear_container();
194 } catch (InternalErr & e) {
195 BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
196 throw ex;
197 } catch (Error & e) {
198 BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
199 throw ex;
200 } catch (...) {
201 BESInternalFatalError ex("unknown exception caught building Freeform DAS", __FILE__, __LINE__);
202 throw ex;
203 }
204
205 return true;
206}
207
208bool FFRequestHandler::ff_build_dds(BESDataHandlerInterface & dhi)
209{
210 BESResponseObject *response = dhi.response_handler->get_response_object();
211 BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *>(response);
212 if (!bdds)
213 throw BESInternalError("cast error", __FILE__, __LINE__);
214
215 try {
217 DDS *dds = bdds->get_dds();
218 string accessed = dhi.container->access();
219 dds->filename(accessed);
220
221 BESDEBUG("ff", "FFRequestHandler::ff_build_dds, accessed: " << accessed << endl);
222
223 ff_read_descriptors(*dds, accessed);
224
225 BESDEBUG("ff", "FFRequestHandler::ff_build_dds, reading attributes" << endl);
226
227 DAS *das = new DAS;
228 BESDASResponse bdas(das);
230 ff_get_attributes(*das, accessed);
231 Ancillary::read_ancillary_das(*das, dhi.container->get_real_name() /*accessed*/);
232
233 BESDEBUG("ff", "FFRequestHandler::ff_build_dds, transferring attributes" << endl);
234
235 dds->transfer_attributes(das);
236
237 bdds->set_constraint(dhi);
238
239 bdds->clear_container();
240
241 } catch (InternalErr & e) {
242 BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
243 throw ex;
244 } catch (Error & e) {
245 BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
246 throw ex;
247 } catch (...) {
248 BESInternalFatalError ex("unknown exception caught building Freeform DDS", __FILE__, __LINE__);
249 throw ex;
250 }
251
252 return true;
253}
254
255bool FFRequestHandler::ff_build_data(BESDataHandlerInterface & dhi)
256{
257 BufPtr = 0; // cache pointer
258 BufSiz = 0; // Cache size
259 BufVal = NULL; // cache buffer
260
261 BESResponseObject *response = dhi.response_handler->get_response_object();
262 BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(response);
263 if (!bdds)
264 throw BESInternalError("cast error", __FILE__, __LINE__);
265 try {
267 DDS *dds = bdds->get_dds();
268 string accessed = dhi.container->access();
269 dds->filename(accessed);
270 ff_read_descriptors(*dds, accessed);
271 Ancillary::read_ancillary_dds(*dds, accessed);
272
273 DAS *das = new DAS;
274 BESDASResponse bdas(das);
276 ff_get_attributes(*das, accessed);
277 Ancillary::read_ancillary_das(*das, dhi.container->get_real_name() /*accessed*/);
278
279 dds->transfer_attributes(das);
280
281 bdds->set_constraint(dhi);
282
283 bdds->clear_container();
284 } catch (InternalErr & e) {
285 BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
286 throw ex;
287 } catch (Error & e) {
288 BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
289 throw ex;
290 } catch (...) {
291 BESInternalFatalError ex("unknown exception caught building Freeform DataDDS", __FILE__, __LINE__);
292 throw ex;
293 }
294
295 return true;
296}
297
308{
309 BufPtr = 0; // cache pointer
310 BufSiz = 0; // Cache size
311 BufVal = NULL; // cache buffer
312
313 // Because this code does not yet know how to build a DMR directly, use
314 // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
315 // First step, build the 'full DDS'
316 string data_path = dhi.container->access();
317
318 BaseTypeFactory factory;
319 DDS dds(&factory, name_path(data_path), "3.2");
320 dds.filename(data_path);
321
322 try {
323 ff_read_descriptors(dds, data_path);
324 // ancillary DDS objects never took off - this does nothing. jhrg 8/12/14
325 // Ancillary::read_ancillary_dds(*dds, data_path);
326
327 DAS das;
328 ff_get_attributes(das, data_path);
329 Ancillary::read_ancillary_das(das, dhi.container->get_real_name() /*data_path*/);
330 dds.transfer_attributes(&das);
331 }
332 catch (InternalErr &e) {
333 throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
334 }
335 catch (Error &e) {
336 throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
337 }
338 catch (...) {
339 throw BESDapError("Caught unknown error build FF DMR response", true, unknown_error, __FILE__, __LINE__);
340 }
341
342 // Extract the DMR Response object - this holds the DMR used by the
343 // other parts of the framework.
344 BESResponseObject *response = dhi.response_handler->get_response_object();
345 BESDMRResponse &bdmr = dynamic_cast<BESDMRResponse &>(*response);
346
347 // Extract the DMR Response object - this holds the DMR used by the
348 // other parts of the framework.
349 DMR *dmr = bdmr.get_dmr();
350 dmr->set_factory(new D4BaseTypeFactory);
351 dmr->build_using_dds(dds);
352
353 // Instead of fiddling with the internal storage of the DHI object,
354 // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
355 // methods to set the constraints. But, why? Maybe setting data[]
356 // directly is better? jhrg 8/14/14
357 bdmr.set_dap4_constraint(dhi);
358 bdmr.set_dap4_function(dhi);
359
360 // What about async and store_result? See BESDapTransmit::send_dap4_data()
361
362 return true;
363}
364
365bool FFRequestHandler::ff_build_help(BESDataHandlerInterface & dhi)
366{
367 BESResponseObject *response = dhi.response_handler->get_response_object();
368 BESInfo *info = dynamic_cast<BESInfo *>(response);
369 if (!info)
370 throw BESInternalError("cast error", __FILE__, __LINE__);
371
372 map < string, string, std::less<>> attrs;
373 attrs["name"] = MODULE_NAME ;
374 attrs["version"] = MODULE_VERSION ;
375#if 0
376 attrs["name"] = PACKAGE_NAME;
377 attrs["version"] = PACKAGE_VERSION;
378#endif
379 list < string > services;
380 BESServiceRegistry::TheRegistry()->services_handled(FF_NAME, services);
381 if (services.size() > 0) {
382 string handles = BESUtil::implode(services, ',');
383 attrs["handles"] = handles;
384 }
385 info->begin_tag("module", &attrs);
386 info->end_tag("module");
387
388 return true;
389}
390
391bool FFRequestHandler::ff_build_version(BESDataHandlerInterface & dhi)
392{
393 BESResponseObject *response = dhi.response_handler->get_response_object();
394 BESVersionInfo *info = dynamic_cast<BESVersionInfo *>(response);
395 if (!info)
396 throw BESInternalError("cast error", __FILE__, __LINE__);
397
398#if 0
399 info->add_module(PACKAGE_NAME, PACKAGE_VERSION);
400#endif
401 info->add_module(MODULE_NAME, MODULE_VERSION);
402
403 return true;
404}
405
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
std::string get_real_name() const
retrieve the real name for this container, such as a file name.
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
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
informational response object
Definition BESInfo.h:63
exception thrown if internal error encountered
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.
static std::string lowercase(const std::string &s)
Definition BESUtil.cc:257
static std::string implode(const std::list< std::string > &values, char delim)
Definition BESUtil.cc:620
static bool ff_build_dmr(BESDataHandlerInterface &dhi)
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
Definition TheBESKeys.cc:85
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.
STL iterator class.