OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // BESXMLInterface.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 #include <iostream> 00034 #include <sstream> 00035 00036 using std::endl ; 00037 using std::cout ; 00038 using std::stringstream ; 00039 00040 #include "BESXMLInterface.h" 00041 #include "BESXMLCommand.h" 00042 #include "BESXMLUtils.h" 00043 #include "BESDataNames.h" 00044 #include "BESDebug.h" 00045 #include "BESLog.h" 00046 #include "BESSyntaxUserError.h" 00047 #include "BESReturnManager.h" 00048 00049 BESXMLInterface::BESXMLInterface( const string &xml_doc, ostream *strm ) 00050 : BESBasicInterface( strm ) 00051 { 00052 _dhi = &_base_dhi ; 00053 _dhi->data[DATA_REQUEST] = "xml document" ; 00054 _dhi->data["XMLDoc"] = xml_doc ; 00055 } 00056 00057 BESXMLInterface::~BESXMLInterface() 00058 { 00059 clean() ; 00060 } 00061 00062 int 00063 BESXMLInterface::execute_request( const string &from ) 00064 { 00065 return BESBasicInterface::execute_request( from ) ; 00066 } 00067 00070 void 00071 BESXMLInterface::initialize() 00072 { 00073 BESBasicInterface::initialize() ; 00074 } 00075 00078 void 00079 BESXMLInterface::validate_data_request() 00080 { 00081 BESBasicInterface::validate_data_request() ; 00082 } 00083 00086 void 00087 BESXMLInterface::build_data_request_plan() 00088 { 00089 BESDEBUG( "besxml", "building request plan for xml document: " 00090 << endl << _dhi->data["XMLDoc"] << endl ) ; 00091 if( BESLog::TheLog()->is_verbose() ) 00092 { 00093 *(BESLog::TheLog()) << _dhi->data[SERVER_PID] 00094 << " from " << _dhi->data[REQUEST_FROM] 00095 << "] building" << endl ; 00096 } 00097 00098 LIBXML_TEST_VERSION 00099 00100 xmlDoc *doc = NULL ; 00101 xmlNode *root_element = NULL ; 00102 xmlNode *current_node = NULL ; 00103 00104 try 00105 { 00106 // set the default error function to my own 00107 vector<string> parseerrors ; 00108 xmlSetGenericErrorFunc( (void *)&parseerrors, BESXMLUtils::XMLErrorFunc ); 00109 00110 doc = xmlParseDoc( (unsigned char *)_dhi->data["XMLDoc"].c_str() ) ; 00111 if( doc == NULL ) 00112 { 00113 string err = "Problem parsing the request xml document:\n" ; 00114 bool isfirst = true ; 00115 vector<string>::const_iterator i = parseerrors.begin() ; 00116 vector<string>::const_iterator e = parseerrors.end() ; 00117 for( ; i != e; i++ ) 00118 { 00119 if( !isfirst && (*i).compare( 0, 6, "Entity" ) == 0 ) 00120 { 00121 err += "\n" ; 00122 } 00123 err += (*i) ; 00124 isfirst = false ; 00125 } 00126 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00127 } 00128 00129 // get the root element and make sure it exists and is called request 00130 root_element = xmlDocGetRootElement( doc ) ; 00131 if( !root_element ) 00132 { 00133 string err = "There is no root element in the xml document" ; 00134 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00135 } 00136 00137 string root_name ; 00138 string root_val ; 00139 map< string, string> props ; 00140 BESXMLUtils::GetNodeInfo( root_element, root_name, root_val, props ) ; 00141 if( root_name != "request" ) 00142 { 00143 string err = (string)"The root element should be a request element, " 00144 + "name is " + (char *)root_element->name ; 00145 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00146 } 00147 if( root_val != "" ) 00148 { 00149 string err = (string)"The request element must not contain a value, " 00150 + root_val ; 00151 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00152 } 00153 00154 // there should be a request id property with one value. 00155 string &reqId = props[REQUEST_ID] ; 00156 if( reqId.empty() ) 00157 { 00158 string err = (string)"request id value empty" ; 00159 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00160 } 00161 _dhi->data[REQUEST_ID] = reqId ; 00162 BESDEBUG( "besxml", "request id = " << _dhi->data[REQUEST_ID] 00163 << endl ) ; 00164 00165 // iterate through the children of the request element. Each child is an 00166 // individual command. 00167 bool has_response = false ; 00168 current_node = root_element->children ; 00169 00170 while( current_node ) 00171 { 00172 if( current_node->type == XML_ELEMENT_NODE ) 00173 { 00174 // given the name of this node we should be able to find a 00175 // BESXMLCommand object 00176 string node_name = (char *)current_node->name ; 00177 BESDEBUG( "besxml", "looking for command " << node_name 00178 << endl ) ; 00179 p_xmlcmd_builder bldr = BESXMLCommand::find_command( node_name ) ; 00180 if( bldr ) 00181 { 00182 BESXMLCommand *current_cmd = bldr( _base_dhi ) ; 00183 if( !current_cmd ) 00184 { 00185 string err = (string)"Failed to build command object for " 00186 + node_name ; 00187 throw BESInternalError( err, __FILE__, __LINE__ ) ; 00188 } 00189 00190 // push this new command to the back of the list 00191 _cmd_list.push_back( current_cmd ) ; 00192 00193 // only one of the commands can build a response. If more 00194 // than one builds a response, throw an error 00195 bool cmd_has_response = current_cmd->has_response() ; 00196 if( has_response && cmd_has_response ) 00197 { 00198 string err = "Multiple responses not allowed" ; 00199 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00200 } 00201 has_response = cmd_has_response ; 00202 00203 // parse the request given the current node 00204 BESDEBUG( "besxml", "parse request using " << node_name 00205 << endl ) ; 00206 current_cmd->parse_request( current_node ) ; 00207 00208 BESDataHandlerInterface ¤t_dhi = current_cmd->get_dhi(); 00209 BESDEBUG( "besxml", node_name << " parsed request, dhi = " 00210 << current_dhi << endl ) ; 00211 string returnAs = current_dhi.data[RETURN_CMD] ; 00212 if( returnAs != "" ) 00213 { 00214 BESDEBUG( "xml", "Finding transmitter: " << returnAs 00215 << " ... " << endl ) ; 00216 BESTransmitter *transmitter = 00217 BESReturnManager::TheManager()->find_transmitter( returnAs ) ; 00218 if( !transmitter ) 00219 { 00220 string s = (string)"Unable to find transmitter " 00221 + returnAs ; 00222 throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ; 00223 } 00224 BESDEBUG( "xml", "OK" << endl ) ; 00225 } 00226 } 00227 else 00228 { 00229 string err = (string)"Unable to find command for " 00230 + node_name ; 00231 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ; 00232 } 00233 } 00234 current_node = current_node->next ; 00235 } 00236 } 00237 catch( BESError &e ) 00238 { 00239 xmlFreeDoc( doc ) ; 00240 throw e ; 00241 } 00242 00243 xmlFreeDoc( doc ) ; 00244 #if 0 00245 // Removed since the docs indicate it's not needed and it might be 00246 // contributing to memory issues flagged by valgrind. 2/25/09 jhrg 00247 xmlCleanupParser() ; 00248 #endif 00249 BESDEBUG( "besxml", "Done building request plan" << endl ) ; 00250 00251 BESBasicInterface::build_data_request_plan() ; 00252 } 00253 00256 void 00257 BESXMLInterface::execute_data_request_plan() 00258 { 00259 vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ; 00260 vector<BESXMLCommand *>::iterator e = _cmd_list.end() ; 00261 for( ; i != e; i++ ) 00262 { 00263 (*i)->prep_request() ; 00264 _dhi = &(*i)->get_dhi() ; 00265 BESBasicInterface::execute_data_request_plan() ; 00266 } 00267 } 00268 00271 void 00272 BESXMLInterface::invoke_aggregation() 00273 { 00274 BESBasicInterface::invoke_aggregation() ; 00275 } 00276 00279 void 00280 BESXMLInterface::transmit_data() 00281 { 00282 string returnAs = _dhi->data[RETURN_CMD] ; 00283 if( returnAs != "" ) 00284 { 00285 BESDEBUG( "xml", "Setting transmitter: " << returnAs 00286 << " ... " << endl ) ; 00287 _transmitter = 00288 BESReturnManager::TheManager()->find_transmitter( returnAs ) ; 00289 if( !_transmitter ) 00290 { 00291 string s = (string)"Unable to find transmitter " 00292 + returnAs ; 00293 throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ; 00294 } 00295 BESDEBUG( "xml", "OK" << endl ) ; 00296 } 00297 00298 BESBasicInterface::transmit_data() ; 00299 } 00300 00305 void 00306 BESXMLInterface::log_status() 00307 { 00308 vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ; 00309 vector<BESXMLCommand *>::iterator e = _cmd_list.end() ; 00310 for( ; i != e; i++ ) 00311 { 00312 _dhi = &(*i)->get_dhi() ; 00313 BESBasicInterface::log_status() ; 00314 } 00315 } 00316 00332 void 00333 BESXMLInterface::report_request() 00334 { 00335 vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ; 00336 vector<BESXMLCommand *>::iterator e = _cmd_list.end() ; 00337 for( ; i != e; i++ ) 00338 { 00339 _dhi = &(*i)->get_dhi() ; 00340 BESBasicInterface::report_request() ; 00341 } 00342 } 00343 00346 void 00347 BESXMLInterface::clean() 00348 { 00349 vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ; 00350 vector<BESXMLCommand *>::iterator e = _cmd_list.end() ; 00351 for( ; i != e; i++ ) 00352 { 00353 BESXMLCommand *cmd = *i ; 00354 _dhi = &cmd->get_dhi() ; 00355 BESBasicInterface::clean() ; 00356 delete cmd ; 00357 } 00358 _cmd_list.clear() ; 00359 } 00360 00367 void 00368 BESXMLInterface::dump( ostream &strm ) const 00369 { 00370 strm << BESIndent::LMarg << "BESXMLInterface::dump - (" 00371 << (void *)this << ")" << endl ; 00372 BESIndent::Indent() ; 00373 BESBasicInterface::dump( strm ) ; 00374 vector<BESXMLCommand *>::const_iterator i = _cmd_list.begin() ; 00375 vector<BESXMLCommand *>::const_iterator e = _cmd_list.end() ; 00376 for( ; i != e; i++ ) 00377 { 00378 BESXMLCommand *cmd = *i ; 00379 cmd->dump( strm ) ; 00380 } 00381 BESIndent::UnIndent() ; 00382 } 00383