BESXMLInfo.cc

Go to the documentation of this file.
00001 // BESXMLInfo.cc
00002 
00003 // This file is part of bes, A C++ back-end server implementation framework
00004 // for the OPeNDAP Data Access Protocol.
00005 
00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 // 
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 // 
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact University Corporation for Atmospheric Research at
00024 // 3080 Center Green Drive, Boulder, CO 80301
00025  
00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
00028 //
00029 // Authors:
00030 //      pwest       Patrick West <pwest@ucar.edu>
00031 //      jgarcia     Jose Garcia <jgarcia@ucar.edu>
00032 
00033 #ifdef __GNUG__
00034 #pragma implementation
00035 #endif
00036 
00037 #include <sstream>
00038 
00039 using std::ostringstream ;
00040 
00041 #include "BESXMLInfo.h"
00042 #include "BESUtil.h"
00043 #include "BESDataNames.h"
00044 
00045 #define MY_ENCODING "ISO-8859-1"
00046 #define BES_SCHEMA "http://xml.opendap.org/ns/bes/1.0#"
00047 
00053 BESXMLInfo::BESXMLInfo( )
00054     : BESInfo( ),
00055       _writer( 0 ),
00056       _doc_buf( 0 ),
00057       _started( false ),
00058       _ended( false )
00059 {
00060 }
00061 
00062 BESXMLInfo::~BESXMLInfo()
00063 {
00064     cleanup() ;
00065 }
00066 
00067 void
00068 BESXMLInfo::cleanup()
00069 {
00070     // make sure the buffer and writer are all cleaned up
00071     if( _writer )
00072     {
00073         xmlFreeTextWriter( _writer ) ;
00074         _writer = 0 ;
00075         _doc_buf = 0 ;
00076     }
00077     if( _doc_buf )
00078     {
00079         xmlBufferFree( _doc_buf ) ;
00080         _doc_buf = 0 ;
00081     }
00082 
00083     // this always seems to be causing a memory fault
00084     // xmlCleanupParser();
00085 
00086     _started = false ;
00087     _ended = false ;
00088     if( _strm )
00089     {
00090         ((ostringstream *)_strm)->str( "" ) ;
00091     }
00092 }
00093 
00102 void
00103 BESXMLInfo::begin_response( const string &response_name,
00104                             BESDataHandlerInterface &dhi )
00105 {
00106     BESInfo::begin_response( response_name, dhi ) ;
00107 
00108     _response_name = response_name ;
00109 
00110     LIBXML_TEST_VERSION
00111 
00112     int rc = 0 ;
00113 
00114     /* Create a new XML buffer, to which the XML document will be
00115      * written */
00116     _doc_buf = xmlBufferCreate() ;
00117     if( _doc_buf == NULL )
00118     {
00119         cleanup() ;
00120         string err = (string)"Error creating the xml buffer for response "
00121                      + _response_name ;
00122         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00123     }
00124 
00125     /* Create a new XmlWriter for memory, with no compression.
00126      * Remark: there is no compression for this kind of xmlTextWriter */
00127     _writer = xmlNewTextWriterMemory( _doc_buf, 0 ) ;
00128     if( _writer == NULL )
00129     {
00130         cleanup() ;
00131         string err = (string)"Error creating the xml writer for response "
00132                      + _response_name ;
00133         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00134     }
00135 
00136     _started = true ;
00137 
00138     /* Start the document with the xml default for the version,
00139      * encoding ISO 8859-1 and the default for the standalone
00140      * declaration. MY_ENCODING defined at top of this file*/
00141     rc = xmlTextWriterStartDocument( _writer, NULL, MY_ENCODING, NULL ) ;
00142     if( rc < 0 )
00143     {
00144         cleanup() ;
00145         string err = (string)"Error starting xml response document for "
00146                      + _response_name ;
00147         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00148     }
00149 
00150     /* Start an element named "response". Since this is the first element,
00151      * this will be the root element of the document */
00152     rc = xmlTextWriterStartElementNS( _writer, NULL,
00153                                       BAD_CAST "response",
00154                                       BAD_CAST BES_SCHEMA ) ;
00155     if( rc < 0 )
00156     {
00157         cleanup() ;
00158         string err = (string)"Error starting the response element for response "
00159                      + _response_name ;
00160         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00161     }
00162 
00163     /* Add the request id attribute */
00164     string reqid = dhi.data[REQUEST_ID] ;
00165     if( !reqid.empty() )
00166     {
00167         rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID,
00168                                           BAD_CAST reqid.c_str() ) ;
00169         if( rc < 0 )
00170         {
00171             cleanup() ;
00172             string err = (string)"Error adding attribute " + REQUEST_ID
00173                          + " for response " + _response_name ;
00174             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00175         }
00176     }
00177 
00178     /* Start an element for the specific response. */
00179     rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() ) ;
00180     if( rc < 0 )
00181     {
00182         cleanup() ;
00183         string err = (string)"Error creating root element for response "
00184                      + _response_name ;
00185         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00186     }
00187 }
00188 
00196 void
00197 BESXMLInfo::end_response()
00198 {
00199     BESInfo::end_response() ;
00200 
00201     int rc = 0 ;
00202 
00203     // this should end the response element
00204     rc = xmlTextWriterEndElement( _writer ) ;
00205     if( rc < 0 )
00206     {
00207         cleanup() ;
00208         string err = (string)"Error ending response element for response "
00209                      + _response_name ;
00210         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00211     }
00212 
00213     // this should end the specific response element, like showVersion
00214     rc = xmlTextWriterEndElement( _writer ) ;
00215     if( rc < 0 )
00216     {
00217         cleanup() ;
00218         string err = (string)"Error ending specific response element "
00219                      + "for response " + _response_name ; 
00220         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00221     }
00222 
00223     rc = xmlTextWriterEndDocument( _writer ) ;
00224     if( rc < 0 )
00225     {
00226         cleanup() ;
00227         string err = (string)"Error ending the response document for response "
00228                      + _response_name ;
00229         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00230     }
00231 
00232     // must call this before getting the buffer content
00233     xmlFreeTextWriter( _writer ) ;
00234     _writer = 0 ;
00235 
00236     // get the xml document as a string and return
00237     if( !_doc_buf->content )
00238     {
00239         cleanup() ;
00240         string err = (string)"Error retrieving response document as string "
00241                      + "for response " + _response_name ;
00242         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00243     }
00244     else
00245     {
00246         _doc = (char *)_doc_buf->content ;
00247     }
00248 
00249     _ended = true ;
00250 
00251     cleanup() ;
00252 }
00253 
00260 void
00261 BESXMLInfo::add_tag( const string &tag_name,
00262                      const string &tag_data,
00263                      map<string,string> *attrs )
00264 {
00265     /* Start an element named tag_name. */
00266     int rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str() ) ;
00267     if( rc < 0 )
00268     {
00269         cleanup() ;
00270         string err = (string)"Error starting element " + tag_name
00271                      + " for response " + _response_name ;
00272         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00273     }
00274 
00275     if( attrs )
00276     {
00277         map<string,string>::const_iterator i = attrs->begin() ;
00278         map<string,string>::const_iterator e = attrs->end() ;
00279         for( ; i != e; i++ )
00280         {
00281             string name = (*i).first ;
00282             string val = (*i).second ;
00283 
00284             // FIXME: is there one with no value?
00285             /* Add the attributes */
00286             rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
00287                                               BAD_CAST val.c_str() ) ;
00288             if( rc < 0 )
00289             {
00290                 cleanup() ;
00291                 string err = (string)"Error adding attribute " + name
00292                              + " for response " + _response_name ;
00293                 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00294             }
00295         }
00296     }
00297 
00298     /* Write the value of the element */
00299     if( !tag_data.empty() )
00300     {
00301         rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() ) ;
00302         if( rc < 0 )
00303         {
00304             cleanup() ;
00305             string err = (string)"Error writing the value for element "
00306                          + tag_name + " for response " + _response_name ;
00307             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00308         }
00309     }
00310 
00311     // this should end the tag_name element
00312     rc = xmlTextWriterEndElement( _writer ) ;
00313     if( rc < 0 )
00314     {
00315         cleanup() ;
00316         string err = (string)"Error ending element " + tag_name
00317                      + " for response " + _response_name ;
00318         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00319     }
00320 }
00321 
00327 void
00328 BESXMLInfo::begin_tag( const string &tag_name,
00329                        map<string,string> *attrs )
00330 {
00331     begin_tag( tag_name, "", "", attrs ) ;
00332 }
00333 
00341 void
00342 BESXMLInfo::begin_tag( const string &tag_name,
00343                        const string &ns,
00344                        const string &uri,
00345                        map<string,string> *attrs )
00346 {
00347     BESInfo::begin_tag( tag_name ) ;
00348 
00349     /* Start an element named tag_name. */
00350     int rc = 0 ;
00351     if( ns.empty() && uri.empty() )
00352     {
00353         rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
00354         if( rc < 0 )
00355         {
00356             cleanup() ;
00357             string err = (string)"Error starting element " + tag_name
00358                          + " for response " + _response_name ;
00359             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00360         }
00361     }
00362     else
00363     {
00364         const char *cns = NULL ;
00365         if( !ns.empty() ) cns = ns.c_str() ;
00366         rc = xmlTextWriterStartElementNS( _writer,
00367                                           BAD_CAST cns,
00368                                           BAD_CAST tag_name.c_str(),
00369                                           BAD_CAST uri.c_str() ) ;
00370         if( rc < 0 )
00371         {
00372             cleanup() ;
00373             string err = (string)"Error starting element " + tag_name
00374                          + " for response " + _response_name ;
00375             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00376         }
00377     }
00378 
00379     if( attrs )
00380     {
00381         map<string,string>::const_iterator i = attrs->begin() ;
00382         map<string,string>::const_iterator e = attrs->end() ;
00383         for( ; i != e; i++ )
00384         {
00385             string name = (*i).first ;
00386             string val = (*i).second ;
00387 
00388             /* Add the attributes */
00389             rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
00390                                               BAD_CAST val.c_str() ) ;
00391             if( rc < 0 )
00392             {
00393                 cleanup() ;
00394                 string err = (string)"Error adding attribute " + name
00395                              + " for response " + _response_name ;
00396                 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00397             }
00398         }
00399     }
00400 }
00401 
00408 void
00409 BESXMLInfo::end_tag( const string &tag_name )
00410 {
00411     BESInfo::end_tag( tag_name ) ;
00412 
00413     int rc = 0 ;
00414 
00415     string s = ((ostringstream *)_strm)->str() ;
00416     if( !s.empty() )
00417     {
00418         /* Write the value of the element */
00419         rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() ) ;
00420         if( rc < 0 )
00421         {
00422             cleanup() ;
00423             string err = (string)"Error writing the value for element "
00424                          + tag_name + " for response " + _response_name ;
00425             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00426         }
00427 
00428         ((ostringstream *)_strm)->str( "" ) ;
00429     }
00430 
00431     // this should end the tag_name element
00432     rc = xmlTextWriterEndElement( _writer ) ;
00433     if( rc < 0 )
00434     {
00435         cleanup() ;
00436         string err = (string)"Error ending element " + tag_name
00437                      + " for response " + _response_name ;
00438         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00439     }
00440 }
00441 
00446 void
00447 BESXMLInfo::add_space( unsigned long num_spaces )
00448 {
00449     string to_add ;
00450     for( unsigned long i = 0; i < num_spaces; i++ )
00451     {
00452         to_add += " " ;
00453     }
00454     BESInfo::add_data( to_add ) ;
00455 }
00456 
00461 void
00462 BESXMLInfo::add_break( unsigned long num_breaks )
00463 {
00464     string to_add ;
00465     for( unsigned long i = 0; i < num_breaks; i++ )
00466     {
00467         to_add += "\n" ;
00468     }
00469     BESInfo::add_data( to_add ) ;
00470 }
00471 
00472 void
00473 BESXMLInfo::add_data( const string &s )
00474 {
00475     BESInfo::add_data( s ) ;
00476 }
00477 
00486 void
00487 BESXMLInfo::add_data_from_file( const string &key, const string &name )
00488 {
00489     // just add the html file with the <html ... wrapper around it
00490     // <html xmlns="http://www.w3.org/1999/xhtml">
00491     begin_tag( "html", "", "http://www.w3.org/1999/xhtml" ) ;
00492 
00493     string newkey = key + ".HTML" ;
00494     BESInfo::add_data_from_file( newkey, name ) ;
00495 
00496     end_tag( "html" ) ;
00497 }
00498 
00507 void
00508 BESXMLInfo::transmit( BESTransmitter *transmitter,
00509                       BESDataHandlerInterface &dhi )
00510 {
00511     if( _started && !_ended )
00512     {
00513         end_response() ;
00514     }
00515     transmitter->send_text( *this, dhi ) ;
00516 }
00517 
00523 void
00524 BESXMLInfo::print( ostream &strm )
00525 {
00526     if( _started && !_ended )
00527     {
00528         end_response() ;
00529     }
00530     strm << _doc ;
00531 }
00532 
00540 void
00541 BESXMLInfo::dump( ostream &strm ) const
00542 {
00543     strm << BESIndent::LMarg << "BESXMLInfo::dump - ("
00544                              << (void *)this << ")" << endl ;
00545     BESIndent::Indent() ;
00546     BESInfo::dump( strm ) ;
00547     BESIndent::UnIndent() ;
00548 }
00549 
00550 BESInfo *
00551 BESXMLInfo::BuildXMLInfo( const string &info_type )
00552 {
00553     return new BESXMLInfo( ) ;
00554 }
00555 

Generated on Tue May 11 20:02:06 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7