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]
00164                             << endl ) ;
00165 
00166         // iterate through the children of the request element. Each child is an
00167         // individual command.
00168         bool has_response = false ;
00169         current_node = root_element->children ;
00170 
00171         while( current_node )
00172         {
00173             if( current_node->type == XML_ELEMENT_NODE )
00174             {
00175                 // given the name of this node we should be able to find a
00176                 // BESXMLCommand object
00177                 string node_name = (char *)current_node->name ;
00178                 p_xmlcmd_builder bldr = BESXMLCommand::find_command( node_name ) ;
00179                 if( bldr )
00180                 {
00181                     BESXMLCommand *current_cmd = bldr( _base_dhi ) ;
00182                     if( !current_cmd )
00183                     {
00184                         string err = (string)"Failed to build command object for "
00185                                      + node_name ;
00186                         throw BESInternalError( err, __FILE__, __LINE__ ) ;
00187                     }
00188 
00189                     // push this new command to the back of the list
00190                     _cmd_list.push_back( current_cmd ) ;
00191 
00192                     // only one of the commands can build a response. If more
00193                     // than one builds a response, throw an error
00194                     bool cmd_has_response = current_cmd->has_response() ;
00195                     if( has_response && cmd_has_response )
00196                     {
00197                         string err = "Multiple responses not allowed" ;
00198                         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00199                     }
00200                     has_response = cmd_has_response ;
00201 
00202                     // parse the request given the current node
00203                     current_cmd->parse_request( current_node ) ;
00204 
00205                     BESDataHandlerInterface &current_dhi = current_cmd->get_dhi();
00206                     string returnAs = current_dhi.data[RETURN_CMD] ;
00207                     if( returnAs != "" )
00208                     {
00209                         BESDEBUG( "xml", "Finding transmitter: " << returnAs
00210                                          << " ...  " << endl ) ;
00211                         BESTransmitter *transmitter =
00212                             BESReturnManager::TheManager()->find_transmitter( returnAs ) ;
00213                         if( !transmitter )
00214                         {
00215                             string s = (string)"Unable to find transmitter "
00216                                        + returnAs ;
00217                             throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
00218                         }
00219                         BESDEBUG( "xml", "OK" << endl ) ;
00220                     }
00221                 }
00222                 else
00223                 {
00224                     string err = (string)"Unable to find command for "
00225                                  + node_name ;
00226                     throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00227                 }
00228             }
00229             current_node = current_node->next ;
00230         }
00231     }
00232     catch( BESError &e )
00233     {
00234         xmlFreeDoc( doc ) ;
00235         throw e ;
00236     }
00237 
00238     xmlFreeDoc( doc ) ;
00239 #if 0
00240     // Removed since the docs indicate it's not needed and it might be
00241     // contributing to memory issues flagged by valgrind. 2/25/09 jhrg
00242     xmlCleanupParser() ;
00243 #endif
00244     BESDEBUG( "besxml", "Done building request plan" << endl ) ;
00245 
00246     BESBasicInterface::build_data_request_plan() ;
00247 }
00248 
00251 void
00252 BESXMLInterface::execute_data_request_plan()
00253 {
00254     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00255     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00256     for( ; i != e; i++ )
00257     {
00258         (*i)->prep_request() ;
00259         _dhi = &(*i)->get_dhi() ;
00260         BESBasicInterface::execute_data_request_plan() ;
00261     }
00262 }
00263 
00266 void
00267 BESXMLInterface::invoke_aggregation()
00268 {
00269     BESBasicInterface::invoke_aggregation() ;
00270 }
00271 
00274 void
00275 BESXMLInterface::transmit_data()
00276 {
00277     string returnAs = _dhi->data[RETURN_CMD] ;
00278     if( returnAs != "" )
00279     {
00280         BESDEBUG( "xml", "Setting transmitter: " << returnAs
00281                          << " ...  " << endl ) ;
00282         _transmitter =
00283             BESReturnManager::TheManager()->find_transmitter( returnAs ) ;
00284         if( !_transmitter )
00285         {
00286             string s = (string)"Unable to find transmitter "
00287                        + returnAs ;
00288             throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
00289         }
00290         BESDEBUG( "xml", "OK" << endl ) ;
00291     }
00292 
00293     BESBasicInterface::transmit_data() ;
00294 }
00295 
00300 void
00301 BESXMLInterface::log_status()
00302 {
00303     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00304     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00305     for( ; i != e; i++ )
00306     {
00307         _dhi = &(*i)->get_dhi() ;
00308         BESBasicInterface::log_status() ;
00309     }
00310 }
00311 
00327 void
00328 BESXMLInterface::report_request()
00329 {
00330     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00331     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00332     for( ; i != e; i++ )
00333     {
00334         _dhi = &(*i)->get_dhi() ;
00335         BESBasicInterface::report_request() ;
00336     }
00337 }
00338 
00341 void
00342 BESXMLInterface::clean()
00343 {
00344     vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
00345     vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
00346     for( ; i != e; i++ )
00347     {
00348         BESXMLCommand *cmd = *i ;
00349         _dhi = &cmd->get_dhi() ;
00350         BESBasicInterface::clean() ;
00351         delete cmd ;
00352     }
00353     _cmd_list.clear() ;
00354 }
00355 
00362 void
00363 BESXMLInterface::dump( ostream &strm ) const
00364 {
00365     strm << BESIndent::LMarg << "BESXMLInterface::dump - ("
00366                              << (void *)this << ")" << endl ;
00367     BESIndent::Indent() ;
00368     BESBasicInterface::dump( strm ) ;
00369     vector<BESXMLCommand *>::const_iterator i = _cmd_list.begin() ;
00370     vector<BESXMLCommand *>::const_iterator e = _cmd_list.end() ;
00371     for( ; i != e; i++ )
00372     {
00373         BESXMLCommand *cmd = *i ;
00374         cmd->dump( strm ) ;
00375     }
00376     BESIndent::UnIndent() ;
00377 }
00378 

Generated on Thu Feb 11 09:13:15 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7