OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
GeoTiffTransmitter.cc
Go to the documentation of this file.
1 // GeoTiffTransmitter.cc
2 
3 // This file is part of BES GDAL File Out Module
4 
5 // Copyright (c) 2012 OPeNDAP, Inc.
6 // Author: James Gallagher <jgallagher@opendap.org>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact University Corporation for Atmospheric Research at
23 // 3080 Center Green Drive, Boulder, CO 80301
24 
25 #include "config.h"
26 
27 #include <unistd.h>
28 
29 #include <cstdio>
30 #include <cstdlib>
31 
32 #include <sys/types.h> // For umask
33 #include <sys/stat.h>
34 
35 #include <iostream>
36 #include <fstream>
37 
38 #include <DataDDS.h>
39 #include <BaseType.h>
40 #include <escaping.h>
41 
42 using namespace libdap;
43 
44 #include "GeoTiffTransmitter.h"
45 #include "FONgTransform.h"
46 
47 #include <BESInternalError.h>
48 #include <BESContextManager.h>
49 #include <BESDataDDSResponse.h>
50 #include <BESDapNames.h>
51 #include <BESDataNames.h>
52 #include <BESDebug.h>
53 
54 #include <TheBESKeys.h>
55 
56 #define FONG_TEMP_DIR "/tmp"
57 #define FONG_GCS "WGS84"
58 
59 string GeoTiffTransmitter::temp_dir;
61 
79 {
80  // DATA_SERVICE == "dods"
82 
83  if (GeoTiffTransmitter::temp_dir.empty()) {
84  // Where is the temp directory for creating these files
85  bool found = false;
86  string key = "FONg.Tempdir";
87  TheBESKeys::TheKeys()->get_value(key, GeoTiffTransmitter::temp_dir, found);
88  if (!found || GeoTiffTransmitter::temp_dir.empty()) {
89  GeoTiffTransmitter::temp_dir = FONG_TEMP_DIR;
90  }
91  string::size_type len = GeoTiffTransmitter::temp_dir.length();
92  if (GeoTiffTransmitter::temp_dir[len - 1] == '/') {
93  GeoTiffTransmitter::temp_dir = GeoTiffTransmitter::temp_dir.substr(0, len - 1);
94  }
95  }
96 
97  if (GeoTiffTransmitter::default_gcs.empty()) {
98  // Use what as the default Geographic coordinate system?
99  bool found = false;
100  string key = "FONg.Default_GCS";
102  if (!found || GeoTiffTransmitter::default_gcs.empty()) {
104  }
105  }
106 }
107 
124 {
125  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(obj);
126  if (!bdds)
127  throw BESInternalError("cast error", __FILE__, __LINE__);
128 
129  DataDDS *dds = bdds->get_dds();
130  if (!dds)
131  throw BESInternalError("No DataDDS has been created for transmit", __FILE__, __LINE__);
132 
133  ostream &strm = dhi.get_output_stream();
134  if (!strm)
135  throw BESInternalError("Output stream is not set, cannot return as", __FILE__, __LINE__);
136 
137  BESDEBUG("fong2", "GeoTiffTransmitter::send_data - parsing the constraint" << endl);
138 
139  // ticket 1248 jhrg 2/23/09
140  string ce = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
141  try {
142  bdds->get_ce().parse_constraint(ce, *dds);
143  }
144  catch (Error &e) {
145  throw BESInternalError("Failed to parse the constraint expression: " + e.get_error_message(), __FILE__, __LINE__);
146  }
147  catch (...) {
148  throw BESInternalError("Failed to parse the constraint expression: Unknown exception caught", __FILE__, __LINE__);
149  }
150 
151  // now we need to read the data
152  BESDEBUG("fong2", "GeoTiffTransmitter::send_data - reading data into DataDDS" << endl);
153 
154  try {
155  // Handle *functional* constraint expressions specially
156  if (bdds->get_ce().function_clauses()) {
157  BESDEBUG("fonc", "processing a functional constraint clause(s)." << endl);
158  DataDDS *tmp_dds = bdds->get_ce().eval_function_clauses(*dds);
159  bdds->set_dds(tmp_dds);
160  delete dds;
161  dds = tmp_dds;
162  }
163  else {
164  // Iterate through the variables in the DataDDS and read
165  // in the data if the variable has the send flag set.
166  for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
167  if ((*i)->send_p()) {
168  (*i)->intern_data(bdds->get_ce(), *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  // Huh? Put the template for the temp file name in a char array. Use vector<char>
181  // to avoid using new/delete.
182  string temp_file_name = GeoTiffTransmitter::temp_dir + '/' + "geotiffXXXXXX";
183  vector<char> temp_file(temp_file_name.length() + 1);
184  string::size_type len = temp_file_name.copy(&temp_file[0], temp_file_name.length());
185  temp_file[len] = '\0';
186 
187  // cover the case where older versions of mkstemp() create the file using
188  // a mode of 666.
189  mode_t original_mode = umask(077);
190 
191  // Make and open (an atomic operation) the temporary file. Then reset the umask
192  int fd = mkstemp(&temp_file[0]);
193  umask(original_mode);
194 
195  if (fd == -1)
196  throw BESInternalError("Failed to open the temporary file: " + temp_file_name, __FILE__, __LINE__);
197 
198  // transform the OPeNDAP DataDDS to the geotiff file
199  BESDEBUG("fong2", "GeoTiffTransmitter::send_data - transforming into temporary file " << &temp_file[0] << endl);
200 
201  try {
202  FONgTransform ft(dds, bdds->get_ce(), &temp_file[0]);
203 
204  // transform() opens the temporary file, dumps data to it and closes it.
206 
207  BESDEBUG("fong2", "GeoTiffTransmitter::send_data - transmitting temp file " << &temp_file[0] << endl );
208 
209  GeoTiffTransmitter::return_temp_stream(&temp_file[0], strm);
210  }
211  catch (BESError &e) {
212  close(fd);
213  (void) unlink(&temp_file[0]);
214  throw;
215  }
216  catch (Error &e) {
217  close(fd);
218  (void) unlink(&temp_file[0]);
219  throw BESInternalError(e.get_error_message(), __FILE__, __LINE__);
220  }
221 
222  catch (...) {
223  close(fd);
224  (void) unlink(&temp_file[0]);
225  throw BESInternalError("Fileout GeoTiff, was not able to transform to geotiff, unknown error", __FILE__, __LINE__);
226  }
227 
228  close(fd);
229  (void) unlink(&temp_file[0]);
230 
231  BESDEBUG("fong2", "GeoTiffTransmitter::send_data - done transmitting to geotiff" << endl);
232 }
233 
243 void GeoTiffTransmitter::return_temp_stream(const string &filename, ostream &strm)
244 {
245  ifstream os;
246  os.open(filename.c_str(), ios::binary | ios::in);
247  if (!os)
248  throw BESInternalError("Cannot connect to data source", __FILE__, __LINE__);
249 
250  char block[4096];
251  os.read(block, sizeof block);
252  int nbytes = os.gcount();
253  if (nbytes == 0) {
254  os.close();
255  throw BESInternalError("Internal server error, got zero count on stream buffer.", __FILE__, __LINE__);
256  }
257 
258  bool found = false;
259  string context = "transmit_protocol";
260  string protocol = BESContextManager::TheManager()->get_context(context, found);
261  if (protocol == "HTTP") {
262  strm << "HTTP/1.0 200 OK\n";
263  strm << "Content-type: application/octet-stream\n";
264  strm << "Content-Description: " << "BES dataset" << "\n";
265  strm << "Content-Disposition: filename=" << filename << ".tif;\n\n";
266  strm << flush;
267  }
268  strm.write(block, nbytes);
269 
270  while (os) {
271  os.read(block, sizeof block);
272  nbytes = os.gcount();
273  strm.write(block, nbytes);
274  }
275 
276  os.close();
277 }
278 
#define DATA_SERVICE
Definition: BESDapNames.h:71
void set_dds(DataDDS *ddsIn)
Set the response object's DDS.
exception thrown if inernal error encountered
static string default_gcs
virtual void transform_to_geotiff()
Transforms the variables of the DataDDS to a GeoTiff file.
virtual bool add_method(string method_name, p_transmitter trans_method)
virtual string get_context(const string &name, bool &found)
retrieve the value of the specified context from the BES
static class NCMLUtil overview
#define FONG_GCS
Abstract exception class for the BES with basic string message.
Definition: BESError.h:51
GeoTiffTransmitter()
Construct the GeoTiffTransmitter, adding it with name geotiff to be able to transmit a data response...
#define FONG_TEMP_DIR
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
static BESContextManager * TheManager()
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
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.
Transformation object that converts an OPeNDAP DataDDS to a GeoTiff file.
Definition: FONgTransform.h:41
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static void send_data_as_geotiff(BESResponseObject *obj, BESDataHandlerInterface &dhi)
The static method registered to transmit OPeNDAP data objects as a netcdf file.
static BESKeys * TheKeys()
Definition: TheBESKeys.cc:48
Abstract base class representing a specific set of information in response to a request to the BES...