bes  Updated for version 3.20.6
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 <DataDDS.h>
45 #include <BaseType.h>
46 #include <escaping.h>
47 #include <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 
71 using namespace ::libdap;
72 
73 #define W10N_JSON_TEMP_DIR "/tmp"
74 
75 string 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 
113 void 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 
133 string 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 
152 string 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 
164 struct 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 (BESISDEBUG(TIMING_LOG)) 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 (BESISDEBUG(TIMING_LOG)) 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 
315 void 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 }
BESStopWatch::start
virtual bool start(std::string name)
Definition: BESStopWatch.cc:58
W10nJsonTransmitter::send_metadata
static void send_metadata(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
Definition: W10nJsonTransmitter.cc:258
BESDDSResponse::get_dds
libdap::DDS * get_dds()
Definition: BESDDSResponse.h:80
BESUtil::conditional_timeout_cancel
static void conditional_timeout_cancel()
Definition: BESUtil.cc:967
BESDDSResponse::get_ce
libdap::ConstraintEvaluator & get_ce()
Definition: BESDDSResponse.h:92
libdap
Definition: BESDapFunctionResponseCache.h:35
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESSyntaxUserError
error thrown if there is a user syntax error in the request or any other user error
Definition: BESSyntaxUserError.h:41
BESDataHandlerInterface::data
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
Definition: BESDataHandlerInterface.h:90
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
BESStopWatch
Definition: BESStopWatch.h:55
TheBESKeys::get_value
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:272
BESTransmitter
Definition: BESTransmitter.h:47
BESDDSResponse
Holds a DDS object within the BES.
Definition: BESDDSResponse.h:50
BESDapResponseBuilder::intern_dap2_data
virtual libdap::DDS * intern_dap2_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
Definition: BESDapResponseBuilder.cc:980
BESDapResponseBuilder
Definition: BESDapResponseBuilder.h:53
W10nJsonTransmitter::W10nJsonTransmitter
W10nJsonTransmitter()
Construct the W10nJsonTransmitter.
Definition: W10nJsonTransmitter.cc:88
Error
BESDapError
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
BESDataHandlerInterface
Structure storing information used by the BES to handle the request.
Definition: BESDataHandlerInterface.h:56
BESContextManager::unset_context
virtual void unset_context(const std::string &name)
set context in the BES
Definition: BESContextManager.cc:63
BESError
Abstract exception class for the BES with basic string message.
Definition: BESError.h:58
W10nJsonTransform
Definition: W10nJsonTransform.h:50
BESResponseObject
Abstract base class representing a specific set of information in response to a request to the BES.
Definition: BESResponseObject.h:45
W10nJsonTransmitter::send_data
static void send_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
Definition: W10nJsonTransmitter.cc:188