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                     << " [" << _dhi->data[DATA_REQUEST] << "] building"
00096                     << endl ;
00097     }
00098 
00099     LIBXML_TEST_VERSION
00100 
00101     xmlDoc *doc = NULL ;
00102     xmlNode *root_element = NULL ;
00103     xmlNode *current_node = NULL ;
00104 
00105     try
00106     {
00107         // set the default error function to my own
00108         vector<string> parseerrors ;
00109         xmlSetGenericErrorFunc( (void *)&parseerrors, BESXMLUtils::XMLErrorFunc );
00110 
00111         doc = xmlParseDoc( (unsigned char *)_dhi->data["XMLDoc"].c_str() ) ;
00112         if( doc == NULL )
00113         {
00114             string err = "Problem parsing the request xml document:\n" ;
00115             bool isfirst = true ;
00116             vector<string>::const_iterator i = parseerrors.begin() ;
00117             vector<string>::const_iterator e = parseerrors.end() ;
00118             for( ; i != e; i++ )
00119             {
00120                 if( !isfirst && (*i).compare( 0, 6, "Entity" ) == 0 )
00121                 {
00122                     err += "\n" ;
00123                 }
00124                 err += (*i) ;
00125                 isfirst = false ;
00126             }
00127             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00128         }
00129 
00130         // get the root element and make sure it exists and is called request
00131         root_element = xmlDocGetRootElement( doc ) ;
00132         if( !root_element )
00133         {
00134             string err = "There is no root element in the xml document" ;
00135             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00136         }
00137 
00138         string root_name ;
00139         string root_val ;
00140         map< string, string> props ;
00141         BESXMLUtils::GetNodeInfo( root_element, root_name, root_val, props ) ;
00142         if( root_name != "request" )
00143         {
00144             string err = (string)"The root element should be a request element, "
00145                          + "name is " + (char *)root_element->name ;
00146             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00147         }
00148         if( root_val != "" )
00149         {
00150             string err = (string)"The request element must not contain a value, "
00151                          + root_val ;
00152             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00153         }
00154 
00155         // there should be a request id property with one value.
00156         string &reqId = props[REQUEST_ID] ;
00157         if( reqId.empty() )
00158         {
00159             string err = (string)"request id value empty" ;
00160             throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00161         }
00162         _dhi->data[REQUEST_ID] = reqId ;
00163         BESDEBUG( "besxml", "request id = "<< _dhi->data[REQUEST_ID] << 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                 p_xmlcmd_builder bldr = BESXMLCommand::find_command( node_name ) ;
00178                 if( bldr )
00179                 {
00180                     BESXMLCommand *current_cmd = bldr( _base_dhi ) ;
00181                     if( !current_cmd )
00182                     {
00183                         string err = (string)"Failed to build command object for "
00184                                      + node_name ;
00185                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00186                     }
00187 
00188                     // push this new command to the back of the list
00189                     _cmd_list.push_back( current_cmd ) ;
00190 
00191                     // only one of the commands can build a response. If more
00192                     // than one builds a response, throw an error
00193                     bool cmd_has_response = current_cmd->has_response() ;
00194                     if( has_response && cmd_has_response )
00195                     {
00196                         string err = "Multiple responses not allowed" ;
00197                         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00198                     }
00199                     has_response = cmd_has_response ;
00200 
00201                     // parse the request given the current node
00202                     current_cmd->parse_request( current_node ) ;
00203 
00204                     BESDataHandlerInterface &current_dhi = current_cmd->get_dhi();
00205                     string returnAs = current_dhi.data[RETURN_CMD] ;
00206                     if( returnAs != "" )
00207                     {
00208                         BESDEBUG( "xml", "Finding transmitter: " << returnAs
00209                                          << " ...  " << endl )
00210                         BESTransmitter *transmitter =
00211                             BESReturnManager::TheManager()->find_transmitter( returnAs ) ;
00212                         if( !transmitter )
00213                         {
00214                             string s = (string)"Unable to find transmitter "
00215                                        + returnAs ;
00216                             throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
00217                         }
00218                         BESDEBUG( "xml", "OK" << endl )
00219                     }
00220                 }
00221                 else
00222                 {
00223                     string err = (string)"Unable to find command for "
00224                                  + node_name ;
00225                     throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00226                 }
00227             }
00228             current_node = current_node->next ;
00229         }
00230     }
00231     catch( BESError &e )
00232     {
00233         xmlFreeDoc( doc ) ;
00234         throw e ;
00235     }
00236 
00237     xmlFreeDoc( doc ) ;
00238 #if 0
00239     // Removed since the docs indicate it's not needed and it might be
00240     // contributing to memory issues flagged by valgrind. 2/25/09 jhrg
00241     xmlCleanupParser() ;
00242 #endif
00243     BESDEBUG( "besxml", "Done building request plan" << endl )
00244 
00245     BESBasicInterface::build_data_request_plan() ;
00246 }
00247 
00250 void
00251 BESXMLInterface::execute_data_request_plan()
00252 {
00253     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00254     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00255     for( ; i != e; i++ )
00256     {
00257         (*i)->prep_request() ;
00258         _dhi = &(*i)->get_dhi() ;
00259         BESBasicInterface::execute_data_request_plan() ;
00260     }
00261 }
00262 
00265 void
00266 BESXMLInterface::invoke_aggregation()
00267 {
00268     BESBasicInterface::invoke_aggregation() ;
00269 }
00270 
00273 void
00274 BESXMLInterface::transmit_data()
00275 {
00276     string returnAs = _dhi->data[RETURN_CMD] ;
00277     if( returnAs != "" )
00278     {
00279         BESDEBUG( "xml", "Setting transmitter: " << returnAs
00280                          << " ...  " << endl )
00281         _transmitter =
00282             BESReturnManager::TheManager()->find_transmitter( returnAs ) ;
00283         if( !_transmitter )
00284         {
00285             string s = (string)"Unable to find transmitter "
00286                        + returnAs ;
00287             throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
00288         }
00289         BESDEBUG( "xml", "OK" << endl )
00290     }
00291 
00292     BESBasicInterface::transmit_data() ;
00293 }
00294 
00299 void
00300 BESXMLInterface::log_status()
00301 {
00302     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00303     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00304     for( ; i != e; i++ )
00305     {
00306         _dhi = &(*i)->get_dhi() ;
00307         BESBasicInterface::log_status() ;
00308     }
00309 }
00310 
00326 void
00327 BESXMLInterface::report_request()
00328 {
00329     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00330     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00331     for( ; i != e; i++ )
00332     {
00333         _dhi = &(*i)->get_dhi() ;
00334         BESBasicInterface::report_request() ;
00335     }
00336 }
00337 
00340 void
00341 BESXMLInterface::clean()
00342 {
00343     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00344     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00345     for( ; i != e; i++ )
00346     {
00347         BESXMLCommand *cmd = *i ;
00348         _dhi = &cmd->get_dhi() ;
00349         BESBasicInterface::clean() ;
00350         delete cmd ;
00351     }
00352     _cmd_list.clear() ;
00353 }
00354 
00361 void
00362 BESXMLInterface::dump( ostream &strm ) const
00363 {
00364     strm << BESIndent::LMarg << "BESXMLInterface::dump - ("
00365                              << (void *)this << ")" << endl ;
00366     BESIndent::Indent() ;
00367     BESBasicInterface::dump( strm ) ;
00368     vector<BESXMLCommand *>::const_iterator i = _cmd_list.begin() ;
00369     vector<BESXMLCommand *>::const_iterator e = _cmd_list.end() ;
00370     for( ; i != e; i++ )
00371     {
00372         BESXMLCommand *cmd = *i ;
00373         cmd->dump( strm ) ;
00374     }
00375     BESIndent::UnIndent() ;
00376 }
00377 

Generated on Sat Aug 22 06:04:40 2009 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.6.0