OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESXMLInfo.cc
Go to the documentation of this file.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 #ifdef __GNUG__
34 #pragma implementation
35 #endif
36 
37 #include <sstream>
38 
39 using std::ostringstream ;
40 
41 #include "BESXMLInfo.h"
42 #include "BESUtil.h"
43 #include "BESDataNames.h"
44 
45 #define MY_ENCODING "ISO-8859-1"
46 #define BES_SCHEMA "http://xml.opendap.org/ns/bes/1.0#"
47 
54  : BESInfo( ),
55  _writer( 0 ),
56  _doc_buf( 0 ),
57  _started( false ),
58  _ended( false )
59 {
60 }
61 
63 {
64  cleanup() ;
65 }
66 
67 void
68 BESXMLInfo::cleanup()
69 {
70  // make sure the buffer and writer are all cleaned up
71  if( _writer )
72  {
73  xmlFreeTextWriter( _writer ) ;
74  _writer = 0 ;
75  _doc_buf = 0 ;
76  }
77  if( _doc_buf )
78  {
79  xmlBufferFree( _doc_buf ) ;
80  _doc_buf = 0 ;
81  }
82 
83  // this always seems to be causing a memory fault
84  // xmlCleanupParser();
85 
86  _started = false ;
87  _ended = false ;
88  if( _strm )
89  {
90  ((ostringstream *)_strm)->str( "" ) ;
91  }
92 }
93 
102 void
103 BESXMLInfo::begin_response( const string &response_name,
105 {
106  BESInfo::begin_response( response_name, dhi ) ;
107 
108  _response_name = response_name ;
109 
110  LIBXML_TEST_VERSION
111 
112  int rc = 0 ;
113 
114  /* Create a new XML buffer, to which the XML document will be
115  * written */
116  _doc_buf = xmlBufferCreate() ;
117  if( _doc_buf == NULL )
118  {
119  cleanup() ;
120  string err = (string)"Error creating the xml buffer for response "
121  + _response_name ;
122  throw BESInternalError( err, __FILE__, __LINE__ ) ;
123  }
124 
125  /* Create a new XmlWriter for memory, with no compression.
126  * Remark: there is no compression for this kind of xmlTextWriter */
127  _writer = xmlNewTextWriterMemory( _doc_buf, 0 ) ;
128  if( _writer == NULL )
129  {
130  cleanup() ;
131  string err = (string)"Error creating the xml writer for response "
132  + _response_name ;
133  throw BESInternalError( err, __FILE__, __LINE__ ) ;
134  }
135 
136  rc = xmlTextWriterSetIndent( _writer, 4 ) ;
137  if( rc < 0 )
138  {
139  cleanup() ;
140  string err = (string)"Error starting indentation for response document "
141  + _response_name ;
142  throw BESInternalError( err, __FILE__, __LINE__ ) ;
143  }
144 
145  rc = xmlTextWriterSetIndentString( _writer, BAD_CAST " " ) ;
146  if( rc < 0 )
147  {
148  cleanup() ;
149  string err = (string)"Error setting indentation for response document "
150  + _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  {
162  cleanup() ;
163  string err = (string)"Error starting xml response document for "
164  + _response_name ;
165  throw BESInternalError( err, __FILE__, __LINE__ ) ;
166  }
167 
168  /* Start an element named "response". Since this is the first element,
169  * this will be the root element of the document */
170  rc = xmlTextWriterStartElementNS( _writer, NULL,
171  BAD_CAST "response",
172  BAD_CAST BES_SCHEMA ) ;
173  if( rc < 0 )
174  {
175  cleanup() ;
176  string err = (string)"Error starting the response element for response "
177  + _response_name ;
178  throw BESInternalError( err, __FILE__, __LINE__ ) ;
179  }
180 
181  /* Add the request id attribute */
182  string reqid = dhi.data[REQUEST_ID] ;
183  if( !reqid.empty() )
184  {
185  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID,
186  BAD_CAST reqid.c_str() ) ;
187  if( rc < 0 )
188  {
189  cleanup() ;
190  string err = (string)"Error adding attribute " + REQUEST_ID
191  + " for response " + _response_name ;
192  throw BESInternalError( err, __FILE__, __LINE__ ) ;
193  }
194  }
195 
196  /* Start an element for the specific response. */
197  rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() ) ;
198  if( rc < 0 )
199  {
200  cleanup() ;
201  string err = (string)"Error creating root element for response "
202  + _response_name ;
203  throw BESInternalError( err, __FILE__, __LINE__ ) ;
204  }
205 }
206 
214 void
216 {
218 
219  int rc = 0 ;
220 
221  // this should end the response element
222  rc = xmlTextWriterEndElement( _writer ) ;
223  if( rc < 0 )
224  {
225  cleanup() ;
226  string err = (string)"Error ending response element for response "
227  + _response_name ;
228  throw BESInternalError( err, __FILE__, __LINE__ ) ;
229  }
230 
231  // this should end the specific response element, like showVersion
232  rc = xmlTextWriterEndElement( _writer ) ;
233  if( rc < 0 )
234  {
235  cleanup() ;
236  string err = (string)"Error ending specific response element "
237  + "for response " + _response_name ;
238  throw BESInternalError( err, __FILE__, __LINE__ ) ;
239  }
240 
241  rc = xmlTextWriterEndDocument( _writer ) ;
242  if( rc < 0 )
243  {
244  cleanup() ;
245  string err = (string)"Error ending the response document for response "
246  + _response_name ;
247  throw BESInternalError( err, __FILE__, __LINE__ ) ;
248  }
249 
250  // must call this before getting the buffer content
251  xmlFreeTextWriter( _writer ) ;
252  _writer = 0 ;
253 
254  // get the xml document as a string and return
255  if( !_doc_buf->content )
256  {
257  cleanup() ;
258  string err = (string)"Error retrieving response document as string "
259  + "for response " + _response_name ;
260  throw BESInternalError( err, __FILE__, __LINE__ ) ;
261  }
262  else
263  {
264  _doc = (char *)_doc_buf->content ;
265  }
266 
267  _ended = true ;
268 
269  cleanup() ;
270 }
271 
278 void
279 BESXMLInfo::add_tag( const string &tag_name,
280  const string &tag_data,
281  map<string,string> *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  {
287  cleanup() ;
288  string err = (string)"Error starting element " + tag_name
289  + " for response " + _response_name ;
290  throw BESInternalError( err, __FILE__, __LINE__ ) ;
291  }
292 
293  if( attrs )
294  {
295  map<string,string>::const_iterator i = attrs->begin() ;
296  map<string,string>::const_iterator e = attrs->end() ;
297  for( ; i != e; i++ )
298  {
299  string name = (*i).first ;
300  string val = (*i).second ;
301 
302  // FIXME: is there one with no value?
303  /* Add the attributes */
304  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
305  BAD_CAST val.c_str() ) ;
306  if( rc < 0 )
307  {
308  cleanup() ;
309  string err = (string)"Error adding attribute " + name
310  + " for response " + _response_name ;
311  throw BESInternalError( err, __FILE__, __LINE__ ) ;
312  }
313  }
314  }
315 
316  /* Write the value of the element */
317  if( !tag_data.empty() )
318  {
319  rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() ) ;
320  if( rc < 0 )
321  {
322  cleanup() ;
323  string err = (string)"Error writing the value for element "
324  + tag_name + " for response " + _response_name ;
325  throw BESInternalError( err, __FILE__, __LINE__ ) ;
326  }
327  }
328 
329  // this should end the tag_name element
330  rc = xmlTextWriterEndElement( _writer ) ;
331  if( rc < 0 )
332  {
333  cleanup() ;
334  string err = (string)"Error ending element " + tag_name
335  + " for response " + _response_name ;
336  throw BESInternalError( err, __FILE__, __LINE__ ) ;
337  }
338 }
339 
345 void
346 BESXMLInfo::begin_tag( const string &tag_name,
347  map<string,string> *attrs )
348 {
349  begin_tag( tag_name, "", "", attrs ) ;
350 }
351 
359 void
360 BESXMLInfo::begin_tag( const string &tag_name,
361  const string &ns,
362  const string &uri,
363  map<string,string> *attrs )
364 {
365  BESInfo::begin_tag( tag_name ) ;
366 
367  /* Start an element named tag_name. */
368  int rc = 0 ;
369  if( ns.empty() && uri.empty() )
370  {
371  rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
372  if( rc < 0 )
373  {
374  cleanup() ;
375  string err = (string)"Error starting element " + tag_name
376  + " for response " + _response_name ;
377  throw BESInternalError( err, __FILE__, __LINE__ ) ;
378  }
379  }
380  else
381  {
382  const char *cns = NULL ;
383  if( !ns.empty() ) cns = ns.c_str() ;
384  rc = xmlTextWriterStartElementNS( _writer,
385  BAD_CAST cns,
386  BAD_CAST tag_name.c_str(),
387  BAD_CAST uri.c_str() ) ;
388  if( rc < 0 )
389  {
390  cleanup() ;
391  string err = (string)"Error starting element " + tag_name
392  + " for response " + _response_name ;
393  throw BESInternalError( err, __FILE__, __LINE__ ) ;
394  }
395  }
396 
397  if( attrs )
398  {
399  map<string,string>::const_iterator i = attrs->begin() ;
400  map<string,string>::const_iterator e = attrs->end() ;
401  for( ; i != e; i++ )
402  {
403  string name = (*i).first ;
404  string val = (*i).second ;
405 
406  /* Add the attributes */
407  rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
408  BAD_CAST val.c_str() ) ;
409  if( rc < 0 )
410  {
411  cleanup() ;
412  string err = (string)"Error adding attribute " + name
413  + " for response " + _response_name ;
414  throw BESInternalError( err, __FILE__, __LINE__ ) ;
415  }
416  }
417  }
418 }
419 
426 void
427 BESXMLInfo::end_tag( const string &tag_name )
428 {
429  BESInfo::end_tag( tag_name ) ;
430 
431  int rc = 0 ;
432 
433  string s = ((ostringstream *)_strm)->str() ;
434  if( !s.empty() )
435  {
436  /* Write the value of the element */
437  rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() ) ;
438  if( rc < 0 )
439  {
440  cleanup() ;
441  string err = (string)"Error writing the value for element "
442  + tag_name + " for response " + _response_name ;
443  throw BESInternalError( err, __FILE__, __LINE__ ) ;
444  }
445 
446  ((ostringstream *)_strm)->str( "" ) ;
447  }
448 
449  // this should end the tag_name element
450  rc = xmlTextWriterEndElement( _writer ) ;
451  if( rc < 0 )
452  {
453  cleanup() ;
454  string err = (string)"Error ending element " + tag_name
455  + " for response " + _response_name ;
456  throw BESInternalError( err, __FILE__, __LINE__ ) ;
457  }
458 }
459 
464 void
465 BESXMLInfo::add_space( unsigned long num_spaces )
466 {
467  string to_add ;
468  for( unsigned long i = 0; i < num_spaces; i++ )
469  {
470  to_add += " " ;
471  }
472  BESInfo::add_data( to_add ) ;
473 }
474 
479 void
480 BESXMLInfo::add_break( unsigned long num_breaks )
481 {
482  string to_add ;
483  for( unsigned long i = 0; i < num_breaks; i++ )
484  {
485  to_add += "\n" ;
486  }
487  BESInfo::add_data( to_add ) ;
488 }
489 
490 void
491 BESXMLInfo::add_data( const string &s )
492 {
493  BESInfo::add_data( s ) ;
494 }
495 
504 void
505 BESXMLInfo::add_data_from_file( const string &key, const string &name )
506 {
507  // just add the html file with the <html ... wrapper around it
508  // <html xmlns="http://www.w3.org/1999/xhtml">
509  begin_tag( "html", "", "http://www.w3.org/1999/xhtml" ) ;
510 
511  string newkey = key + ".HTML" ;
512  BESInfo::add_data_from_file( newkey, name ) ;
513 
514  end_tag( "html" ) ;
515 }
516 
525 void
528 {
529  if( _started && !_ended )
530  {
531  end_response() ;
532  }
533  transmitter->send_text( *this, dhi ) ;
534 }
535 
541 void
542 BESXMLInfo::print( ostream &strm )
543 {
544  if( _started && !_ended )
545  {
546  end_response() ;
547  }
548  strm << _doc ;
549 }
550 
558 void
559 BESXMLInfo::dump( ostream &strm ) const
560 {
561  strm << BESIndent::LMarg << "BESXMLInfo::dump - ("
562  << (void *)this << ")" << endl ;
564  BESInfo::dump( strm ) ;
566 }
567 
568 BESInfo *
569 BESXMLInfo::BuildXMLInfo( const string &info_type )
570 {
571  return new BESXMLInfo( ) ;
572 }
573