bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
BESXMLInfo.cc
1// BESXMLInfo.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-2009 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// (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27// Please read the full copyright statement in the file COPYRIGHT_UCAR.
28//
29// Authors:
30// pwest Patrick West <pwest@ucar.edu>
31// jgarcia Jose Garcia <jgarcia@ucar.edu>
32
33#include <sstream>
34#include <map>
35
36using std::ostringstream;
37using std::endl;
38using std::map;
39using std::string;
40using std::ostream;
41
42#include "BESXMLInfo.h"
43#include "BESUtil.h"
44#include "BESDataNames.h"
45
46#define MY_ENCODING "ISO-8859-1"
47#define BES_SCHEMA "http://xml.opendap.org/ns/bes/1.0#"
48
55 BESInfo(), _writer(0), _doc_buf(0), _started(false), _ended(false)
56{
57}
58
59BESXMLInfo::~BESXMLInfo()
60{
61 cleanup();
62}
63
64void BESXMLInfo::cleanup()
65{
66 // make sure the buffer and writer are all cleaned up
67 if (_writer) {
68 xmlFreeTextWriter(_writer);
69 _writer = 0;
70 _doc_buf = 0;
71 }
72
73 if (_doc_buf) {
74 xmlBufferFree(_doc_buf);
75 _doc_buf = 0;
76 }
77
78 // this always seems to be causing a memory fault
79 // xmlCleanupParser();
80
81 _started = false;
82 _ended = false;
83 if (_strm) {
84 ((ostringstream *) _strm)->str("");
85 }
86}
87
96void BESXMLInfo::begin_response(const string &response_name, BESDataHandlerInterface &dhi)
97{
98 map<string, string, std::less<>> empty_attrs;
99 begin_response(response_name, &empty_attrs, dhi);
100
101}
102
110void BESXMLInfo::begin_response(const string &response_name, map<string, string, std::less<>> *attrs, BESDataHandlerInterface &dhi)
111{
112 BESInfo::begin_response(response_name, attrs, dhi);
113
114 _response_name = response_name;
115
116#if 1
117 LIBXML_TEST_VERSION
118#endif
119
120 int rc = 0;
121
122 /* Create a new XML buffer, to which the XML document will be
123 * written */
124 _doc_buf = xmlBufferCreate();
125 if (_doc_buf == NULL) {
126 cleanup();
127 string err = (string) "Error creating the xml buffer for response " + _response_name;
128 throw BESInternalError(err, __FILE__, __LINE__);
129 }
130
131 /* Create a new XmlWriter for memory, with no compression.
132 * Remark: there is no compression for this kind of xmlTextWriter */
133 _writer = xmlNewTextWriterMemory(_doc_buf, 0);
134 if (_writer == NULL) {
135 cleanup();
136 string err = (string) "Error creating the xml writer for response " + _response_name;
137 throw BESInternalError(err, __FILE__, __LINE__);
138 }
139
140 rc = xmlTextWriterSetIndent(_writer, 4);
141 if (rc < 0) {
142 cleanup();
143 string err = (string) "Error starting indentation for response document " + _response_name;
144 throw BESInternalError(err, __FILE__, __LINE__);
145 }
146
147 rc = xmlTextWriterSetIndentString( _writer, BAD_CAST " " );
148 if (rc < 0) {
149 cleanup();
150 string err = (string) "Error setting indentation for response document " + _response_name;
151 throw BESInternalError(err, __FILE__, __LINE__);
152 }
153
154 _started = true;
155
156 /* Start the document with the xml default for the version,
157 * encoding ISO 8859-1 and the default for the standalone
158 * declaration. MY_ENCODING defined at top of this file*/
159 rc = xmlTextWriterStartDocument(_writer, NULL, MY_ENCODING, NULL);
160 if (rc < 0) {
161 cleanup();
162 string err = (string) "Error starting xml response document for " + _response_name;
163 throw BESInternalError(err, __FILE__, __LINE__);
164 }
165
166 /* Start an element named "response". Since this is the first element,
167 * this will be the root element of the document */
168 rc = xmlTextWriterStartElementNS(_writer, NULL, BAD_CAST "response", BAD_CAST BES_SCHEMA);
169 if (rc < 0) {
170 cleanup();
171 string err = (string) "Error starting the response element for response " + _response_name;
172 throw BESInternalError(err, __FILE__, __LINE__);
173 }
174
175 /* Add the request id attribute */
176 string reqid = dhi.data[REQUEST_ID_KEY];
177 if (!reqid.empty()) {
178 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID_KEY,
179 BAD_CAST reqid.c_str() );
180 if (rc < 0) {
181 cleanup();
182 string err = (string) "Error adding attribute " + REQUEST_ID_KEY + " for response " + _response_name;
183 throw BESInternalError(err, __FILE__, __LINE__);
184 }
185 }
186
187 /* Add the request uuid attribute */
188 string req_uuid = dhi.data[REQUEST_UUID_KEY];
189 if (!req_uuid.empty()) {
190 rc = xmlTextWriterWriteAttribute( _writer, (const xmlChar *)( REQUEST_UUID_KEY),
191 (const xmlChar *)(req_uuid.c_str()) );
192 if (rc < 0) {
193 cleanup();
194 string err = (string) "Error adding attribute " + REQUEST_UUID_KEY + " for response " + _response_name;
195 throw BESInternalError(err, __FILE__, __LINE__);
196 }
197 }
198
199 /* Start an element for the specific response. */
200 rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() );
201 if (rc < 0) {
202 cleanup();
203 string err = (string) "Error creating root element for response " + _response_name;
204 throw BESInternalError(err, __FILE__, __LINE__);
205 }
206
208 for ( it = attrs->begin(); it != attrs->end(); it++ )
209 {
210 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST it->first.c_str(), BAD_CAST it->second.c_str());
211 if (rc < 0) {
212 cleanup();
213 string err = (string) "Error creating root element for response " + _response_name;
214 throw BESInternalError(err, __FILE__, __LINE__);
215 }
216 }
217
218 }
219
228{
229 BESInfo::end_response();
230
231 int rc = 0;
232
233 // this should end the response element
234 rc = xmlTextWriterEndElement(_writer);
235 if (rc < 0) {
236 cleanup();
237 string err = (string) "Error ending response element for response " + _response_name;
238 throw BESInternalError(err, __FILE__, __LINE__);
239 }
240
241 // this should end the specific response element, like showVersion
242 rc = xmlTextWriterEndElement(_writer);
243 if (rc < 0) {
244 cleanup();
245 string err = (string) "Error ending specific response element " + "for response " + _response_name;
246 throw BESInternalError(err, __FILE__, __LINE__);
247 }
248
249 rc = xmlTextWriterEndDocument(_writer);
250 if (rc < 0) {
251 cleanup();
252 string err = (string) "Error ending the response document for response " + _response_name;
253 throw BESInternalError(err, __FILE__, __LINE__);
254 }
255
256 // must call this before getting the buffer content
257 xmlFreeTextWriter(_writer);
258 _writer = 0;
259
260 // get the xml document as a string and return
261 if (!_doc_buf->content) {
262 cleanup();
263 string err = (string) "Error retrieving response document as string " + "for response " + _response_name;
264 throw BESInternalError(err, __FILE__, __LINE__);
265 }
266 else {
267 _doc = (char *) _doc_buf->content;
268 }
269
270 _ended = true;
271
272 cleanup();
273}
274
281void BESXMLInfo::add_tag(const string &tag_name, const string &tag_data, map<string, string, std::less<>> *attrs)
282{
283 /* Start an element named tag_name. */
284 int rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str() );
285 if (rc < 0) {
286 cleanup();
287 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
288 throw BESInternalError(err, __FILE__, __LINE__);
289 }
290
291 if (attrs) {
292 map<string, string>::const_iterator i = attrs->begin();
294 for (; i != e; i++) {
295 string name = (*i).first;
296 string val = (*i).second;
297
298 // FIXME: is there one with no value?
299 /* Add the attributes */
300 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
301 BAD_CAST val.c_str() );
302 if (rc < 0) {
303 cleanup();
304 string err = (string) "Error adding attribute " + name + " for response " + _response_name;
305 throw BESInternalError(err, __FILE__, __LINE__);
306 }
307 }
308 }
309
310 /* Write the value of the element */
311 if (!tag_data.empty()) {
312 rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() );
313 if (rc < 0) {
314 cleanup();
315 string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
316 throw BESInternalError(err, __FILE__, __LINE__);
317 }
318 }
319
320 // this should end the tag_name element
321 rc = xmlTextWriterEndElement(_writer);
322 if (rc < 0) {
323 cleanup();
324 string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
325 throw BESInternalError(err, __FILE__, __LINE__);
326 }
327}
328
334void BESXMLInfo::begin_tag(const string &tag_name, map<string, string, std::less<>> *attrs)
335{
336 begin_tag(tag_name, "", "", attrs);
337}
338
346void BESXMLInfo::begin_tag(const string &tag_name,
347 const string &ns,
348 const string &uri,
349 map<string, string, std::less<>> *attrs = nullptr)
350{
351 BESInfo::begin_tag(tag_name);
352
353 /* Start an element named tag_name. */
354 int rc = 0;
355 if (ns.empty() && uri.empty()) {
356 rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
357 if (rc < 0) {
358 cleanup();
359 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
360 throw BESInternalError(err, __FILE__, __LINE__);
361 }
362 }
363 else {
364 const char *cns = nullptr;
365 if (!ns.empty()) cns = ns.c_str();
366 rc = xmlTextWriterStartElementNS( _writer,
367 BAD_CAST cns,
368 BAD_CAST tag_name.c_str(),
369 BAD_CAST uri.c_str() );
370 if (rc < 0) {
371 cleanup();
372 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
373 throw BESInternalError(err, __FILE__, __LINE__);
374 }
375 }
376
377 if (attrs) {
378 map<string, string>::const_iterator i = attrs->begin();
380 for (; i != e; i++) {
381 string name = (*i).first;
382 string val = (*i).second;
383
384 /* Add the attributes */
385 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
386 BAD_CAST val.c_str() );
387 if (rc < 0) {
388 cleanup();
389 string err = (string) "Error adding attribute " + name + " for response " + _response_name;
390 throw BESInternalError(err, __FILE__, __LINE__);
391 }
392 }
393 }
394}
395
402void BESXMLInfo::end_tag(const string &tag_name)
403{
404 BESInfo::end_tag(tag_name);
405
406 int rc = 0;
407
408 string s = ((ostringstream *) _strm)->str();
409 if (!s.empty()) {
410 /* Write the value of the element */
411 rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
412 if (rc < 0) {
413 cleanup();
414 string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
415 throw BESInternalError(err, __FILE__, __LINE__);
416 }
417
418 ((ostringstream *) _strm)->str("");
419 }
420
421 // this should end the tag_name element
422 rc = xmlTextWriterEndElement(_writer);
423 if (rc < 0) {
424 cleanup();
425 string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
426 throw BESInternalError(err, __FILE__, __LINE__);
427 }
428}
429
434void BESXMLInfo::add_space(unsigned long num_spaces)
435{
436 string to_add;
437 for (unsigned long i = 0; i < num_spaces; i++) {
438 to_add += " ";
439 }
440 BESInfo::add_data(to_add);
441}
442
447void BESXMLInfo::add_break(unsigned long num_breaks)
448{
449 string to_add;
450 for (unsigned long i = 0; i < num_breaks; i++) {
451 to_add += "\n";
452 }
453 BESInfo::add_data(to_add);
454}
455
456void BESXMLInfo::add_data(const string &s)
457{
458#if 0
460#else
461 int rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
462 if (rc < 0) {
463 cleanup();
464 throw BESInternalError(string("Error writing String data for response ") + _response_name, __FILE__, __LINE__);
465 }
466#endif
467}
468
477void BESXMLInfo::add_data_from_file(const string &key, const string &name)
478{
479 // just add the html file with the <html ... wrapper around it
480 // <html xmlns="http://www.w3.org/1999/xhtml">
481 begin_tag("html", "", "http://www.w3.org/1999/xhtml");
482
483 string newkey = key + ".HTML";
484 BESInfo::add_data_from_file(newkey, name);
485
486 end_tag("html");
487}
488
498{
499 if (_started && !_ended) {
500 end_response();
501 }
502 transmitter->send_text(*this, dhi);
503}
504
510void BESXMLInfo::print(ostream &strm)
511{
512 if (_started && !_ended) {
513 end_response();
514 }
515 strm << _doc;
516}
517
525void BESXMLInfo::dump(ostream &strm) const
526{
527 strm << BESIndent::LMarg << "BESXMLInfo::dump - (" << (void *) this << ")" << endl;
528 BESIndent::Indent();
529 BESInfo::dump(strm);
530 BESIndent::UnIndent();
531}
532
533BESInfo *
534BESXMLInfo::BuildXMLInfo(const string &/*info_type*/)
535{
536 return new BESXMLInfo();
537}
538
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.
informational response object
Definition BESInfo.h:63
virtual void add_data(const std::string &s)
add data to this informational object. If buffering is not set then the information is output directl...
Definition BESInfo.cc:151
BESInfo()
constructs a BESInfo object
Definition BESInfo.cc:52
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition BESInfo.cc:120
virtual void dump(std::ostream &strm) const
Displays debug information about this object.
Definition BESInfo.cc:262
virtual void add_data_from_file(const std::string &key, const std::string &name)
add data from a file to the informational object.
Definition BESInfo.cc:172
exception thrown if internal error encountered
void add_tag(const std::string &tag_name, const std::string &tag_data, std::map< std::string, std::string, std::less<> > *attrs=nullptr) override
add tagged information to the informational response
void dump(std::ostream &strm) const override
dumps information about this object
void add_data(const std::string &s) override
add data to this informational object. If buffering is not set then the information is output directl...
void add_break(unsigned long num_breaks) override
add a line break to the information
void add_data_from_file(const std::string &key, const std::string &name) override
add data from a file to the informational object
void end_tag(const std::string &tag_name) override
end a tagged part of the informational response
void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi) override
begin the informational response
Definition BESXMLInfo.cc:96
void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi) override
transmit the text information as text
void add_space(unsigned long num_spaces) override
add a space to the informational response
BESXMLInfo()
constructs an informational response object as an xml document
Definition BESXMLInfo.cc:54
void print(std::ostream &strm) override
print the information from this informational object to the specified stream
void begin_tag(const std::string &tag_name, const std::string &ns, const std::string &uri, std::map< std::string, std::string, std::less<> > *attrs)
begin a tagged part of the information, information to follow
void end_response() override
end the response
STL iterator class.
STL iterator class.