bes Updated for version 3.20.10
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 "BESAsciiTransmit.h"
68#include "get_ascii.h"
69#include "get_ascii_dap4.h"
70
71using namespace dap_asciival;
72using namespace libdap;
73
74BESAsciiTransmit::BESAsciiTransmit() :
76{
77 add_method(DATA_SERVICE, BESAsciiTransmit::send_basic_ascii);
78 add_method(DAP4DATA_SERVICE, BESAsciiTransmit::send_dap4_csv);
79}
80
81void 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
125void 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()
Checks if the timeout alarm should be canceled based on the value of the BES key BES....
Definition: BESUtil.cc:992