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
73using namespace dap_asciival;
74using namespace libdap;
75
76#define MODULE "ascii"
77#define prolog string("BESAsciiTransmit::").append(__func__).append("() - ")
78
79BESAsciiTransmit::BESAsciiTransmit() :
81{
82 add_method(DATA_SERVICE, BESAsciiTransmit::send_basic_ascii);
83 add_method(DAP4DATA_SERVICE, BESAsciiTransmit::send_dap4_csv);
84}
85
86void 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
130void 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...