bes  Updated for version 3.20.6
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 
36 using std::ostringstream;
37 using std::endl;
38 using std::map;
39 using std::string;
40 using 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 
59 BESXMLInfo::~BESXMLInfo()
60 {
61  cleanup();
62 }
63 
64 void 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 
96 void 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 }
110 void 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 
269 void 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 
322 void BESXMLInfo::begin_tag(const string &tag_name, map<string, string> *attrs)
323 {
324  begin_tag(tag_name, "", "", attrs);
325 }
326 
334 void 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 
387 void 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 
419 void 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 
432 void 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 
441 void 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 
462 void 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 
495 void BESXMLInfo::print(ostream &strm)
496 {
497  if (_started && !_ended) {
498  end_response();
499  }
500  strm << _doc;
501 }
502 
510 void 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 
518 BESInfo *
519 BESXMLInfo::BuildXMLInfo(const string &/*info_type*/)
520 {
521  return new BESXMLInfo();
522 }
523 
BESXMLInfo::end_response
virtual void end_response()
end the response
Definition: BESXMLInfo.cc:215
BESXMLInfo::add_tag
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
BESXMLInfo::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: BESXMLInfo.cc:510
BESInfo
informational response object
Definition: BESInfo.h:63
BESXMLInfo::end_tag
virtual void end_tag(const std::string &tag_name)
end a tagged part of the informational response
Definition: BESXMLInfo.cc:387
BESXMLInfo::BESXMLInfo
BESXMLInfo()
constructs an informational response object as an xml document
Definition: BESXMLInfo.cc:54
BESInfo::add_data_from_file
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
BESXMLInfo::add_data
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
BESXMLInfo::add_break
virtual void add_break(unsigned long num_breaks)
add a line break to the information
Definition: BESXMLInfo.cc:432
BESXMLInfo::print
virtual void print(std::ostream &strm)
print the information from this informational object to the specified stream
Definition: BESXMLInfo.cc:495
BESDataHandlerInterface::data
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
Definition: BESDataHandlerInterface.h:90
BESXMLInfo::transmit
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &dhi)
transmit the text information as text
Definition: BESXMLInfo.cc:482
BESInternalError
exception thrown if internal error encountered
Definition: BESInternalError.h:43
BESXMLInfo::add_space
virtual void add_space(unsigned long num_spaces)
add a space to the informational response
Definition: BESXMLInfo.cc:419
BESTransmitter
Definition: BESTransmitter.h:47
BESInfo::add_data
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
BESXMLInfo::begin_response
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESXMLInfo.cc:96
BESXMLInfo::begin_tag
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
BESInfo::dump
virtual void dump(std::ostream &strm) const
Displays debug information about this object.
Definition: BESInfo.cc:275
BESInfo::begin_response
virtual void begin_response(const std::string &response_name, BESDataHandlerInterface &dhi)
begin the informational response
Definition: BESInfo.cc:124
BESDataHandlerInterface
Structure storing information used by the BES to handle the request.
Definition: BESDataHandlerInterface.h:56
BESXMLInfo::add_data_from_file
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