bes  Updated for version 3.20.13
BESAsciiTransmit.cc
1 // BESAsciiTransmit.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public 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 University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include <memory>
34 
35 #include <libdap/BaseType.h>
36 #include <libdap/Sequence.h>
37 #include <libdap/ConstraintEvaluator.h>
38 #include <libdap/D4Group.h>
39 #include <libdap/DMR.h>
40 #include <D4ConstraintEvaluator.h>
41 #include <libdap/D4BaseTypeFactory.h>
42 #include <libdap/ServerFunctionsList.h>
43 #include <D4FunctionEvaluator.h>
44 #include <libdap/crc.h>
45 #include <libdap/InternalErr.h>
46 #include <libdap/util.h>
47 #include <libdap/escaping.h>
48 #include <libdap/mime_util.h>
49 
50 #include <BESUtil.h>
51 #include <BESDapNames.h>
52 #include <BESDataNames.h>
53 #include <BESDapTransmit.h>
54 #include <BESContainer.h>
55 #include <BESDataDDSResponse.h>
56 #include <BESDMRResponse.h>
57 #include <BESDapResponseBuilder.h>
58 
59 #include <BESError.h>
60 #include <BESDapError.h>
61 #include <BESForbiddenError.h>
62 #include <BESInternalFatalError.h>
63 #include <DapFunctionUtils.h>
64 
65 #include <BESDebug.h>
66 
67 #include "RequestServiceTimer.h"
68 
69 #include "BESAsciiTransmit.h"
70 #include "get_ascii.h"
71 #include "get_ascii_dap4.h"
72 
73 using namespace dap_asciival;
74 using namespace libdap;
75 
76 #define MODULE "ascii"
77 #define prolog string("BESAsciiTransmit::").append(__func__).append("() - ")
78 
79 BESAsciiTransmit::BESAsciiTransmit() :
81 {
82  add_method(DATA_SERVICE, BESAsciiTransmit::send_basic_ascii);
83  add_method(DAP4DATA_SERVICE, BESAsciiTransmit::send_dap4_csv);
84 }
85 
86 void BESAsciiTransmit::send_basic_ascii(BESResponseObject *obj, BESDataHandlerInterface &dhi)
87 {
88  BESDEBUG("ascii", "BESAsciiTransmit::send_basic_ascii() - BEGIN" << endl);
89 
90  try { // Expanded try block so all DAP errors are caught. ndp 12/23/2015
91  BESDapResponseBuilder responseBuilder;
92 
93  // Use the DDS from the ResponseObject along with the parameters
94  // from the DataHandlerInterface to load the DDS with values.
95  // Note that the BESResponseObject will manage the loaded_dds object's
96  // memory. Make this a shared_ptr<>. jhrg 9/6/16
97  DDS *loaded_dds = responseBuilder.intern_dap2_data(obj, dhi);
98 
99  // Send data values as CSV/ASCII
100  unique_ptr<DDS> ascii_dds(datadds_to_ascii_datadds(loaded_dds)); // unique_ptr<> jhrg 9/6/16
101 
102  // Verify the request hasn't exceeded bes_timeout, and disable timeout if allowed.
103  RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
105 
106  get_data_values_as_ascii(ascii_dds.get(), dhi.get_output_stream());
107  dhi.get_output_stream() << flush;
108  }
109  catch (Error &e) {
110  throw BESDapError("Failed to get values as ascii: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
111  }
112  catch (BESError &e) {
113  throw;
114  }
115  catch (std::exception &e) {
116  throw BESInternalError("Failed to read data: STL Error: " + string(e.what()), __FILE__, __LINE__);
117  }
118  catch (...) {
119  throw BESInternalError("Failed to get values as ascii: Unknown exception caught", __FILE__, __LINE__);
120  }
121 
122  BESDEBUG("ascii", "Done BESAsciiTransmit::send_basic_ascii()" << endl);
123 }
124 
130 void BESAsciiTransmit::send_dap4_csv_helper(ostream &out, DMR *dmr, const string &dap4Constraint) {
131  if (!dap4Constraint.empty()) {
132  D4ConstraintEvaluator d4ce(dmr);
133  bool parse_ok = d4ce.parse(dap4Constraint);
134  if (!parse_ok) throw Error(malformed_expr, "Constraint Expression (" + dap4Constraint + ") failed to parse.");
135  }
136  else {
137  dmr->root()->set_send_p(true);
138  }
139 
140  if (dmr->response_limit() != 0 && (dmr->request_size(true) > dmr->response_limit())) {
141  string msg = "The Request for " + long_to_string(dmr->request_size(true))
142  + "KB is too large; requests for this server are limited to " +
143  long_to_string(dmr->response_limit())
144  + "KB.";
145  throw Error(msg);
146  }
147 
148  // Verify the request hasn't exceeded bes_timeout.
149  RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
150 
151  print_values_as_ascii(dmr, out);
152  out << flush;
153 }
154 
159 {
160  BESDEBUG("ascii", "BESAsciiTransmit::send_dap4_csv" << endl);
161 
162  BESDMRResponse *bdmr = dynamic_cast<BESDMRResponse *>(obj);
163  if (!bdmr) throw BESInternalFatalError("Expected a BESDMRResponse instance.", __FILE__, __LINE__);
164 
165  DMR *dmr = bdmr->get_dmr();
166 
167  string dap4Constraint = www2id(dhi.data[DAP4_CONSTRAINT], "%", "%20%26");
168  string dap4Function = www2id(dhi.data[DAP4_FUNCTION], "%", "%20%26");
169 
170  // Not sure we need this...
171  dhi.first_container();
172 
173  try {
174  // @TODO Handle *functional* constraint expressions specially
175  // Use the D4FunctionDriver class and evaluate the functions, building
176  // a new DMR, then evaluate the D4CE in the context of that DMR.
177  // This might be coded as "if (there's a function) do this else process the CE".
178  // Or it might be coded as "if (there's a function) build the new DMR, then fall
179  // through and process the CE but on the new DMR". jhrg 9/3/14
180  if (!dap4Function.empty()) {
181  D4BaseTypeFactory d4_factory;
182  DMR function_result(&d4_factory, "function_results");
183 
184  // Function modules load their functions onto this list. The list is
185  // part of libdap, not the BES.
186  if (!ServerFunctionsList::TheList())
187  throw Error(
188  "The function expression could not be evaluated because there are no server functions defined on this server");
189 
190  D4FunctionEvaluator parser(dmr, ServerFunctionsList::TheList());
191  bool parse_ok = parser.parse(dap4Function);
192  if (!parse_ok) throw Error("Function Expression (" + dap4Function + ") failed to parse.");
193 
194  parser.eval(&function_result);
195 
196  // Now use the results of running the functions for the remainder of the
197  // send_data operation.
198  send_dap4_csv_helper(dhi.get_output_stream(), &function_result, dap4Constraint);
199  }
200  else {
201  send_dap4_csv_helper(dhi.get_output_stream(), dmr, dap4Constraint);
202  }
203 
204 #if 0
205  // ORIG HERE
206 
207  if (!dap4Constraint.empty()) {
208  D4ConstraintEvaluator d4ce(dmr);
209  bool parse_ok = d4ce.parse(dap4Constraint);
210  if (!parse_ok) throw Error(malformed_expr, "Constraint Expression (" + dap4Constraint + ") failed to parse.");
211  }
212  else {
213  dmr->root()->set_send_p(true);
214  }
215 
216  if (dmr->response_limit() != 0 && (dmr->request_size(true) > dmr->response_limit())) {
217  string msg = "The Request for " + long_to_string(dmr->request_size(true))
218  + "KB is too large; requests for this server are limited to " + long_to_string(dmr->response_limit())
219  + "KB.";
220  throw Error(msg);
221  }
222 
223  // Now that we are ready to start building the response data we
224  // cancel any pending timeout alarm according to the configuration.
226 
227  print_values_as_ascii(dmr, dhi.get_output_stream());
228  dhi.get_output_stream() << flush;
229 #endif
230  }
231  catch (Error &e) {
232  throw BESDapError("Failed to return values as ascii: " + e.get_error_message(), false, e.get_error_code(),__FILE__, __LINE__);
233  }
234  catch (BESError &e){
235  throw;
236  }
237  catch (...) {
238  throw BESInternalError("Failed to return values as ascii: Unknown exception caught", __FILE__, __LINE__);
239  }
240 
241  BESDEBUG("ascii", "Done BESAsciiTransmit::send_dap4_csv" << endl);
242 }
243 
static void send_dap4_csv(BESResponseObject *obj, BESDataHandlerInterface &dhi)
static void send_dap4_csv_helper(std::ostream &out, libdap::DMR *dmr, const std::string &dap4Constraint)
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 libdap::DDS * intern_dap2_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
Structure storing information used by the BES to handle the request.
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
void first_container()
set the container pointer to the first container in the containers list
Base exception class for the BES with basic string message.
Definition: BESError.h:59
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
Abstract base class representing a specific set of information in response to a request to the BES.
static void conditional_timeout_cancel()
Checks if the timeout alarm should be canceled based on the value of the BES key BES....
Definition: BESUtil.cc:895
static RequestServiceTimer * TheTimer()
Return a pointer to a singleton timer instance. If an instance does not exist it will create and init...
void throw_if_timeout_expired(const std::string &message, const std::string &file, const int line)
Checks the RequestServiceTimer to determine if the time spent servicing the request at this point has...