bes  Updated for version 3.20.5
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 
35 using std::ostringstream;
36 
37 #include "BESXMLInfo.h"
38 #include "BESUtil.h"
39 #include "BESDataNames.h"
40 
41 #define MY_ENCODING "ISO-8859-1"
42 #define BES_SCHEMA "http://xml.opendap.org/ns/bes/1.0#"
43 
50  BESInfo(), _writer(0), _doc_buf(0), _started(false), _ended(false)
51 {
52 }
53 
54 BESXMLInfo::~BESXMLInfo()
55 {
56  cleanup();
57 }
58 
59 void BESXMLInfo::cleanup()
60 {
61  // make sure the buffer and writer are all cleaned up
62  if (_writer) {
63  xmlFreeTextWriter(_writer);
64  _writer = 0;
65  _doc_buf = 0;
66  }
67 
68  if (_doc_buf) {
69  xmlBufferFree(_doc_buf);
70  _doc_buf = 0;
71  }
72 
73  // this always seems to be causing a memory fault
74  // xmlCleanupParser();
75 
76  _started = false;
77  _ended = false;
78  if (_strm) {
79  ((ostringstream *) _strm)->str("");
80  }
81 }
82 
91 void BESXMLInfo::begin_response(const string &response_name, BESDataHandlerInterface &dhi)
92 {
93  map<string, string> empty_attrs;
94  begin_response(response_name, &empty_attrs, dhi);
95 
96 }
105 void BESXMLInfo::begin_response(const string &response_name, map<string, string> *attrs, BESDataHandlerInterface &dhi)
106 {
107  BESInfo::begin_response(response_name, attrs, dhi);
108 
109  _response_name = response_name;
110 
111 #if 1
112  LIBXML_TEST_VERSION
113 #endif
114 
115  int rc = 0;
116 
117  /* Create a new XML buffer, to which the XML document will be
118  * written */
119  _doc_buf = xmlBufferCreate();
120  if (_doc_buf == NULL) {
121  cleanup();
122  string err = (string) "Error creating the xml buffer for response " + _response_name;
123  throw BESInternalError(err, __FILE__, __LINE__);
124  }
125 
126  /* Create a new XmlWriter for memory, with no compression.
127  * Remark: there is no compression for this kind of xmlTextWriter */
128  _writer = xmlNewTextWriterMemory(_doc_buf, 0);
129  if (_writer == NULL) {
130  cleanup();
131  string err = (string) "Error creating the xml writer for response " + _response_name;
132  throw BESInternalError(err, __FILE__, __LINE__);
133  }
134 
135  rc = xmlTextWriterSetIndent(_writer, 4);
136  if (rc < 0) {
137  cleanup();
138  string err = (string) "Error starting indentation for response document " + _response_name;
139  throw BESInternalError(err, __FILE__, __LINE__);
140  }
141 
142  rc = xmlTextWriterSetIndentString( _writer, BAD_CAST " " );
143  if (rc < 0) {
144  cleanup();
145  string err = (string) "Error setting indentation for response document " + _response_name;
146  throw BESInternalError(err, __FILE__, __LINE__);
147  }
148 
149  _started = true;
150 
151  /* Start the document with the xml default for the version,
152  * encoding ISO 8859-1 and the default for the standalone
153  * declaration. MY_ENCODING defined at top of this file*/
154  rc = xmlTextWriterStartDocument(_writer, NULL, MY_ENCODING, NULL);
155  if (rc < 0) {
156  cleanup();
157  string err = (string) "Error starting xml response document for " + _response_name;
158  throw BESInternalError(err, __FILE__, __LINE__);
159  }
160 
161  /* Start an element named "response". Since this is the first element,
162  * this will be the root element of the document */
163  rc = xmlTextWriterStartElementNS(_writer, NULL, BAD_CAST "response", BAD_CAST BES_SCHEMA);
164  if (rc < 0) {
165  cleanup();
166  string err = (string) "Error starting the response element for response " + _response_name;
167  throw BESInternalError(err, __FILE__, __LINE__);
168  }
169 
170  /* Add the request id attribute */
171  string reqid = dhi.data[REQUEST_ID];
172  if (!reqid.empty()) {
173  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID,
174  BAD_CAST reqid.c_str() );
175  if (rc < 0) {
176  cleanup();
177  string err = (string) "Error adding attribute " + REQUEST_ID + " for response " + _response_name;
178  throw BESInternalError(err, __FILE__, __LINE__);
179  }
180  }
181 
182  /* Start an element for the specific response. */
183  rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() );
184  if (rc < 0) {
185  cleanup();
186  string err = (string) "Error creating root element for response " + _response_name;
187  throw BESInternalError(err, __FILE__, __LINE__);
188  }
189 
190  map<string, string>::iterator it;
191  for ( it = attrs->begin(); it != attrs->end(); it++ )
192  {
193  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST it->first.c_str(), BAD_CAST it->second.c_str());
194  if (rc < 0) {
195  cleanup();
196  string err = (string) "Error creating root element for response " + _response_name;
197  throw BESInternalError(err, __FILE__, __LINE__);
198  }
199  }
200 
201  }
202 
211 {
212  BESInfo::end_response();
213 
214  int rc = 0;
215 
216  // this should end the response element
217  rc = xmlTextWriterEndElement(_writer);
218  if (rc < 0) {
219  cleanup();
220  string err = (string) "Error ending response element for response " + _response_name;
221  throw BESInternalError(err, __FILE__, __LINE__);
222  }
223 
224  // this should end the specific response element, like showVersion
225  rc = xmlTextWriterEndElement(_writer);
226  if (rc < 0) {
227  cleanup();
228  string err = (string) "Error ending specific response element " + "for response " + _response_name;
229  throw BESInternalError(err, __FILE__, __LINE__);
230  }
231 
232  rc = xmlTextWriterEndDocument(_writer);
233  if (rc < 0) {
234  cleanup();
235  string err = (string) "Error ending the response document for response " + _response_name;
236  throw BESInternalError(err, __FILE__, __LINE__);
237  }
238 
239  // must call this before getting the buffer content
240  xmlFreeTextWriter(_writer);
241  _writer = 0;
242 
243  // get the xml document as a string and return
244  if (!_doc_buf->content) {
245  cleanup();
246  string err = (string) "Error retrieving response document as string " + "for response " + _response_name;
247  throw BESInternalError(err, __FILE__, __LINE__);
248  }
249  else {
250  _doc = (char *) _doc_buf->content;
251  }
252 
253  _ended = true;
254 
255  cleanup();
256 }
257 
264 void BESXMLInfo::add_tag(const string &tag_name, const string &tag_data, map<string, string> *attrs)
265 {
266  /* Start an element named tag_name. */
267  int rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str() );
268  if (rc < 0) {
269  cleanup();
270  string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
271  throw BESInternalError(err, __FILE__, __LINE__);
272  }
273 
274  if (attrs) {
275  map<string, string>::const_iterator i = attrs->begin();
276  map<string, string>::const_iterator e = attrs->end();
277  for (; i != e; i++) {
278  string name = (*i).first;
279  string val = (*i).second;
280 
281  // FIXME: is there one with no value?
282  /* Add the attributes */
283  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
284  BAD_CAST val.c_str() );
285  if (rc < 0) {
286  cleanup();
287  string err = (string) "Error adding attribute " + name + " for response " + _response_name;
288  throw BESInternalError(err, __FILE__, __LINE__);
289  }
290  }
291  }
292 
293  /* Write the value of the element */
294  if (!tag_data.empty()) {
295  rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() );
296  if (rc < 0) {
297  cleanup();
298  string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
299  throw BESInternalError(err, __FILE__, __LINE__);
300  }
301  }
302 
303  // this should end the tag_name element
304  rc = xmlTextWriterEndElement(_writer);
305  if (rc < 0) {
306  cleanup();
307  string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
308  throw BESInternalError(err, __FILE__, __LINE__);
309  }
310 }
311 
317 void BESXMLInfo::begin_tag(const string &tag_name, map<string, string> *attrs)
318 {
319  begin_tag(tag_name, "", "", attrs);
320 }
321 
329 void BESXMLInfo::begin_tag(const string &tag_name, const string &ns, const string &uri, map<string, string> *attrs)
330 {
331  BESInfo::begin_tag(tag_name);
332 
333  /* Start an element named tag_name. */
334  int rc = 0;
335  if (ns.empty() && uri.empty()) {
336  rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
337  if (rc < 0) {
338  cleanup();
339  string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
340  throw BESInternalError(err, __FILE__, __LINE__);
341  }
342  }
343  else {
344  const char *cns = NULL;
345  if (!ns.empty()) cns = ns.c_str();
346  rc = xmlTextWriterStartElementNS( _writer,
347  BAD_CAST cns,
348  BAD_CAST tag_name.c_str(),
349  BAD_CAST uri.c_str() );
350  if (rc < 0) {
351  cleanup();
352  string err = (string) "Error starting element " + tag_name + " for response " + _response_name;
353  throw BESInternalError(err, __FILE__, __LINE__);
354  }
355  }
356 
357  if (attrs) {
358  map<string, string>::const_iterator i = attrs->begin();
359  map<string, string>::const_iterator e = attrs->end();
360  for (; i != e; i++) {
361  string name = (*i).first;
362  string val = (*i).second;
363 
364  /* Add the attributes */
365  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
366  BAD_CAST val.c_str() );
367  if (rc < 0) {
368  cleanup();
369  string err = (string) "Error adding attribute " + name + " for response " + _response_name;
370  throw BESInternalError(err, __FILE__, __LINE__);
371  }
372  }
373  }
374 }
375 
382 void BESXMLInfo::end_tag(const string &tag_name)
383 {
384  BESInfo::end_tag(tag_name);
385 
386  int rc = 0;
387 
388  string s = ((ostringstream *) _strm)->str();
389  if (!s.empty()) {
390  /* Write the value of the element */
391  rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
392  if (rc < 0) {
393  cleanup();
394  string err = (string) "Error writing the value for element " + tag_name + " for response " + _response_name;
395  throw BESInternalError(err, __FILE__, __LINE__);
396  }
397 
398  ((ostringstream *) _strm)->str("");
399  }
400 
401  // this should end the tag_name element
402  rc = xmlTextWriterEndElement(_writer);
403  if (rc < 0) {
404  cleanup();
405  string err = (string) "Error ending element " + tag_name + " for response " + _response_name;
406  throw BESInternalError(err, __FILE__, __LINE__);
407  }
408 }
409 
414 void BESXMLInfo::add_space(unsigned long num_spaces)
415 {
416  string to_add;
417  for (unsigned long i = 0; i < num_spaces; i++) {
418  to_add += " ";
419  }
420  BESInfo::add_data(to_add);
421 }
422 
427 void BESXMLInfo::add_break(unsigned long num_breaks)
428 {
429  string to_add;
430  for (unsigned long i = 0; i < num_breaks; i++) {
431  to_add += "\n";
432  }
433  BESInfo::add_data(to_add);
434 }
435 
436 void BESXMLInfo::add_data(const string &s)
437 {
438 #if 0
440 #else
441  int rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() );
442  if (rc < 0) {
443  cleanup();
444  throw BESInternalError(string("Error writing String data for response ") + _response_name, __FILE__, __LINE__);
445  }
446 #endif
447 }
448 
457 void BESXMLInfo::add_data_from_file(const string &key, const string &name)
458 {
459  // just add the html file with the <html ... wrapper around it
460  // <html xmlns="http://www.w3.org/1999/xhtml">
461  begin_tag("html", "", "http://www.w3.org/1999/xhtml");
462 
463  string newkey = key + ".HTML";
464  BESInfo::add_data_from_file(newkey, name);
465 
466  end_tag("html");
467 }
468 
478 {
479  if (_started && !_ended) {
480  end_response();
481  }
482  transmitter->send_text(*this, dhi);
483 }
484 
490 void BESXMLInfo::print(ostream &strm)
491 {
492  if (_started && !_ended) {
493  end_response();
494  }
495  strm << _doc;
496 }
497 
505 void BESXMLInfo::dump(ostream &strm) const
506 {
507  strm << BESIndent::LMarg << "BESXMLInfo::dump - (" << (void *) this << ")" << endl;
508  BESIndent::Indent();
509  BESInfo::dump(strm);
510  BESIndent::UnIndent();
511 }
512 
513 BESInfo *
514 BESXMLInfo::BuildXMLInfo(const string &/*info_type*/)
515 {
516  return new BESXMLInfo();
517 }
518 
virtual void dump(ostream &strm) const
dumps information about this object
Definition: BESXMLInfo.cc:505
virtual void end_response()
end the response
Definition: BESXMLInfo.cc:210
virtual void dump(ostream &strm) const
Displays debug information about this object.
Definition: BESInfo.cc:275
exception thrown if inernal error encountered
virtual void add_data_from_file(const string &key, const string &name)
add data from a file to the informational object.
Definition: BESInfo.cc:182
virtual void add_data_from_file(const string &key, const string &name)
add data from a file to the informational object
Definition: BESXMLInfo.cc:457
virtual void end_tag(const string &tag_name)
end a tagged part of the informational response
Definition: BESXMLInfo.cc:382
virtual void print(ostream &strm)
print the information from this informational object to the specified stream
Definition: BESXMLInfo.cc:490
virtual void begin_response(const string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESXMLInfo.cc:91
BESXMLInfo()
constructs an informational response object as an xml document
Definition: BESXMLInfo.cc:49
informational response object
Definition: BESInfo.h:68
virtual void add_space(unsigned long num_spaces)
add a space to the informational response
Definition: BESXMLInfo.cc:414
virtual void add_break(unsigned long num_breaks)
add a line break to the information
Definition: BESXMLInfo.cc:427
virtual void begin_tag(const string &tag_name, const string &ns, const string &uri, map< string, string > *attrs=0)
begin a tagged part of the information, information to follow
Definition: BESXMLInfo.cc:329
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.
virtual void add_tag(const string &tag_name, const string &tag_data, map< string, string > *attrs=0)
add tagged information to the informational response
Definition: BESXMLInfo.cc:264
virtual void begin_response(const string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESInfo.cc:124
virtual void add_data(const 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 transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)
transmit the text information as text
Definition: BESXMLInfo.cc:477
virtual void add_data(const string &s)
add data to this informational object. If buffering is not set then the information is output directl...
Definition: BESXMLInfo.cc:436