bes  Updated for version 3.20.5
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 
266  try {
268  DDS *dds = bdds->get_dds();
269  string accessed = dhi.container->access();
270  dds->filename(accessed);
271  ff_read_descriptors(*dds, accessed);
272  Ancillary::read_ancillary_dds(*dds, accessed);
273 
274  DAS *das = new DAS;
275  BESDASResponse bdas(das);
277  ff_get_attributes(*das, accessed);
278  Ancillary::read_ancillary_das(*das, accessed);
279 
280  dds->transfer_attributes(das);
281 
282  bdds->set_constraint(dhi);
283 
284  bdds->clear_container();
285  } catch (InternalErr & e) {
286  BESDapError ex(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
287  throw ex;
288  } catch (Error & e) {
289  BESDapError ex(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
290  throw ex;
291  } catch (...) {
292  BESInternalFatalError ex("unknown exception caught building Freeform DataDDS", __FILE__, __LINE__);
293  throw ex;
294  }
295 
296  return true;
297 }
298 
309 {
310  BufPtr = 0; // cache pointer
311  BufSiz = 0; // Cache size
312  BufVal = NULL; // cache buffer
313 
314  // Because this code does not yet know how to build a DMR directly, use
315  // the DMR ctor that builds a DMR using a 'full DDS' (a DDS with attributes).
316  // First step, build the 'full DDS'
317  string data_path = dhi.container->access();
318 
319  BaseTypeFactory factory;
320  DDS dds(&factory, name_path(data_path), "3.2");
321  dds.filename(data_path);
322 
323  try {
324  ff_read_descriptors(dds, data_path);
325  // ancillary DDS objects never took off - this does nothing. jhrg 8/12/14
326  // Ancillary::read_ancillary_dds(*dds, data_path);
327 
328  DAS das;
329  ff_get_attributes(das, data_path);
330  Ancillary::read_ancillary_das(das, data_path);
331  dds.transfer_attributes(&das);
332  }
333  catch (InternalErr &e) {
334  throw BESDapError(e.get_error_message(), true, e.get_error_code(), __FILE__, __LINE__);
335  }
336  catch (Error &e) {
337  throw BESDapError(e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
338  }
339  catch (...) {
340  throw BESDapError("Caught unknown error build FF DMR response", true, unknown_error, __FILE__, __LINE__);
341  }
342 
343  // Extract the DMR Response object - this holds the DMR used by the
344  // other parts of the framework.
345  BESResponseObject *response = dhi.response_handler->get_response_object();
346  BESDMRResponse &bdmr = dynamic_cast<BESDMRResponse &>(*response);
347 
348  // Extract the DMR Response object - this holds the DMR used by the
349  // other parts of the framework.
350  DMR *dmr = bdmr.get_dmr();
351  dmr->set_factory(new D4BaseTypeFactory);
352  dmr->build_using_dds(dds);
353 
354  // Instead of fiddling with the internal storage of the DHI object,
355  // (by setting dhi.data[DAP4_CONSTRAINT], etc., directly) use these
356  // methods to set the constraints. But, why? Maybe setting data[]
357  // directly is better? jhrg 8/14/14
358  bdmr.set_dap4_constraint(dhi);
359  bdmr.set_dap4_function(dhi);
360 
361  // What about async and store_result? See BESDapTransmit::send_dap4_data()
362 
363  return true;
364 }
365 
366 bool FFRequestHandler::ff_build_help(BESDataHandlerInterface & dhi)
367 {
368  BESResponseObject *response = dhi.response_handler->get_response_object();
369  BESInfo *info = dynamic_cast<BESInfo *>(response);
370  if (!info)
371  throw BESInternalError("cast error", __FILE__, __LINE__);
372 
373  map < string, string > attrs;
374  attrs["name"] = MODULE_NAME ;
375  attrs["version"] = MODULE_VERSION ;
376 #if 0
377  attrs["name"] = PACKAGE_NAME;
378  attrs["version"] = PACKAGE_VERSION;
379 #endif
380  list < string > services;
381  BESServiceRegistry::TheRegistry()->services_handled(FF_NAME, services);
382  if (services.size() > 0) {
383  string handles = BESUtil::implode(services, ',');
384  attrs["handles"] = handles;
385  }
386  info->begin_tag("module", &attrs);
387  info->end_tag("module");
388 
389  return true;
390 }
391 
392 bool FFRequestHandler::ff_build_version(BESDataHandlerInterface & dhi)
393 {
394  BESResponseObject *response = dhi.response_handler->get_response_object();
395  BESVersionInfo *info = dynamic_cast<BESVersionInfo *>(response);
396  if (!info)
397  throw BESInternalError("cast error", __FILE__, __LINE__);
398 
399 #if 0
400  info->add_module(PACKAGE_NAME, PACKAGE_VERSION);
401 #endif
402  info->add_module(MODULE_NAME, MODULE_VERSION);
403 
404  return true;
405 }
406 
407 
static bool ff_build_dmr(BESDataHandlerInterface &dhi)
exception thrown if an internal error is found and is fatal to the BES
exception thrown if inernal error encountered
static string lowercase(const string &s)
Definition: BESUtil.cc:197
Holds a DDS object within the BES.
virtual void clear_container()
clear the container in the DAP response object
libdap::DDS * get_dds()
virtual void set_dap4_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:420
virtual void set_container(const std::string &cn)
set the container in the DAP response object
virtual 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_dap4_function(BESDataHandlerInterface &dhi)
set the constraint depending on the context
informational response object
Definition: BESInfo.h:68
static string implode(const list< string > &values, char delim)
Definition: BESUtil.cc:635
virtual BESResponseObject * get_response_object()
return the current response object
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:61
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:451
virtual void set_constraint(BESDataHandlerInterface &dhi)
set the constraint depending on the context
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
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
virtual void clear_container()
clear the container in the DAP response object
Represents a specific data type request handler.
Structure storing information used by the BES to handle the request.
virtual void set_container(const string &cn)
set the container in the DAP response object
Represents an OPeNDAP DAS DAP2 data object within the BES.
virtual void set_container(const string &cn)
set the container in the DAP response object
Abstract base class representing a specific set of information in response to a request to the BES.
BESContainer * container
pointer to current container in this interface
virtual void services_handled(const string &handler, list< string > &services)
returns the list of servies provided by the handler in question
string get_symbolic_name() const
retrieve the symbolic name for this container
Definition: BESContainer.h:224