OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
BESXMLInterface.cc
Go to the documentation of this file.
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 &current_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