OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
BESXMLInterface.cc
Go to the documentation of this file.
1 // BESXMLInterface.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include <iostream>
34 #include <sstream>
35 
36 using std::endl ;
37 using std::cout ;
38 using std::stringstream ;
39 
40 #include "BESXMLInterface.h"
41 #include "BESXMLCommand.h"
42 #include "BESXMLUtils.h"
43 #include "BESDataNames.h"
44 #include "BESDebug.h"
45 #include "BESLog.h"
46 #include "BESSyntaxUserError.h"
47 #include "BESReturnManager.h"
48 
49 BESXMLInterface::BESXMLInterface( const string &xml_doc, ostream *strm )
50  : BESBasicInterface( strm )
51 {
52  _dhi = &_base_dhi ;
53  _dhi->data[DATA_REQUEST] = "xml document" ;
54  _dhi->data["XMLDoc"] = xml_doc ;
55 }
56 
58 {
59  clean() ;
60 }
61 
62 int
63 BESXMLInterface::execute_request( const string &from )
64 {
65  return BESBasicInterface::execute_request( from ) ;
66 }
67 
70 void
72 {
74 }
75 
78 void
80 {
82 }
83 
86 void
88 {
89  BESDEBUG( "besxml", "building request plan for xml document: "
90  << endl << _dhi->data["XMLDoc"] << endl ) ;
91  if( BESLog::TheLog()->is_verbose() )
92  {
94  << " from " << _dhi->data[REQUEST_FROM]
95  << "] building" << endl ;
96  }
97 
98  LIBXML_TEST_VERSION
99 
100  xmlDoc *doc = NULL ;
101  xmlNode *root_element = NULL ;
102  xmlNode *current_node = NULL ;
103 
104  try
105  {
106  // set the default error function to my own
107  vector<string> parseerrors ;
108  xmlSetGenericErrorFunc( (void *)&parseerrors, BESXMLUtils::XMLErrorFunc );
109 
110  doc = xmlParseDoc( (unsigned char *)_dhi->data["XMLDoc"].c_str() ) ;
111  if( doc == NULL )
112  {
113  string err = "Problem parsing the request xml document:\n" ;
114  bool isfirst = true ;
115  vector<string>::const_iterator i = parseerrors.begin() ;
116  vector<string>::const_iterator e = parseerrors.end() ;
117  for( ; i != e; i++ )
118  {
119  if( !isfirst && (*i).compare( 0, 6, "Entity" ) == 0 )
120  {
121  err += "\n" ;
122  }
123  err += (*i) ;
124  isfirst = false ;
125  }
126  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
127  }
128 
129  // get the root element and make sure it exists and is called request
130  root_element = xmlDocGetRootElement( doc ) ;
131  if( !root_element )
132  {
133  string err = "There is no root element in the xml document" ;
134  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
135  }
136 
137  string root_name ;
138  string root_val ;
139  map< string, string> props ;
140  BESXMLUtils::GetNodeInfo( root_element, root_name, root_val, props ) ;
141  if( root_name != "request" )
142  {
143  string err = (string)"The root element should be a request element, "
144  + "name is " + (char *)root_element->name ;
145  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
146  }
147  if( root_val != "" )
148  {
149  string err = (string)"The request element must not contain a value, "
150  + root_val ;
151  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
152  }
153 
154  // there should be a request id property with one value.
155  string &reqId = props[REQUEST_ID] ;
156  if( reqId.empty() )
157  {
158  string err = (string)"request id value empty" ;
159  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
160  }
161  _dhi->data[REQUEST_ID] = reqId ;
162  BESDEBUG( "besxml", "request id = " << _dhi->data[REQUEST_ID]
163  << endl ) ;
164 
165  // iterate through the children of the request element. Each child is an
166  // individual command.
167  bool has_response = false ;
168  current_node = root_element->children ;
169 
170  while( current_node )
171  {
172  if( current_node->type == XML_ELEMENT_NODE )
173  {
174  // given the name of this node we should be able to find a
175  // BESXMLCommand object
176  string node_name = (char *)current_node->name ;
177  BESDEBUG( "besxml", "looking for command " << node_name
178  << endl ) ;
179  p_xmlcmd_builder bldr = BESXMLCommand::find_command( node_name ) ;
180  if( bldr )
181  {
182  BESXMLCommand *current_cmd = bldr( _base_dhi ) ;
183  if( !current_cmd )
184  {
185  string err = (string)"Failed to build command object for "
186  + node_name ;
187  throw BESInternalError( err, __FILE__, __LINE__ ) ;
188  }
189 
190  // push this new command to the back of the list
191  _cmd_list.push_back( current_cmd ) ;
192 
193  // only one of the commands can build a response. If more
194  // than one builds a response, throw an error
195  bool cmd_has_response = current_cmd->has_response() ;
196  if( has_response && cmd_has_response )
197  {
198  string err = "Multiple responses not allowed" ;
199  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
200  }
201  has_response = cmd_has_response ;
202 
203  // parse the request given the current node
204  BESDEBUG( "besxml", "parse request using " << node_name
205  << endl ) ;
206  current_cmd->parse_request( current_node ) ;
207 
208  BESDataHandlerInterface &current_dhi = current_cmd->get_dhi();
209  BESDEBUG( "besxml", node_name << " parsed request, dhi = "
210  << current_dhi << endl ) ;
211  string returnAs = current_dhi.data[RETURN_CMD] ;
212  if( returnAs != "" )
213  {
214  BESDEBUG( "xml", "Finding transmitter: " << returnAs
215  << " ... " << endl ) ;
216  BESTransmitter *transmitter =
218  if( !transmitter )
219  {
220  string s = (string)"Unable to find transmitter "
221  + returnAs ;
222  throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
223  }
224  BESDEBUG( "xml", "OK" << endl ) ;
225  }
226  }
227  else
228  {
229  string err = (string)"Unable to find command for "
230  + node_name ;
231  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
232  }
233  }
234  current_node = current_node->next ;
235  }
236  }
237  catch( BESError &e )
238  {
239  xmlFreeDoc( doc ) ;
240  throw e ;
241  }
242 
243  xmlFreeDoc( doc ) ;
244 #if 0
245  // Removed since the docs indicate it's not needed and it might be
246  // contributing to memory issues flagged by valgrind. 2/25/09 jhrg
247  xmlCleanupParser() ;
248 #endif
249  BESDEBUG( "besxml", "Done building request plan" << endl ) ;
250 
252 }
253 
256 void
258 {
259  vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
260  vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
261  for( ; i != e; i++ )
262  {
263  (*i)->prep_request() ;
264  _dhi = &(*i)->get_dhi() ;
266  }
267 }
268 
271 void
273 {
275 }
276 
279 void
281 {
282  string returnAs = _dhi->data[RETURN_CMD] ;
283  if( returnAs != "" )
284  {
285  BESDEBUG( "xml", "Setting transmitter: " << returnAs
286  << " ... " << endl ) ;
287  _transmitter =
289  if( !_transmitter )
290  {
291  string s = (string)"Unable to find transmitter "
292  + returnAs ;
293  throw BESSyntaxUserError( s, __FILE__, __LINE__ ) ;
294  }
295  BESDEBUG( "xml", "OK" << endl ) ;
296  }
297 
299 }
300 
305 void
307 {
308  vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
309  vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
310  for( ; i != e; i++ )
311  {
312  _dhi = &(*i)->get_dhi() ;
314  }
315 }
316 
332 void
334 {
335  vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
336  vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
337  for( ; i != e; i++ )
338  {
339  _dhi = &(*i)->get_dhi() ;
341  }
342 }
343 
346 void
348 {
349  vector<BESXMLCommand *>::iterator i = _cmd_list.begin() ;
350  vector<BESXMLCommand *>::iterator e = _cmd_list.end() ;
351  for( ; i != e; i++ )
352  {
353  BESXMLCommand *cmd = *i ;
354  _dhi = &cmd->get_dhi() ;
356  delete cmd ;
357  }
358  _cmd_list.clear() ;
359 }
360 
367 void
368 BESXMLInterface::dump( ostream &strm ) const
369 {
370  strm << BESIndent::LMarg << "BESXMLInterface::dump - ("
371  << (void *)this << ")" << endl ;
373  BESBasicInterface::dump( strm ) ;
374  vector<BESXMLCommand *>::const_iterator i = _cmd_list.begin() ;
375  vector<BESXMLCommand *>::const_iterator e = _cmd_list.end() ;
376  for( ; i != e; i++ )
377  {
378  BESXMLCommand *cmd = *i ;
379  cmd->dump( strm ) ;
380  }
382 }
383