bes  Updated for version 3.20.8
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 <BaseType.h>
36 #include <Sequence.h>
37 #include <ConstraintEvaluator.h>
38 #include <D4Group.h>
39 #include <DMR.h>
40 #include <D4ConstraintEvaluator.h>
41 #include <D4BaseTypeFactory.h>
42 #include <ServerFunctionsList.h>
43 #include <D4FunctionEvaluator.h>
44 #include <crc.h>
45 #include <InternalErr.h>
46 #include <util.h>
47 #include <escaping.h>
48 #include <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 "BESAsciiTransmit.h"
68 #include "get_ascii.h"
69 #include "get_ascii_dap4.h"
70 
71 using namespace dap_asciival;
72 using namespace libdap;
73 
74 BESAsciiTransmit::BESAsciiTransmit() :
76 {
77  add_method(DATA_SERVICE, BESAsciiTransmit::send_basic_ascii);
78  add_method(DAP4DATA_SERVICE, BESAsciiTransmit::send_dap4_csv);
79 }
80 
81 void BESAsciiTransmit::send_basic_ascii(BESResponseObject *obj, BESDataHandlerInterface &dhi)
82 {
83  BESDEBUG("ascii", "BESAsciiTransmit::send_basic_ascii() - BEGIN" << endl);
84 
85  try { // Expanded try block so all DAP errors are caught. ndp 12/23/2015
86  BESDapResponseBuilder responseBuilder;
87 
88  // Now that we are ready to start reading the response data we
89  // cancel any pending timeout alarm according to the configuration.
91 
92  // Use the DDS from the ResponseObject along with the parameters
93  // from the DataHandlerInterface to load the DDS with values.
94  // Note that the BESResponseObject will manage the loaded_dds object's
95  // memory. Make this a shared_ptr<>. jhrg 9/6/16
96  DDS *loaded_dds = responseBuilder.intern_dap2_data(obj, dhi);
97 
98  // Send data values as CSV/ASCII
99  auto_ptr<DDS> ascii_dds(datadds_to_ascii_datadds(loaded_dds)); // unique_ptr<> jhrg 9/6/16
100 
101  get_data_values_as_ascii(ascii_dds.get(), dhi.get_output_stream());
102  dhi.get_output_stream() << flush;
103  }
104  catch (Error &e) {
105  throw BESDapError("Failed to get values as ascii: " + e.get_error_message(), false, e.get_error_code(), __FILE__, __LINE__);
106  }
107  catch (BESError &e) {
108  throw;
109  }
110  catch (std::exception &e) {
111  throw BESInternalError("Failed to read data: STL Error: " + string(e.what()), __FILE__, __LINE__);
112  }
113  catch (...) {
114  throw BESInternalError("Failed to get values as ascii: Unknown exception caught", __FILE__, __LINE__);
115  }
116 
117  BESDEBUG("ascii", "Done BESAsciiTransmit::send_basic_ascii()" << endl);
118 }
119 
125 void BESAsciiTransmit::send_dap4_csv_helper(ostream &out, DMR *dmr, const string &dap4Constraint) {
126  if (!dap4Constraint.empty()) {
127  D4ConstraintEvaluator d4ce(dmr);
128  bool parse_ok = d4ce.parse(dap4Constraint);
129  if (!parse_ok) throw Error(malformed_expr, "Constraint Expression (" + dap4Constraint + ") failed to parse.");
130  }
131  else {
132  dmr->root()->set_send_p(true);
133  }
134 
135  if (dmr->response_limit() != 0 && (dmr->request_size(true) > dmr->response_limit())) {
136  string msg = "The Request for " + long_to_string(dmr->request_size(true))
137  + "KB is too large; requests for this server are limited to " +
138  long_to_string(dmr->response_limit())
139  + "KB.";
140  throw Error(msg);
141  }
142 
143  // Now that we are ready to start building the response data we
144  // cancel any pending timeout alarm according to the configuration.
146 
147  print_values_as_ascii(dmr, out);
148  out << flush;
149 }
150 
155 {
156  BESDEBUG("ascii", "BESAsciiTransmit::send_dap4_csv" << endl);
157 
158  BESDMRResponse *bdmr = dynamic_cast<BESDMRResponse *>(obj);
159  if (!bdmr) throw BESInternalFatalError("Expected a BESDMRResponse instance.", __FILE__, __LINE__);
160 
161  DMR *dmr = bdmr->get_dmr();
162 
163  string dap4Constraint = www2id(dhi.data[DAP4_CONSTRAINT], "%", "%20%26");
164  string dap4Function = www2id(dhi.data[DAP4_FUNCTION], "%", "%20%26");
165 
166  // Not sure we need this...
167  dhi.first_container();
168 
169  try {
170  // @TODO Handle *functional* constraint expressions specially
171  // Use the D4FunctionDriver class and evaluate the functions, building
172  // a new DMR, then evaluate the D4CE in the context of that DMR.
173  // This might be coded as "if (there's a function) do this else process the CE".
174  // Or it might be coded as "if (there's a function) build the new DMR, then fall
175  // through and process the CE but on the new DMR". jhrg 9/3/14
176  if (!dap4Function.empty()) {
177  D4BaseTypeFactory d4_factory;
178  DMR function_result(&d4_factory, "function_results");
179 
180  // Function modules load their functions onto this list. The list is
181  // part of libdap, not the BES.
182  if (!ServerFunctionsList::TheList())
183  throw Error(
184  "The function expression could not be evaluated because there are no server functions defined on this server");
185 
186  D4FunctionEvaluator parser(dmr, ServerFunctionsList::TheList());
187  bool parse_ok = parser.parse(dap4Function);
188  if (!parse_ok) throw Error("Function Expression (" + dap4Function + ") failed to parse.");
189 
190  parser.eval(&function_result);
191 
192  // Now use the results of running the functions for the remainder of the
193  // send_data operation.
194  send_dap4_csv_helper(dhi.get_output_stream(), &function_result, dap4Constraint);
195  }
196  else {
197  send_dap4_csv_helper(dhi.get_output_stream(), dmr, dap4Constraint);
198  }
199 
200 #if 0
201  // ORIG HERE
202 
203  if (!dap4Constraint.empty()) {
204  D4ConstraintEvaluator d4ce(dmr);
205  bool parse_ok = d4ce.parse(dap4Constraint);
206  if (!parse_ok) throw Error(malformed_expr, "Constraint Expression (" + dap4Constraint + ") failed to parse.");
207  }
208  else {
209  dmr->root()->set_send_p(true);
210  }
211 
212  if (dmr->response_limit() != 0 && (dmr->request_size(true) > dmr->response_limit())) {
213  string msg = "The Request for " + long_to_string(dmr->request_size(true))
214  + "KB is too large; requests for this server are limited to " + long_to_string(dmr->response_limit())
215  + "KB.";
216  throw Error(msg);
217  }
218 
219  // Now that we are ready to start building the response data we
220  // cancel any pending timeout alarm according to the configuration.
222 
223  print_values_as_ascii(dmr, dhi.get_output_stream());
224  dhi.get_output_stream() << flush;
225 #endif
226  }
227  catch (Error &e) {
228  throw BESDapError("Failed to return values as ascii: " + e.get_error_message(), false, e.get_error_code(),__FILE__, __LINE__);
229  }
230  catch (BESError &e){
231  throw;
232  }
233  catch (...) {
234  throw BESInternalError("Failed to return values as ascii: Unknown exception caught", __FILE__, __LINE__);
235  }
236 
237  BESDEBUG("ascii", "Done BESAsciiTransmit::send_dap4_csv" << endl);
238 }
239 
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
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
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()
Definition: BESUtil.cc:967