bes  Updated for version 3.20.13
BESXDTransmit.cc
1 // BESXDTransmit.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // Authors:
27 // pwest Patrick West <pwest@ucar.edu>
28 // jgarcia Jose Garcia <jgarcia@ucar.edu>
29 
30 #include <libdap/BaseType.h>
31 #include <libdap/Sequence.h>
32 #include <libdap/ConstraintEvaluator.h>
33 #include <libdap/DataDDS.h>
34 
35 #include <libdap/escaping.h>
36 #include <libdap/InternalErr.h>
37 #include <libdap/util.h>
38 #include <libdap/mime_util.h>
39 #include <libdap/XMLWriter.h>
40 
41 #include <BESUtil.h>
42 #include <BESDapTransmit.h>
43 #include <BESContainer.h>
44 #include <BESDataNames.h>
45 #include <BESDataDDSResponse.h>
46 #include <BESDapError.h>
47 #include <BESInternalFatalError.h>
48 #include <BESDebug.h>
49 #include <DapFunctionUtils.h>
50 #include <RequestServiceTimer.h>
51 
52 #include "BESXDTransmit.h"
53 #include "get_xml_data.h"
54 
55 using namespace xml_data;
56 using namespace libdap;
57 
58 #define MODULE "xml_data"
59 #define prolog string("BESXDTransmit::").append(__func__).append("() - ")
60 
61 void BESXDTransmit::send_basic_ascii(BESResponseObject * obj, BESDataHandlerInterface & dhi)
62 {
63  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() - BEGIN" << endl);
64  BESDataDDSResponse *bdds = dynamic_cast<BESDataDDSResponse *>(obj);
65  if (!bdds)
66  throw BESInternalFatalError("Expected a BESDataDDSResponse instance.", __FILE__, __LINE__);
67 
68  DDS *dds = bdds->get_dds();
69  ConstraintEvaluator & ce = bdds->get_ce();
70 
71  dhi.first_container();
72 
73  string constraint = www2id(dhi.data[POST_CONSTRAINT], "%", "%20%26");
74 
75  try {
76  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() - " "parsing constraint: " << constraint << endl);
77  ce.parse_constraint(constraint, *dds);
78  }
79  catch (InternalErr &e) {
80  string err = "Failed to parse the constraint expression: " + e.get_error_message();
81  throw BESDapError(err, true, e.get_error_code(), __FILE__, __LINE__);
82  }
83  catch (Error &e) {
84  string err = "Failed to parse the constraint expression: " + e.get_error_message();
85  throw BESDapError(err, false, e.get_error_code(), __FILE__, __LINE__);
86  }
87  catch (...) {
88  string err = (string) "Failed to parse the constraint expression: " + "Unknown exception caught";
89  throw BESInternalFatalError(err, __FILE__, __LINE__);
90  }
91 
92  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() - " "tagging sequences" << endl);
93  dds->tag_nested_sequences(); // Tag Sequences as Parent or Leaf node.
94 
95  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() - " "accessing container" << endl);
96  string dataset_name = dhi.container->access();
97 
98  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() - dataset_name = " << dataset_name << endl);
99 
100  bool functional_constraint = false;
101  try {
102  // Handle *functional* constraint expressions specially
103  if (ce.function_clauses()) {
104  BESDEBUG("xd", "BESXDTransmit::send_base_ascii() Processing functional constraint clause(s)." << endl);
105  DDS *tmp_dds = ce.eval_function_clauses(*dds);
106  delete dds;
107  dds = tmp_dds;
108  bdds->set_dds(dds);
109  // This next step utilizes a well known function, promote_function_output_structures()
110  // to look for one or more top level Structures whose name indicates (by way of ending
111  // with "_uwrap") that their contents should be promoted (aka moved) to the top level.
112  // This is in support of a hack around the current API where server side functions
113  // may only return a single DAP object and not a collection of objects. The name suffix
114  // "_unwrap" is used as a signal from the function to the the various response
115  // builders and transmitters that the representation needs to be altered before
116  // transmission, and that in fact is what happens in our friend
117  // promote_function_output_structures()
118  promote_function_output_structures(dds);
119  }
120  else {
121  // Iterate through the variables in the DataDDS and read
122  // in the data if the variable has the send flag set.
123  for (DDS::Vars_iter i = dds->var_begin(); i != dds->var_end(); i++) {
124  if ((*i)->send_p()) {
125  RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit " + (*i)->name() , __FILE__, __LINE__);
126  (*i)->intern_data(ce, *dds);
127  }
128  }
129  }
130  }
131  catch (InternalErr &e) {
132  if (functional_constraint)
133  delete dds;
134  string err = "Failed to read data: " + e.get_error_message();
135  throw BESDapError(err, true, e.get_error_code(), __FILE__, __LINE__);
136  }
137  catch (Error & e) {
138  if (functional_constraint)
139  delete dds;
140  string err = "Failed to read data: " + e.get_error_message();
141  throw BESDapError(err, false, e.get_error_code(), __FILE__, __LINE__);
142  }
143  catch (BESError &e) {
144  throw;
145  }
146  catch (...) {
147  if (functional_constraint)
148  delete dds;
149  string err = "Failed to read data: Unknown exception caught";
150  throw BESInternalFatalError(err, __FILE__, __LINE__);
151  }
152 
153  try {
154  // Now that we have constrained the DataDDS and read in the data,
155  // send it as ascii
156  BESDEBUG("xd", "converting to xd datadds" << endl);
157  DDS *xd_dds = dds_to_xd_dds(dds);
158 
159  // Verify the request hasn't exceeded bes_timeout.
160  RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
161 
162  // Now that we are ready to start building the response data we
163  // cancel any pending timeout alarm according to the configuration.
165 
166  BESDEBUG("xd", "getting xd values" << endl);
167  XMLWriter writer;
168  get_data_values_as_xml(xd_dds, &writer);
169  dhi.get_output_stream() << writer.get_doc();
170 
171  BESDEBUG("xd", "got the ascii values" << endl);
172  dhi.get_output_stream() << flush;
173  delete xd_dds;
174 
175  BESDEBUG("xd", "done transmitting ascii" << endl);
176  }
177  catch (InternalErr &e) {
178  if (functional_constraint)
179  delete dds;
180  string err = "Failed to get values as ascii: " + e.get_error_message();
181  throw BESDapError(err, true, e.get_error_code(), __FILE__, __LINE__);
182  }
183  catch (Error &e) {
184  if (functional_constraint)
185  delete dds;
186  string err = "Failed to get values as ascii: " + e.get_error_message();
187  throw BESDapError(err, false, e.get_error_code(), __FILE__, __LINE__);
188  }
189  catch (BESError &e) {
190  throw;
191  }
192  catch (...) {
193  if (functional_constraint)
194  delete dds;
195  string err = "Failed to get values as ascii: Unknown exception caught";
196  throw BESInternalFatalError(err, __FILE__, __LINE__);
197  }
198 
199  if (functional_constraint)
200  delete dds;
201 }
202 
203 
virtual std::string access()=0
returns the true name of this container
error object created from libdap error objects and can handle those errors
Definition: BESDapError.h:59
Represents an OPeNDAP DataDDS DAP2 data object within the BES.
void set_dds(libdap::DDS *ddsIn)
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.
void first_container()
set the container pointer to the first container in the containers list
BESContainer * container
pointer to current container in this interface
Base exception class for the BES with basic string message.
Definition: BESError.h:59
exception thrown if an internal error is found and is fatal to the BES
Abstract base class representing a specific set of information in response to a request to the BES.
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:895
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...