OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
FoInstanceJsonTransmitter.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 //
3 // FoInstanceJsonTransmitter.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 
30 #include "config.h"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 
39 #include <sys/types.h> // For umask
40 #include <sys/stat.h>
41 
42 #include <iostream>
43 #include <fstream>
44 
45 #include <DataDDS.h>
46 #include <BaseType.h>
47 #include <escaping.h>
48 #include <ConstraintEvaluator.h>
49 
50 #include <BESInternalError.h>
51 #include <TheBESKeys.h>
52 #include <BESContextManager.h>
53 #include <BESDataDDSResponse.h>
54 #include <BESDDSResponse.h>
55 #include <BESDapNames.h>
56 #include <BESDataNames.h>
57 #include <BESDebug.h>
58 
61 
62 
63 using namespace ::libdap;
64 
65 #define FO_JSON_TEMP_DIR "/tmp"
66 
67 
68 string FoInstanceJsonTransmitter::temp_dir;
69 
82 {
85 
86  if (FoInstanceJsonTransmitter::temp_dir.empty()) {
87  // Where is the temp directory for creating these files
88  bool found = false;
89  string key = "FoJson.Tempdir";
90  TheBESKeys::TheKeys()->get_value(key, FoInstanceJsonTransmitter::temp_dir, found);
91  if (!found || FoInstanceJsonTransmitter::temp_dir.empty()) {
92  FoInstanceJsonTransmitter::temp_dir = FO_JSON_TEMP_DIR;
93  }
94  string::size_type len = FoInstanceJsonTransmitter::temp_dir.length();
95  if (FoInstanceJsonTransmitter::temp_dir[len - 1] == '/') {
96  FoInstanceJsonTransmitter::temp_dir = FoInstanceJsonTransmitter::temp_dir.substr(0, len - 1);
97  }
98  }
99 }
100 
121 {
122  BESDDSResponse *bdds = dynamic_cast<BESDDSResponse *>(obj);
123  if (!bdds) {
124  throw BESInternalError("Cast to BESDDSResponse error.", __FILE__, __LINE__);
125  }
126 
127  DDS *dds = bdds->get_dds();
128  if (!dds)
129  throw BESInternalError("No DataDDS has been created for transmit", __FILE__, __LINE__);
130 
131  BESDEBUG("fojson", "FoJsonTransmitter::send_metadata - parsing the constraint" << endl);
132 
133  ConstraintEvaluator &eval = bdds->get_ce();
134  ostream &o_strm = dhi.get_output_stream();
135  if (!o_strm)
136  throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
137 
138  // ticket 1248 jhrg 2/23/09
139  string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
140  try {
141  eval.parse_constraint(ce, *dds);
142  }
143  catch (Error &e) {
144  throw BESInternalError("Failed to parse the constraint expression: " + e.get_error_message(), __FILE__, __LINE__);
145  }
146  catch (...) {
147  throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__, __LINE__);
148  }
149 
150  // now we need to read the data
151  BESDEBUG("fojson", "FoJsonTransmitter::send_data - reading data into DataDDS" << endl);
152 
153  try {
154  // Handle *functional* constraint expressions specially
155  if (eval.function_clauses()) {
156  BESDEBUG("fojson", "processing a functional constraint clause(s)." << endl);
157  DDS *tmp_dds = eval.eval_function_clauses(*dds);
158  bdds->set_dds(tmp_dds);
159  delete dds;
160  dds = tmp_dds;
161  }
162  else {
163  // Iterate through the variables in the DataDDS and read
164  // in the data if the variable has the send flag set.
165 
166  for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
167  if ((*i)->send_p()) {
168  (*i)->intern_data(eval, *dds);
169  }
170  }
171  }
172  }
173  catch (Error &e) {
174  throw BESInternalError("Failed to read data: " + e.get_error_message(), __FILE__, __LINE__);
175  }
176  catch (...) {
177  throw BESInternalError("Failed to read data: Unknown exception caught", __FILE__, __LINE__);
178  }
179 
180  try {
181  FoInstanceJsonTransform ft(dds, dhi, &o_strm);
182 
183  ft.transform( false /* do not send data */ );
184  }
185  catch (BESError &e) {
186  throw;
187  }
188  catch (...) {
189  throw BESInternalError("fileout_json: Failed to transform to JSON, unknown error", __FILE__, __LINE__);
190  }
191 
192  BESDEBUG("fojson", "FoJsonTransmitter::send_data - done transmitting JSON" << endl);
193 }
194 
195 
212 {
213  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(obj);
214  if (!bdds)
215  throw BESInternalError("cast error", __FILE__, __LINE__);
216 
217  DataDDS *dds = bdds->get_dds();
218  if (!dds)
219  throw BESInternalError("No DataDDS has been created for transmit", __FILE__, __LINE__);
220 
221  BESDEBUG("fojson", "FoJsonTransmitter::send_data - parsing the constraint" << endl);
222 
223  ConstraintEvaluator &eval = bdds->get_ce();
224 
225  ostream &o_strm = dhi.get_output_stream();
226  if (!o_strm)
227  throw BESInternalError("Output stream is not set, can not return as JSON", __FILE__, __LINE__);
228 
229  // ticket 1248 jhrg 2/23/09
230  string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
231  try {
232  eval.parse_constraint(ce, *dds);
233  }
234  catch (Error &e) {
235  throw BESInternalError("Failed to parse the constraint expression: " + e.get_error_message(), __FILE__, __LINE__);
236  }
237  catch (...) {
238  throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__, __LINE__);
239  }
240 
241  // now we need to read the data
242  BESDEBUG("fojson", "FoJsonTransmitter::send_data - reading data into DataDDS" << endl);
243 
244  try {
245  // Handle *functional* constraint expressions specially
246  if (eval.function_clauses()) {
247  BESDEBUG("fojson", "processing a functional constraint clause(s)." << endl);
248  DataDDS *tmp_dds = eval.eval_function_clauses(*dds);
249  bdds->set_dds(tmp_dds);
250  delete dds;
251  dds = tmp_dds;
252  }
253  else {
254  // Iterate through the variables in the DataDDS and read
255  // in the data if the variable has the send flag set.
256 
257  for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
258  if ((*i)->send_p()) {
259  (*i)->intern_data(eval, *dds);
260  }
261 
262  }
263  }
264  }
265  catch (Error &e) {
266  throw BESInternalError("Failed to read data: " + e.get_error_message(), __FILE__, __LINE__);
267  }
268  catch (...) {
269  throw BESInternalError("Failed to read data: Unknown exception caught", __FILE__, __LINE__);
270  }
271 #if 0
272  string temp_file_name = FoJsonTransmitter::temp_dir + '/' + "jsonXXXXXX";
273  vector<char> temp_full(temp_file_name.length() + 1);
274  string::size_type len = temp_file_name.copy(&temp_full[0], temp_file_name.length());
275  temp_full[len] = '\0';
276 
277  // cover the case where older versions of mkstemp() create the file using
278  // a mode of 666.
279  mode_t original_mode = umask(077);
280  int fd = mkstemp(&temp_full[0]);
281  umask(original_mode);
282  if (fd == -1)
283  throw BESInternalError("Failed to open the temporary file: " + temp_file_name, __FILE__, __LINE__);
284 
285  // transform the OPeNDAP DataDDS to the netcdf file
286  BESDEBUG("fojson", "FoJsonTransmitter::send_data - transforming into temporary file " << &temp_full[0] << endl);
287 #endif
288  try {
289  FoInstanceJsonTransform ft(dds, dhi, &o_strm /*&temp_full[0]*/);
290 
291  ft.transform( true /* send data */ );
292 
293  // FoJsonTransmitter::return_temp_stream(&temp_full[0], o_strm);
294  }
295 #if 0
296  catch (BESError &e) {
297  close(fd);
298  (void) unlink(&temp_full[0]);
299  throw;
300  }
301 #endif
302  catch (...) {
303 #if 0
304  close(fd);
305  (void) unlink(&temp_full[0]);
306 #endif
307  throw BESInternalError("fileout_json: Failed to transform to JSON, unknown error", __FILE__, __LINE__);
308  }
309 
310  //close(fd);
311  //(void) unlink(&temp_full[0]);
312 
313  BESDEBUG("fojson", "FoJsonTransmitter::send_data - done transmitting JSON" << endl);
314 }
315 
325 void FoInstanceJsonTransmitter::return_temp_stream(const string &filename, ostream &strm)
326 {
327  ifstream os;
328  os.open(filename.c_str(), ios::binary | ios::in);
329  if (!os) {
330  string err = "Can not connect to file " + filename;
331  BESInternalError pe(err, __FILE__, __LINE__);
332  throw pe;
333  }
334  int nbytes;
335  char block[4096];
336 
337  os.read(block, sizeof block);
338  nbytes = os.gcount();
339  if (nbytes > 0) {
340  strm.write(block, nbytes);
341  }
342  else {
343  // close the stream before we leave.
344  os.close();
345 
346  string err = (string) "0XAAE234F: failed to stream. Internal server "
347  + "error, got zero count on stream buffer." + filename;
348  BESInternalError pe(err, __FILE__, __LINE__);
349  throw pe;
350  }
351  while (os) {
352  os.read(block, sizeof block);
353  nbytes = os.gcount();
354  strm.write(block, nbytes);
355  }
356  os.close();
357 }
358 
void set_dds(DDS *ddsIn)
Set the response object's DDS.
#define DATA_SERVICE
Definition: BESDapNames.h:71
void set_dds(DataDDS *ddsIn)
Set the response object's DDS.
exception thrown if inernal error encountered
ConstraintEvaluator & get_ce()
Transforms a DDS into JSON document on disk.
Represents an OPeNDAP DDS DAP2 data object within the BES.
virtual bool add_method(string method_name, p_transmitter trans_method)
static void send_data(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
static class NCMLUtil overview
FoInstanceJsonTransmitter()
Construct the FoJsonTransmitter.
Abstract exception class for the BES with basic string message.
Definition: BESError.h:51
#define DDX_SERVICE
Definition: BESDapNames.h:66
static void send_metadata(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a JSON file.
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: BESKeys.cc:453
#define POST_CONSTRAINT
Definition: BESDataNames.h:43
#define FO_JSON_TEMP_DIR
ConstraintEvaluator & get_ce()
Structure storing information used by the BES to handle the request.
map< string, string > data
the map of string data that will be required for the current request.
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
Abstract base class representing a specific set of information in response to a request to the BES...