bes Updated for version 3.20.10
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
65#include "W10nJsonTransmitter.h"
66
67#include "W10nJsonTransform.h"
68#include "W10NNames.h"
69#include "w10n_utils.h"
70
71using namespace ::libdap;
72
73#define W10N_JSON_TEMP_DIR "/tmp"
74
75string W10nJsonTransmitter::temp_dir;
76
90{
91 add_method(DATA_SERVICE, W10nJsonTransmitter::send_data);
92 add_method(DDX_SERVICE, W10nJsonTransmitter::send_metadata);
93
94 if (W10nJsonTransmitter::temp_dir.empty()) {
95 // Where is the temp directory for creating these files
96 bool found = false;
97 string key = "W10nJson.Tempdir";
98 TheBESKeys::TheKeys()->get_value(key, W10nJsonTransmitter::temp_dir, found);
99 if (!found || W10nJsonTransmitter::temp_dir.empty()) {
100 W10nJsonTransmitter::temp_dir = W10N_JSON_TEMP_DIR;
101 }
102 string::size_type len = W10nJsonTransmitter::temp_dir.length();
103 if (W10nJsonTransmitter::temp_dir[len - 1] == '/') {
104 W10nJsonTransmitter::temp_dir = W10nJsonTransmitter::temp_dir.substr(0, len - 1);
105 }
106 }
107}
108
113void W10nJsonTransmitter::checkConstraintForW10nCompatibility(const string &ce)
114{
115 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - BEGIN. ce: "<< ce << endl);
116
117 string projectionClause = getProjectionClause(ce);
118 int firstComma = projectionClause.find(",");
119
120 if (firstComma != -1) {
121 string msg = "The w10n protocol only allows one variable to be selected at a time. ";
122 msg += "The constraint expression '" + ce + "' requests more than one.";
123 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - ERROR! "<< msg << endl);
124 throw BESSyntaxUserError(msg, __FILE__, __LINE__);
125 }
126
127 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::checkConstraintForW10nCompatibility() - END: " << endl);
128}
129
133string W10nJsonTransmitter::getProjectionClause(const string &constraintExpression)
134{
135 string projectionClause = constraintExpression;
136 BESDEBUG(W10N_DEBUG_KEY,
137 "W10nJsonTransmitter::getProjectionClause() - constraintExpression: "<< constraintExpression << endl);
138
139 int firstAmpersand = constraintExpression.find("&");
140 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::getProjectionClause() - firstAmpersand: "<< firstAmpersand << endl);
141 if (firstAmpersand >= 0) projectionClause = constraintExpression.substr(0, firstAmpersand);
142
143 BESDEBUG(W10N_DEBUG_KEY,
144 "W10nJsonTransmitter::getProjectionClause() - CE projection clause: "<< projectionClause << endl);
145
146 return projectionClause;
147}
148
152string W10nJsonTransmitter::getProjectedVariableName(const string &constraintExpression)
153{
154 string varName = getProjectionClause(constraintExpression);
155
156 int firstSquareBracket = varName.find("[");
157 if (firstSquareBracket != -1) {
158 varName = varName.substr(0, firstSquareBracket);
159 }
160
161 return varName;
162}
163
164struct ContextCleanup {
165 ContextCleanup() {}
166 ~ContextCleanup() {
167 BESDEBUG(W10N_DEBUG_KEY, "Cleanup w10n contexts" << endl);
168 W10nJsonTransmitter::cleanupW10nContexts();
169 }
170};
171
189{
190#ifndef NDEBUG
191 BESStopWatch sw;
192 if (BESDebug::IsSet(TIMING_LOG_KEY)) sw.start("W10nJsonTransmitter::send_data", dhi.data[REQUEST_ID]);
193#endif
194
195 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - BEGIN." << endl);
196
197 // When 'cleanup' goes out of scope, cleanup the w10n contexts - incl. exceptions.
198 ContextCleanup cleanup;
199
200 try {
201 BESDapResponseBuilder responseBuilder;
202
203 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - reading data into DataDDS" << endl);
204
205 DDS *loaded_dds = responseBuilder.intern_dap2_data(obj, dhi);
206
207 checkConstraintForW10nCompatibility(dhi.data[POST_CONSTRAINT]);
208 w10n::checkConstrainedDDSForW10nDataCompatibility(loaded_dds);
209
210 ostream &o_strm = dhi.get_output_stream();
211 if (!o_strm) throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
212
213 W10nJsonTransform ft(loaded_dds, dhi, &o_strm);
214
215 string varName = getProjectedVariableName(dhi.data[POST_CONSTRAINT]);
216
217 // Now that we are ready to start building the response data we
218 // cancel any pending timeout alarm according to the configuration.
220
221 BESDEBUG(W10N_DEBUG_KEY,
222 "W10nJsonTransmitter::send_data() - Sending w10n data response for variable " << varName << endl);
223
224 ft.sendW10nDataForVariable(varName);
225 }
226 catch (Error &e) {
227 throw BESDapError("Failed to read data! Msg: " + e.get_error_message(), false, e.get_error_code(),
228 __FILE__, __LINE__);
229 }
230 catch (BESError &e) {
231 throw;
232 }
233 catch (...) {
234 throw BESInternalError("Failed to read data: Unknown exception caught", __FILE__, __LINE__);
235 }
236
237 // cleanupW10nContexts(); See above where an instance
238
239 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_data() - END. Done transmitting JSON" << endl);
240}
241
259{
260#ifndef NDEBUG
261 BESStopWatch sw;
262 if (BESDebug::IsSet(TIMING_LOG_KEY)) sw.start("W10nJsonTransmitter::send_metadata", dhi.data[REQUEST_ID]);
263#endif
264
265 ContextCleanup cleanup;
266
267 BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *>(obj);
268 if (!bdds) throw BESInternalError("cast error", __FILE__, __LINE__);
269
270 DDS *dds = bdds->get_dds();
271 if (!dds) throw BESInternalError("No DDS has been created for transmit", __FILE__, __LINE__);
272
273 ConstraintEvaluator &eval = bdds->get_ce();
274
275 ostream &o_strm = dhi.get_output_stream();
276 if (!o_strm) throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
277
278 // ticket 1248 jhrg 2/23/09
279 string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
280
281 checkConstraintForW10nCompatibility(ce);
282
283 try {
284 eval.parse_constraint(ce, *dds);
285 }
286 catch (Error &e) {
287 throw BESDapError("Failed to parse the constraint expression: " + e.get_error_message(), false,
288 e.get_error_code(), __FILE__, __LINE__);
289 }
290 catch (...) {
291 throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__,
292 __LINE__);
293 }
294
295 W10nJsonTransform ft(dds, dhi, &o_strm);
296
297 string varName = getProjectedVariableName(ce);
298
299 if (varName.length() == 0) {
300 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_metadata() - Sending w10n meta response for DDS" << endl);
301 ft.sendW10nMetaForDDS();
302 }
303 else {
304 BESDEBUG(W10N_DEBUG_KEY,
305 "W10nJsonTransmitter::send_metadata() - Sending w10n meta response for variable " << varName << endl);
306 ft.sendW10nMetaForVariable(varName, true);
307 }
308
309 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::send_metadata() - done transmitting JSON" << endl);
310}
311
315void W10nJsonTransmitter::cleanupW10nContexts()
316{
317 BESDEBUG(W10N_DEBUG_KEY, "W10nJsonTransmitter::cleanupW10nContexts() - Removing contexts" << endl);
318
319 BESContextManager::TheManager()->unset_context(W10N_META_OBJECT_KEY);
320
321 BESContextManager::TheManager()->unset_context(W10N_CALLBACK_KEY);
322
323 BESContextManager::TheManager()->unset_context(W10N_FLATTEN_KEY);
324
325 BESContextManager::TheManager()->unset_context(W10N_TRAVERSE_KEY);
326}
virtual void unset_context(const std::string &name)
set context in the BES
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: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.
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
Definition: BESDebug.h:168
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
exception thrown if internal error encountered
Abstract base class representing a specific set of information in response to a request to the BES.
virtual bool start(std::string name)
Definition: BESStopWatch.cc:67
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:992
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:340
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:71
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.