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
55using namespace xml_data;
56using namespace libdap;
57
58#define MODULE "xml_data"
59#define prolog string("BESXDTransmit::").append(__func__).append("() - ")
60
61void 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...