bes Updated for version 3.20.13
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> empty_attrs;
99 begin_response(response_name, &empty_attrs, dhi);
100
101}
110void BESXMLInfo::begin_response(const string &response_name, map<string, string> *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];
177 if (!reqid.empty()) {
178 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID,
179 BAD_CAST reqid.c_str() );
180 if (rc < 0) {
181 cleanup();
182 string err = (string) "Error adding attribute " + REQUEST_ID + " for response " + _response_name;
183 throw BESInternalError(err, __FILE__, __LINE__);
184 }
185 }
186
187 /* Start an element for the specific response. */
188 rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() );
189 if (rc < 0) {
190 cleanup();
191 string err = (string) "Error creating root element for response " + _response_name;
192 throw BESInternalError(err, __FILE__, __LINE__);
193 }
194
195 map<string, string>::iterator it;
196 for ( it = attrs->begin(); it != attrs->end(); it++ )
197 {
198 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST it->first.c_str(), BAD_CAST it->second.c_str());
199 if (rc < 0) {
200 cleanup();
201 string err = (string) "Error creating root element for response " + _response_name;
202 throw BESInternalError(err, __FILE__, __LINE__);
203 }
204 }
205
206 }
207
216{
217 BESInfo::end_response();
218
219 int rc = 0;
220
221 // this should end the response element
222 rc = xmlTextWriterEndElement(_writer);
223 if (rc < 0) {
224 cleanup();
225 string err = (string) "Error ending response element for response " + _response_name;
226 throw BESInternalError(err, __FILE__, __LINE__);
227 }
228
229 // this should end the specific response element, like showVersion
230 rc = xmlTextWriterEndElement(_writer);
231 if (rc < 0) {
232 cleanup();
233 string err = (string) "Error ending specific response element " + "for response " + _response_name;
234 throw BESInternalError(err, __FILE__, __LINE__);
235 }
236
237 rc = xmlTextWriterEndDocument(_writer);
238 if (rc < 0) {
239 cleanup();
240 string err = (string) "Error ending the response document for response " + _response_name;
241 throw BESInternalError(err, __FILE__, __LINE__);
242 }
243
244 // must call this before getting the buffer content
245 xmlFreeTextWriter(_writer);
246 _writer = 0;
247
248 // get the xml document as a string and return
249 if (!_doc_buf->content) {
250 cleanup();
251 string err = (string) "Error retrieving response document as string " + "for response " + _response_name;
252 throw BESInternalError(err, __FILE__, __LINE__);
253 }
254 else {
255 _doc = (char *) _doc_buf->content;
256 }
257
258 _ended = true;
259
260 cleanup();
261}
262
269void BESXMLInfo::add_tag(const string &tag_name, const string &tag_data, map<string, string> *attrs)
270{
271 /* Start an element named tag_name. */
272 int rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str() );
273 if (rc < 0) {
274 cleanup();
275 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
276 throw BESInternalError(err, __FILE__, __LINE__);
277 }
278
279 if (attrs) {
280 map<string, string>::const_iterator i = attrs->begin();
281 map<string, string>::const_iterator e = attrs->end();
282 for (; i != e; i++) {
283 string name = (*i).first;
284 string val = (*i).second;
285
286 // FIXME: is there one with no value?
287 /* Add the attributes */
288 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
289 BAD_CAST val.c_str() );
290 if (rc < 0) {
291 cleanup();
292 string err = (string) "Error adding attribute " + name + " for response " + _response_name;
293 throw BESInternalError(err, __FILE__, __LINE__);
294 }
295 }
296 }
297
298 /* Write the value of the element */
299 if (!tag_data.empty()) {
300 rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() );
301 if (rc < 0) {
302 cleanup();
303 string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
304 throw BESInternalError(err, __FILE__, __LINE__);
305 }
306 }
307
308 // this should end the tag_name element
309 rc = xmlTextWriterEndElement(_writer);
310 if (rc < 0) {
311 cleanup();
312 string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
313 throw BESInternalError(err, __FILE__, __LINE__);
314 }
315}
316
322void BESXMLInfo::begin_tag(const string &tag_name, map<string, string> *attrs)
323{
324 begin_tag(tag_name, "", "", attrs);
325}
326
334void BESXMLInfo::begin_tag(const string &tag_name, const string &ns, const string &uri, map<string, string> *attrs)
335{
336 BESInfo::begin_tag(tag_name);
337
338 /* Start an element named tag_name. */
339 int rc = 0;
340 if (ns.empty() && uri.empty()) {
341 rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
342 if (rc < 0) {
343 cleanup();
344 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
345 throw BESInternalError(err, __FILE__, __LINE__);
346 }
347 }
348 else {
349 const char *cns = NULL;
350 if (!ns.empty()) cns = ns.c_str();
351 rc = xmlTextWriterStartElementNS( _writer,
352 BAD_CAST cns,
353 BAD_CAST tag_name.c_str(),
354 BAD_CAST uri.c_str() );
355 if (rc < 0) {
356 cleanup();
357 string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
358 throw BESInternalError(err, __FILE__, __LINE__);
359 }
360 }
361
362 if (attrs) {
363 map<string, string>::const_iterator i = attrs->begin();
364 map<string, string>::const_iterator e = attrs->end();
365 for (; i != e; i++) {
366 string name = (*i).first;
367 string val = (*i).second;
368
369 /* Add the attributes */
370 rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
371 BAD_CAST val.c_str() );
372 if (rc < 0) {
373 cleanup();
374 string err = (string) "Error adding attribute " + name + " for response " + _response_name;
375 throw BESInternalError(err, __FILE__, __LINE__);
376 }
377 }
378 }
379}
380
387void BESXMLInfo::end_tag(const string &tag_name)
388{
389 BESInfo::end_tag(tag_name);
390
391 int rc = 0;
392
393 string s = ((ostringstream *) _strm)->str();
394 if (!s.empty()) {
395 /* Write the value of the element */
396 rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
397 if (rc < 0) {
398 cleanup();
399 string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
400 throw BESInternalError(err, __FILE__, __LINE__);
401 }
402
403 ((ostringstream *) _strm)->str("");
404 }
405
406 // this should end the tag_name element
407 rc = xmlTextWriterEndElement(_writer);
408 if (rc < 0) {
409 cleanup();
410 string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
411 throw BESInternalError(err, __FILE__, __LINE__);
412 }
413}
414
419void BESXMLInfo::add_space(unsigned long num_spaces)
420{
421 string to_add;
422 for (unsigned long i = 0; i < num_spaces; i++) {
423 to_add += " ";
424 }
425 BESInfo::add_data(to_add);
426}
427
432void BESXMLInfo::add_break(unsigned long num_breaks)
433{
434 string to_add;
435 for (unsigned long i = 0; i < num_breaks; i++) {
436 to_add += "\n";
437 }
438 BESInfo::add_data(to_add);
439}
440
441void BESXMLInfo::add_data(const string &s)
442{
443#if 0
445#else
446 int rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
447 if (rc < 0) {
448 cleanup();
449 throw BESInternalError(string("Error writing String data for response ") + _response_name, __FILE__, __LINE__);
450 }
451#endif
452}
453
462void BESXMLInfo::add_data_from_file(const string &key, const string &name)
463{
464 // just add the html file with the <html ... wrapper around it
465 // <html xmlns="http://www.w3.org/1999/xhtml">
466 begin_tag("html", "", "http://www.w3.org/1999/xhtml");
467
468 string newkey = key + ".HTML";
469 BESInfo::add_data_from_file(newkey, name);
470
471 end_tag("html");
472}
473
483{
484 if (_started && !_ended) {
485 end_response();
486 }
487 transmitter->send_text(*this, dhi);
488}
489
495void BESXMLInfo::print(ostream &strm)
496{
497 if (_started && !_ended) {
498 end_response();
499 }
500 strm << _doc;
501}
502
510void BESXMLInfo::dump(ostream &strm) const
511{
512 strm << BESIndent::LMarg << "BESXMLInfo::dump - (" << (void *) this << ")" << endl;
513 BESIndent::Indent();
514 BESInfo::dump(strm);
515 BESIndent::UnIndent();
516}
517
518BESInfo *
519BESXMLInfo::BuildXMLInfo(const string &/*info_type*/)
520{
521 return new BESXMLInfo();
522}
523
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:160
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESInfo.cc:124
virtual void dump(std::ostream &strm) const
Displays debug information about this object.
Definition: BESInfo.cc:275
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:182
exception thrown if internal error encountered
virtual void add_tag(const std::string &tag_name, const std::string &tag_data, std::map< std::string, std::string > *attrs=0)
add tagged information to the informational response
Definition: BESXMLInfo.cc:269
virtual void end_tag(const std::string &tag_name)
end a tagged part of the informational response
Definition: BESXMLInfo.cc:387
virtual void add_data_from_file(const std::string &key, const std::string &name)
add data from a file to the informational object
Definition: BESXMLInfo.cc:462
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)
transmit the text information as text
Definition: BESXMLInfo.cc:482
virtual void end_response()
end the response
Definition: BESXMLInfo.cc:215
virtual void add_space(unsigned long num_spaces)
add a space to the informational response
Definition: BESXMLInfo.cc:419
virtual void add_break(unsigned long num_breaks)
add a line break to the information
Definition: BESXMLInfo.cc:432
BESXMLInfo()
constructs an informational response object as an xml document
Definition: BESXMLInfo.cc:54
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: BESXMLInfo.cc:441
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESXMLInfo.cc:96
virtual void begin_tag(const std::string &tag_name, const std::string &ns, const std::string &uri, std::map< std::string, std::string > *attrs=0)
begin a tagged part of the information, information to follow
Definition: BESXMLInfo.cc:334
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: BESXMLInfo.cc:510
virtual void print(std::ostream &strm)
print the information from this informational object to the specified stream
Definition: BESXMLInfo.cc:495