OPeNDAP Hyrax Back End Server (BES)
Updated for version 3.8.3
|
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