bes  Updated for version 3.20.6
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 <DDS.h>
35 #include <DataDDS.h>
36 #include <DMR.h>
37 #include <D4BaseTypeFactory.h>
38 #include <Ancillary.h>
39 #include <Error.h>
40 #include <InternalErr.h>
41 #include <mime_util.h>
42 #include <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 
67 using namespace libdap;
68 using namespace std;
69 
70 #define FF_NAME "ff"
71 
72 long BufPtr = 0; // cache pointer
73 long BufSiz = 0; // Cache size
74 char *BufVal = NULL; // cache buffer
75 
76 extern void ff_read_descriptors(DDS & dds, const string & filename);
77 extern void ff_get_attributes(DAS & das, string filename);
78 
79 bool FFRequestHandler::d_RSS_format_support = false;
80 string FFRequestHandler::d_RSS_format_files = "";
81 
82 bool FFRequestHandler::d_Regex_format_support = false;
83 std::map<string,string> FFRequestHandler::d_fmt_regex_map;
84 
85 FFRequestHandler::FFRequestHandler(const string &name) :
86  BESRequestHandler(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);
143  vector<string>::iterator it;
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 
162 FFRequestHandler::~FFRequestHandler()
163 {
164 }
165 
166 bool 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(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 
208 bool 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, 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 
255 bool 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, 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, 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 
365 bool 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 > 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 
391 bool 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 
BESRequestHandler
Represents a specific data type request handler.
Definition: BESRequestHandler.h:74
BESDataHandlerInterface::container
BESContainer * container
pointer to current container in this interface
Definition: BESDataHandlerInterface.h:75
BESServiceRegistry::services_handled
virtual void services_handled(const std::string &handler, std::list< std::string > &services)
returns the list of servies provided by the handler in question
Definition: BESServiceRegistry.cc:334
BESDapResponse::set_dap4_constraint
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:137
BESDDSResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDDSResponse.cc:64
BESInternalFatalError
exception thrown if an internal error is found and is fatal to the BES
Definition: BESInternalFatalError.h:43
BESDataDDSResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDataDDSResponse.cc:50
BESDapResponse::set_dap4_function
virtual void set_dap4_function(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:154
BESContainer::get_symbolic_name
std::string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:221
BESDDSResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDDSResponse.cc:73
BESDDSResponse::get_dds
libdap::DDS * get_dds()
Definition: BESDDSResponse.h:80
BESDASResponse
Represents an OPeNDAP DAS DAP2 data object within the BES.
Definition: BESDASResponse.h:44
BESInfo
informational response object
Definition: BESInfo.h:63
FFRequestHandler::ff_build_dmr
static bool ff_build_dmr(BESDataHandlerInterface &dhi)
Definition: FFRequestHandler.cc:307
BESDASResponse::set_container
virtual void set_container(const std::string &cn)
set the container in the DAP response object
Definition: BESDASResponse.cc:49
libdap
Definition: BESDapFunctionResponseCache.h:35
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESResponseHandler::get_response_object
virtual BESResponseObject * get_response_object()
return the current response object
Definition: BESResponseHandler.cc:82
BESVersionInfo
Definition: BESVersionInfo.h:47
BESContainer::access
virtual std::string access()=0
returns the true name of this container
BESDataDDSResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDataDDSResponse.cc:59
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
TheBESKeys::get_value
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:272
BESDDSResponse
Holds a DDS object within the BES.
Definition: BESDDSResponse.h:50
TheBESKeys::get_values
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.
Definition: TheBESKeys.cc:303
BESDASResponse::clear_container
virtual void clear_container()
clear the container in the DAP response object
Definition: BESDASResponse.cc:58
BESDapResponse::set_constraint
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
Definition: BESDapResponse.cc:115
BESDataDDSResponse
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
Definition: BESDataDDSResponse.h:46
Error
BESUtil::lowercase
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:200
BESUtil::implode
static std::string implode(const std::list< std::string > &values, char delim)
Definition: BESUtil.cc:638
BESDapError
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
BESDataHandlerInterface
Structure storing information used by the BES to handle the request.
Definition: BESDataHandlerInterface.h:56
BESResponseObject
Abstract base class representing a specific set of information in response to a request to the BES.
Definition: BESResponseObject.h:45
BESDMRResponse
Represents an OPeNDAP DMR DAP4 data object within the BES.
Definition: BESDMRResponse.h:39