BESXMLDefineCommand.cc

Go to the documentation of this file.
00001 // BESXMLDefineCommand.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 "BESXMLDefineCommand.h"
00034 #include "BESContainerStorageList.h"
00035 #include "BESXMLUtils.h"
00036 #include "BESUtil.h"
00037 #include "BESResponseNames.h"
00038 #include "BESDataNames.h"
00039 #include "BESSyntaxUserError.h"
00040 #include "BESDebug.h"
00041 
00042 BESXMLDefineCommand::BESXMLDefineCommand( const BESDataHandlerInterface &base_dhi )
00043     : BESXMLCommand( base_dhi ),
00044       _default_constraint( "" )
00045 {
00046 }
00047 
00065 void
00066 BESXMLDefineCommand::parse_request( xmlNode *node )
00067 {
00068     string value ;              // element value, should not be any
00069     string def_name ;           // definition name
00070     string action ;             // element name, which is the request action
00071     map<string, string> props ; // element properties. Should contain name
00072                                 // and optionally space
00073 
00074     BESXMLUtils::GetNodeInfo( node, action, value, props ) ;
00075     if( action != DEFINE_RESPONSE_STR )
00076     {
00077         string err = "The specified command " + action
00078                      + " is not a set context command" ;
00079         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00080     }
00081 
00082     _dhi.action = DEFINE_RESPONSE ;
00083 
00084     def_name = props["name"] ;
00085     if( def_name.empty() )
00086     {
00087         string err = action + " command: definition name missing" ;
00088         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00089     }
00090 
00091     _dhi.data[DEF_NAME] = def_name ;
00092     _str_cmd = (string)"define " + def_name ;
00093 
00094     int num_containers = 0 ;
00095     string child_name ;
00096     string child_value ;
00097     props.clear() ;
00098     xmlNode *child_node =
00099         BESXMLUtils::GetFirstChild( node, child_name, child_value, props ) ;
00100     while( child_node )
00101     {
00102         if( child_name == "constraint" )
00103         {
00104             // default constraint for all containers
00105             _default_constraint = child_value ;
00106         }
00107         else if( child_name == "container" )
00108         {
00109             handle_container_element( action, child_node, child_value, props ) ;
00110             num_containers++ ;
00111         }
00112         else if( child_name == "aggregate" )
00113         {
00114             handle_aggregate_element( action, child_node, child_value, props ) ;
00115         }
00116 
00117         // get the next child element
00118         props.clear() ;
00119         child_name.clear() ;
00120         child_value.clear() ;
00121         child_node = BESXMLUtils::GetNextChild( child_node, child_name,
00122                                                 child_value, props ) ;
00123     }
00124 
00125     if( num_containers < 1 )
00126     {
00127         string err = action + "The define element must contain at least "
00128                      + "one container element" ;
00129         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00130     }
00131 
00132     _str_cmd += " as " ;
00133     bool first = true ;
00134     vector<string>::iterator i = _containers.begin() ;
00135     vector<string>::iterator e = _containers.end() ;
00136     for( ; i != e; i++ )
00137     {
00138         if( !first ) _str_cmd += "," ;
00139         _str_cmd += (*i) ;
00140         first = false ;
00141     }
00142     if( _constraints.size() )
00143     {
00144         _str_cmd += " with " ;
00145         first = true ;
00146         map<string,string>::iterator ci = _constraints.begin() ;
00147         map<string,string>::iterator ce = _constraints.end() ;
00148         for( ; ci != ce; ci++ )
00149         {
00150             if( !first ) _str_cmd += "," ;
00151             _str_cmd += (*ci).first + ".constraint=\"" + (*ci).second + "\"" ;
00152             first = false ;
00153             string attrs = _attributes[(*ci).first] ;
00154             if( !attrs.empty() )
00155             {
00156                 _str_cmd += "," + (*ci).first + ".attributes=\"" + attrs + "\"";
00157             }
00158         }
00159     }
00160     _str_cmd += ";" ;
00161 
00162     // now that we've set the action, go get the response handler for the
00163     // action
00164     BESXMLCommand::set_response() ;
00165 }
00166 
00181 void
00182 BESXMLDefineCommand::handle_container_element( const string &action,
00183                                                xmlNode *node,
00184                                                const string &value,
00185                                                map<string,string> &props )
00186 {
00187     string name = props["name"] ;
00188     if( name.empty() )
00189     {
00190         string err = action + " command: container element missing name prop" ;
00191         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00192     }
00193 
00194     _containers.push_back( name ) ;
00195 
00196     bool have_constraint = false ;
00197     bool have_attributes = false ;
00198     string child_name ;
00199     string child_value ;
00200     string constraint ;
00201     string attributes ;
00202     map<string,string> child_props ;
00203     xmlNode *child_node =
00204         BESXMLUtils::GetFirstChild( node, child_name, child_value, child_props);
00205     while( child_node )
00206     {
00207         if( child_name == "constraint" )
00208         {
00209             if( child_props.size() )
00210             {
00211                 string err = action + " command: constraint element "
00212                                     + "should not contain properties" ;
00213                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00214             }
00215             if( child_value.empty() )
00216             {
00217                 string err = action + " command: attributes element "
00218                                     + "missing value" ;
00219                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00220             }
00221             if( have_constraint )
00222             {
00223                 string err = action + " command: container element "
00224                                     + "contains multiple constraint elements" ;
00225                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00226             }
00227             have_constraint = true ;
00228             _constraints[name] = child_value ;
00229         }
00230         else if( child_name == "attributes" )
00231         {
00232             if( child_props.size() )
00233             {
00234                 string err = action + " command: attributes element "
00235                                     + "should not contain properties" ;
00236                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00237             }
00238             if( child_value.empty() )
00239             {
00240                 string err = action + " command: attributes element "
00241                                     + "missing value" ;
00242                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00243             }
00244             if( have_attributes )
00245             {
00246                 string err = action + " command: container element "
00247                                     + "contains multiple attributes elements" ;
00248                 throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00249             }
00250             have_attributes = true ;
00251             _attributes[name] = child_value ;
00252         }
00253 
00254         // get the next child element
00255         props.clear() ;
00256         child_name.clear() ;
00257         child_value.clear() ;
00258         child_node = BESXMLUtils::GetNextChild( child_node, child_name,
00259                                                 child_value, props ) ;
00260     }
00261 }
00262 
00274 void
00275 BESXMLDefineCommand::handle_aggregate_element( const string &action,
00276                                                xmlNode *node,
00277                                                const string &value,
00278                                                map<string,string> &props )
00279 {
00280     string handler = props["handler"] ;
00281     string cmd = props["cmd"] ;
00282     if( handler.empty() )
00283     {
00284         string err = action + " command: must specify aggregation handler" ;
00285         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00286     }
00287     if( cmd.empty() )
00288     {
00289         string err = action + " command: must specify aggregation cmd" ;
00290         throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
00291     }
00292 
00293     _dhi.data[AGG_HANDLER] = handler ;
00294     _dhi.data[AGG_CMD] = cmd ;
00295     _str_cmd += " aggregate using " + handler + " by " + cmd ;
00296 }
00297 
00300 void
00301 BESXMLDefineCommand::prep_request()
00302 {
00303     vector<string>::iterator i = _containers.begin() ;
00304     vector<string>::iterator e = _containers.end() ;
00305     for( ; i != e; i++ )
00306     {
00307         // look for the specified container
00308         BESContainer *d =
00309             BESContainerStorageList::TheList()->look_for( (*i) ) ;
00310         string constraint = _constraints[(*i)] ;
00311         if( constraint.empty() ) constraint = _default_constraint ;
00312         d->set_constraint( constraint ) ;
00313         d->set_attributes( _attributes[(*i)] ) ;
00314         _dhi.containers.push_back( d ) ;
00315         BESDEBUG( "xml", "define using container: " << endl << *d << endl ) ;
00316     }
00317 }
00318 
00325 void
00326 BESXMLDefineCommand::dump( ostream &strm ) const
00327 {
00328     strm << BESIndent::LMarg << "BESXMLDefineCommand::dump - ("
00329                              << (void *)this << ")" << endl ;
00330     BESIndent::Indent() ;
00331     BESXMLCommand::dump( strm ) ;
00332     BESIndent::UnIndent() ;
00333 }
00334 
00335 BESXMLCommand *
00336 BESXMLDefineCommand::CommandBuilder( const BESDataHandlerInterface &base_dhi )
00337 {
00338     return new BESXMLDefineCommand( base_dhi ) ;
00339 }
00340