bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
W10nJsonTransmitter.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2//
3// W10nJsonTransmitter.cc
4//
5// This file is part of BES JSON File Out Module
6//
7// Copyright (c) 2014 OPeNDAP, Inc.
8// Author: Nathan Potter <ndp@opendap.org>
9//
10// This library is free software; you can redistribute it and/or
11// modify it under the terms of the GNU Lesser General Public
12// License as published by the Free Software Foundation; either
13// version 2.1 of the License, or (at your option) any later version.
14//
15// This library is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18// Lesser General Public License for more details.
19//
20// You should have received a copy of the GNU Lesser General Public
21// License along with this library; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23//
24// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25// (c) COPYRIGHT URI/MIT 1995-1999
26// Please read the full copyright statement in the file COPYRIGHT_URI.
27//
28
29#include "config.h"
30
31#include <stdio.h>
32#include <stdlib.h>
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#include <sys/types.h> // For umask
39#include <sys/stat.h>
40
41#include <iostream>
42#include <fstream>
43
44#include <libdap/DataDDS.h>
45#include <libdap/BaseType.h>
46#include <libdap/escaping.h>
47#include <libdap/ConstraintEvaluator.h>
48
49#include <BESUtil.h>
50#include <BESInternalError.h>
51#include <BESDapError.h>
52#include <BESDapError.h>
53#include <TheBESKeys.h>
54#include <BESContextManager.h>
55#include <BESDataDDSResponse.h>
56#include <BESDDSResponse.h>
57#include <BESDapError.h>
58#include <BESDapNames.h>
59#include <BESDataNames.h>
60#include <BESDebug.h>
61#include <BESStopWatch.h>
62#include <BESSyntaxUserError.h>
63#include <BESDapResponseBuilder.h>
64#include <RequestServiceTimer.h>
65
66#include "W10nJsonTransmitter.h"
67
68#include "W10nJsonTransform.h"
69#include "W10NNames.h"
70#include "w10n_utils.h"
71
72using namespace ::libdap;
73
74#define MODULE "w10n"
75#define prolog string("W10nJsonTransmitter::").append(__func__).append("() - ")
76
77#define W10N_JSON_TEMP_DIR "/tmp"
78
79string W10nJsonTransmitter::temp_dir;
80
93 BESTransmitter()
94{
95 add_method(DATA_SERVICE, W10nJsonTransmitter::send_data);
96 add_method(DDX_SERVICE, W10nJsonTransmitter::send_metadata);
97
98 if (W10nJsonTransmitter::temp_dir.empty()) {
99 // Where is the temp directory for creating these files
100 bool found = false;
101 string key = "W10nJson.Tempdir";
102 TheBESKeys::TheKeys()->get_value(key, W10nJsonTransmitter::temp_dir, found);
103 if (!found || W10nJsonTransmitter::temp_dir.empty()) {
104 W10nJsonTransmitter::temp_dir = W10N_JSON_TEMP_DIR;
105 }
106 string::size_type len = W10nJsonTransmitter::temp_dir.size();
107 if (W10nJsonTransmitter::temp_dir[len - 1] == '/') {
108 W10nJsonTransmitter::temp_dir = W10nJsonTransmitter::temp_dir.substr(0, len - 1);
109 }
110 }
111}
112
117void W10nJsonTransmitter::checkConstraintForW10nCompatibility(const string &ce)
118{
119 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - BEGIN. ce: "<< ce << endl);
120
121 string projectionClause = getProjectionClause(ce);
122 int firstComma = projectionClause.find(",");
123
124 if (firstComma != -1) {
125 string msg = "The w10n protocol only allows one variable to be selected at a time. ";
126 msg += "The constraint expression '" + ce + "' requests more than one.";
127 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - ERROR! "<< msg << endl);
128 throw BESSyntaxUserError(msg, __FILE__, __LINE__);
129 }
130
131 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - END: " << endl);
132}
133
137string W10nJsonTransmitter::getProjectionClause(const string &constraintExpression)
138{
139 string projectionClause = constraintExpression;
140 BESDEBUG(W10N_DEBUG_KEY,
141 "W10nJsonTransmitter::getProjectionClause() - constraintExpression: "<< constraintExpression << endl);
142
143 int firstAmpersand = constraintExpression.find("&");
144 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::getProjectionClause() - firstAmpersand: "<< firstAmpersand << endl);
145 if (firstAmpersand >= 0) projectionClause = constraintExpression.substr(0, firstAmpersand);
146
147 BESDEBUG(W10N_DEBUG_KEY,
148 "W10nJsonTransmitter::getProjectionClause() - CE projection clause: "<< projectionClause << endl);
149
150 return projectionClause;
151}
152
156string W10nJsonTransmitter::getProjectedVariableName(const string &constraintExpression)
157{
158 string varName = getProjectionClause(constraintExpression);
159
160 int firstSquareBracket = varName.find("[");
161 if (firstSquareBracket != -1) {
162 varName = varName.substr(0, firstSquareBracket);
163 }
164
165 return varName;
166}
167
168struct ContextCleanup {
169 ContextCleanup() {}
170 ~ContextCleanup() {
171 BESDEBUG(W10N_DEBUG_KEY, "Cleanup w10n contexts" << endl);
172 W10nJsonTransmitter::cleanupW10nContexts();
173 }
174};
175
193{
194 BES_STOPWATCH_START_DHI(MODULE, prolog + "Timing", &dhi);
195
196 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - BEGIN." << endl);
197
198 // When 'cleanup' goes out of scope, cleanup the w10n contexts - incl. exceptions.
199 ContextCleanup cleanup;
200
201 try {
202 BESDapResponseBuilder responseBuilder;
203
204 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - reading data into DataDDS" << endl);
205
206 DDS *loaded_dds = responseBuilder.intern_dap2_data(obj, dhi);
207
208 checkConstraintForW10nCompatibility(dhi.data[POST_CONSTRAINT]);
209 w10n::checkConstrainedDDSForW10nDataCompatibility(loaded_dds);
210
211 ostream &o_strm = dhi.get_output_stream();
212 if (!o_strm) throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
213
214 W10nJsonTransform ft(loaded_dds, dhi, &o_strm);
215
216 string varName = getProjectedVariableName(dhi.data[POST_CONSTRAINT]);
217
218 // Verify the request hasn't exceeded bes_timeout.
219 RequestServiceTimer::TheTimer()->throw_if_timeout_expired("ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
220
221 // Now that we are ready to start building the response data we
222 // cancel any pending timeout alarm according to the configuration.
224
225 BESDEBUG(W10N_DEBUG_KEY,
226 "W10nJsonTransmitter::send_data() - Sending w10n data response for variable " << varName << endl);
227
228 ft.sendW10nDataForVariable(varName);
229 }
230 catch (Error &e) {
231 throw BESDapError("Failed to read data! Msg: " + e.get_error_message(), false, e.get_error_code(),
232 __FILE__, __LINE__);
233 }
234 catch (BESError &e) {
235 throw;
236 }
237 catch (...) {
238 throw BESInternalError("Failed to read data: Unknown exception caught", __FILE__, __LINE__);
239 }
240
241 // cleanupW10nContexts(); See above where an instance
242
243 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - END. Done transmitting JSON" << endl);
244}
245
263{
264 BES_STOPWATCH_START_DHI(MODULE, prolog + "Timing", &dhi);
265
266 ContextCleanup cleanup;
267
268 BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *>(obj);
269 if (!bdds) throw BESInternalError("cast error", __FILE__, __LINE__);
270
271 DDS *dds = bdds->get_dds();
272 if (!dds) throw BESInternalError("No DDS has been created for transmit", __FILE__, __LINE__);
273
274 ConstraintEvaluator &eval = bdds->get_ce();
275
276 ostream &o_strm = dhi.get_output_stream();
277 if (!o_strm) throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
278
279 // ticket 1248 jhrg 2/23/09
280 string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
281
282 checkConstraintForW10nCompatibility(ce);
283
284 try {
285 eval.parse_constraint(ce, *dds);
286 }
287 catch (Error &e) {
288 throw BESDapError("Failed to parse the constraint expression: " + e.get_error_message(), false,
289 e.get_error_code(), __FILE__, __LINE__);
290 }
291 catch (...) {
292 throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__,
293 __LINE__);
294 }
295
296 W10nJsonTransform ft(dds, dhi, &o_strm);
297
298 string varName = getProjectedVariableName(ce);
299
300 if (varName.size() == 0) {
301 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_metadata() - Sending w10n meta response for DDS" << endl);
302 ft.sendW10nMetaForDDS();
303 }
304 else {
305 BESDEBUG(W10N_DEBUG_KEY,
306 "W10nJsonTransmitter::send_metadata() - Sending w10n meta response for variable " << varName << endl);
307 ft.sendW10nMetaForVariable(varName, true);
308 }
309
310 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_metadata() - done transmitting JSON" << endl);
311}
312
316void W10nJsonTransmitter::cleanupW10nContexts()
317{
318 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::cleanupW10nContexts() - Removing contexts" << endl);
319
320 BESContextManager::TheManager()->unset_context(W10N_META_OBJECT_KEY);
321
322 BESContextManager::TheManager()->unset_context(W10N_CALLBACK_KEY);
323
324 BESContextManager::TheManager()->unset_context(W10N_FLATTEN_KEY);
325
326 BESContextManager::TheManager()->unset_context(W10N_TRAVERSE_KEY);
327}
Holds a DDS object within the BES.
libdap::ConstraintEvaluator & get_ce()
libdap::DDS * get_dds()
error object created from libdap error objects and can handle those errors
Definition BESDapError.h:50
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.
Base exception class for the BES with basic string message.
Definition BESError.h:66
exception thrown if internal error encountered
Abstract base class representing a specific set of information in response to a request to the BES.
error thrown if there is a user syntax error in the request or any other user error
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:898
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...
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
Definition TheBESKeys.cc:85
static void send_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
static void send_metadata(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
W10nJsonTransmitter()
Construct the W10nJsonTransmitter.
STL class.