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     rc = xmlTextWriterSetIndent( _writer, 4 ) ;
00137     if( rc < 0 )
00138     {
00139         cleanup() ;
00140         string err = (string)"Error starting indentation for response document "
00141                      + _response_name ;
00142         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00143     }
00144 
00145     rc = xmlTextWriterSetIndentString( _writer, BAD_CAST "    " ) ;
00146     if( rc < 0 )
00147     {
00148         cleanup() ;
00149         string err = (string)"Error setting indentation for response document "
00150                      + _response_name ;
00151         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00152     }
00153 
00154     _started = true ;
00155 
00156     /* Start the document with the xml default for the version,
00157      * encoding ISO 8859-1 and the default for the standalone
00158      * declaration. MY_ENCODING defined at top of this file*/
00159     rc = xmlTextWriterStartDocument( _writer, NULL, MY_ENCODING, NULL ) ;
00160     if( rc < 0 )
00161     {
00162         cleanup() ;
00163         string err = (string)"Error starting xml response document for "
00164                      + _response_name ;
00165         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00166     }
00167 
00168     /* Start an element named "response". Since this is the first element,
00169      * this will be the root element of the document */
00170     rc = xmlTextWriterStartElementNS( _writer, NULL,
00171                                       BAD_CAST "response",
00172                                       BAD_CAST BES_SCHEMA ) ;
00173     if( rc < 0 )
00174     {
00175         cleanup() ;
00176         string err = (string)"Error starting the response element for response "
00177                      + _response_name ;
00178         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00179     }
00180 
00181     /* Add the request id attribute */
00182     string reqid = dhi.data[REQUEST_ID] ;
00183     if( !reqid.empty() )
00184     {
00185         rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST REQUEST_ID,
00186                                           BAD_CAST reqid.c_str() ) ;
00187         if( rc < 0 )
00188         {
00189             cleanup() ;
00190             string err = (string)"Error adding attribute " + REQUEST_ID
00191                          + " for response " + _response_name ;
00192             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00193         }
00194     }
00195 
00196     /* Start an element for the specific response. */
00197     rc = xmlTextWriterStartElement( _writer, BAD_CAST _response_name.c_str() ) ;
00198     if( rc < 0 )
00199     {
00200         cleanup() ;
00201         string err = (string)"Error creating root element for response "
00202                      + _response_name ;
00203         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00204     }
00205 }
00206 
00214 void
00215 BESXMLInfo::end_response()
00216 {
00217     BESInfo::end_response() ;
00218 
00219     int rc = 0 ;
00220 
00221     // this should end the response element
00222     rc = xmlTextWriterEndElement( _writer ) ;
00223     if( rc < 0 )
00224     {
00225         cleanup() ;
00226         string err = (string)"Error ending response element for response "
00227                      + _response_name ;
00228         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00229     }
00230 
00231     // this should end the specific response element, like showVersion
00232     rc = xmlTextWriterEndElement( _writer ) ;
00233     if( rc < 0 )
00234     {
00235         cleanup() ;
00236         string err = (string)"Error ending specific response element "
00237                      + "for response " + _response_name ; 
00238         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00239     }
00240 
00241     rc = xmlTextWriterEndDocument( _writer ) ;
00242     if( rc < 0 )
00243     {
00244         cleanup() ;
00245         string err = (string)"Error ending the response document for response "
00246                      + _response_name ;
00247         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00248     }
00249 
00250     // must call this before getting the buffer content
00251     xmlFreeTextWriter( _writer ) ;
00252     _writer = 0 ;
00253 
00254     // get the xml document as a string and return
00255     if( !_doc_buf->content )
00256     {
00257         cleanup() ;
00258         string err = (string)"Error retrieving response document as string "
00259                      + "for response " + _response_name ;
00260         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00261     }
00262     else
00263     {
00264         _doc = (char *)_doc_buf->content ;
00265     }
00266 
00267     _ended = true ;
00268 
00269     cleanup() ;
00270 }
00271 
00278 void
00279 BESXMLInfo::add_tag( const string &tag_name,
00280                      const string &tag_data,
00281                      map<string,string> *attrs )
00282 {
00283     /* Start an element named tag_name. */
00284     int rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str() ) ;
00285     if( rc < 0 )
00286     {
00287         cleanup() ;
00288         string err = (string)"Error starting element " + tag_name
00289                      + " for response " + _response_name ;
00290         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00291     }
00292 
00293     if( attrs )
00294     {
00295         map<string,string>::const_iterator i = attrs->begin() ;
00296         map<string,string>::const_iterator e = attrs->end() ;
00297         for( ; i != e; i++ )
00298         {
00299             string name = (*i).first ;
00300             string val = (*i).second ;
00301 
00302             // FIXME: is there one with no value?
00303             /* Add the attributes */
00304             rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
00305                                               BAD_CAST val.c_str() ) ;
00306             if( rc < 0 )
00307             {
00308                 cleanup() ;
00309                 string err = (string)"Error adding attribute " + name
00310                              + " for response " + _response_name ;
00311                 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00312             }
00313         }
00314     }
00315 
00316     /* Write the value of the element */
00317     if( !tag_data.empty() )
00318     {
00319         rc = xmlTextWriterWriteString( _writer, BAD_CAST tag_data.c_str() ) ;
00320         if( rc < 0 )
00321         {
00322             cleanup() ;
00323             string err = (string)"Error writing the value for element "
00324                          + tag_name + " for response " + _response_name ;
00325             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00326         }
00327     }
00328 
00329     // this should end the tag_name element
00330     rc = xmlTextWriterEndElement( _writer ) ;
00331     if( rc < 0 )
00332     {
00333         cleanup() ;
00334         string err = (string)"Error ending element " + tag_name
00335                      + " for response " + _response_name ;
00336         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00337     }
00338 }
00339 
00345 void
00346 BESXMLInfo::begin_tag( const string &tag_name,
00347                        map<string,string> *attrs )
00348 {
00349     begin_tag( tag_name, "", "", attrs ) ;
00350 }
00351 
00359 void
00360 BESXMLInfo::begin_tag( const string &tag_name,
00361                        const string &ns,
00362                        const string &uri,
00363                        map<string,string> *attrs )
00364 {
00365     BESInfo::begin_tag( tag_name ) ;
00366 
00367     /* Start an element named tag_name. */
00368     int rc = 0 ;
00369     if( ns.empty() && uri.empty() )
00370     {
00371         rc = xmlTextWriterStartElement( _writer, BAD_CAST tag_name.c_str());
00372         if( rc < 0 )
00373         {
00374             cleanup() ;
00375             string err = (string)"Error starting element " + tag_name
00376                          + " for response " + _response_name ;
00377             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00378         }
00379     }
00380     else
00381     {
00382         const char *cns = NULL ;
00383         if( !ns.empty() ) cns = ns.c_str() ;
00384         rc = xmlTextWriterStartElementNS( _writer,
00385                                           BAD_CAST cns,
00386                                           BAD_CAST tag_name.c_str(),
00387                                           BAD_CAST uri.c_str() ) ;
00388         if( rc < 0 )
00389         {
00390             cleanup() ;
00391             string err = (string)"Error starting element " + tag_name
00392                          + " for response " + _response_name ;
00393             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00394         }
00395     }
00396 
00397     if( attrs )
00398     {
00399         map<string,string>::const_iterator i = attrs->begin() ;
00400         map<string,string>::const_iterator e = attrs->end() ;
00401         for( ; i != e; i++ )
00402         {
00403             string name = (*i).first ;
00404             string val = (*i).second ;
00405 
00406             /* Add the attributes */
00407             rc = xmlTextWriterWriteAttribute( _writer, BAD_CAST name.c_str(),
00408                                               BAD_CAST val.c_str() ) ;
00409             if( rc < 0 )
00410             {
00411                 cleanup() ;
00412                 string err = (string)"Error adding attribute " + name
00413                              + " for response " + _response_name ;
00414                 throw BESInternalError( err, __FILE__, __LINE__ ) ;
00415             }
00416         }
00417     }
00418 }
00419 
00426 void
00427 BESXMLInfo::end_tag( const string &tag_name )
00428 {
00429     BESInfo::end_tag( tag_name ) ;
00430 
00431     int rc = 0 ;
00432 
00433     string s = ((ostringstream *)_strm)->str() ;
00434     if( !s.empty() )
00435     {
00436         /* Write the value of the element */
00437         rc = xmlTextWriterWriteString( _writer, BAD_CAST s.c_str() ) ;
00438         if( rc < 0 )
00439         {
00440             cleanup() ;
00441             string err = (string)"Error writing the value for element "
00442                          + tag_name + " for response " + _response_name ;
00443             throw BESInternalError( err, __FILE__, __LINE__ ) ;
00444         }
00445 
00446         ((ostringstream *)_strm)->str( "" ) ;
00447     }
00448 
00449     // this should end the tag_name element
00450     rc = xmlTextWriterEndElement( _writer ) ;
00451     if( rc < 0 )
00452     {
00453         cleanup() ;
00454         string err = (string)"Error ending element " + tag_name
00455                      + " for response " + _response_name ;
00456         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00457     }
00458 }
00459 
00464 void
00465 BESXMLInfo::add_space( unsigned long num_spaces )
00466 {
00467     string to_add ;
00468     for( unsigned long i = 0; i < num_spaces; i++ )
00469     {
00470         to_add += " " ;
00471     }
00472     BESInfo::add_data( to_add ) ;
00473 }
00474 
00479 void
00480 BESXMLInfo::add_break( unsigned long num_breaks )
00481 {
00482     string to_add ;
00483     for( unsigned long i = 0; i < num_breaks; i++ )
00484     {
00485         to_add += "\n" ;
00486     }
00487     BESInfo::add_data( to_add ) ;
00488 }
00489 
00490 void
00491 BESXMLInfo::add_data( const string &s )
00492 {
00493     BESInfo::add_data( s ) ;
00494 }
00495 
00504 void
00505 BESXMLInfo::add_data_from_file( const string &key, const string &name )
00506 {
00507     // just add the html file with the <html ... wrapper around it
00508     // <html xmlns="http://www.w3.org/1999/xhtml">
00509     begin_tag( "html", "", "http://www.w3.org/1999/xhtml" ) ;
00510 
00511     string newkey = key + ".HTML" ;
00512     BESInfo::add_data_from_file( newkey, name ) ;
00513 
00514     end_tag( "html" ) ;
00515 }
00516 
00525 void
00526 BESXMLInfo::transmit( BESTransmitter *transmitter,
00527                       BESDataHandlerInterface &dhi )
00528 {
00529     if( _started && !_ended )
00530     {
00531         end_response() ;
00532     }
00533     transmitter->send_text( *this, dhi ) ;
00534 }
00535 
00541 void
00542 BESXMLInfo::print( ostream &strm )
00543 {
00544     if( _started && !_ended )
00545     {
00546         end_response() ;
00547     }
00548     strm << _doc ;
00549 }
00550 
00558 void
00559 BESXMLInfo::dump( ostream &strm ) const
00560 {
00561     strm << BESIndent::LMarg << "BESXMLInfo::dump - ("
00562                              << (void *)this << ")" << endl ;
00563     BESIndent::Indent() ;
00564     BESInfo::dump( strm ) ;
00565     BESIndent::UnIndent() ;
00566 }
00567 
00568 BESInfo *
00569 BESXMLInfo::BuildXMLInfo( const string &info_type )
00570 {
00571     return new BESXMLInfo( ) ;
00572 }
00573 
Generated by  doxygen 1.6.2-20100208