bes  Updated for version 3.20.8
BESXMLDefineCommand.cc
1 // BESXMLDefineCommand.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "config.h"
34 
35 #include "BESXMLDefineCommand.h"
36 #include "BESContainerStorageList.h"
37 #include "BESContainerStorage.h"
38 
39 #include "BESXMLUtils.h"
40 #include "BESUtil.h"
41 #include "BESResponseNames.h"
42 #include "BESDataNames.h"
43 
44 #include "BESSyntaxUserError.h"
45 #include "BESInternalFatalError.h"
46 #include "BESDebug.h"
47 
48 using std::endl;
49 using std::string;
50 using std::vector;
51 using std::ostream;
52 using std::map;
53 
54 BESXMLDefineCommand::BESXMLDefineCommand(const BESDataHandlerInterface &base_dhi) :
55  BESXMLCommand(base_dhi), _default_constraint(""), _default_dap4_constraint(""), _default_dap4_function("")
56 {
57 }
58 
88 {
89  string value; // element value, should not be any
90  string action; // element name, which is the request action
91  map<string, string> props; // element attributes; 'name' and maybe 'space'
92 
93  BESXMLUtils::GetNodeInfo(node, action, value, props);
94  if (action != DEFINE_RESPONSE_STR) {
95  string err = "The specified command " + action + " is not a set context command";
96  throw BESInternalFatalError(err, __FILE__, __LINE__);
97  }
98 
99  d_xmlcmd_dhi.action = DEFINE_RESPONSE;
100 
101  string def_name = props["name"];
102  if (def_name.empty())
103  throw BESSyntaxUserError(string(action) + " command: definition name missing", __FILE__, __LINE__);
104 
105  d_xmlcmd_dhi.data[DEF_NAME] = def_name;
106  d_cmd_log_info = (string) "define " + def_name;
107 
108  d_xmlcmd_dhi.data[STORE_NAME] = props["space"].empty() ? DEFAULT: props["space"];
109  d_cmd_log_info += " in " + d_xmlcmd_dhi.data[STORE_NAME];
110 
111  int num_containers = 0;
112  string child_name;
113  string child_value;
114  props.clear();
115  xmlNode *child_node = BESXMLUtils::GetFirstChild(node, child_name, child_value, props);
116  while (child_node) {
117  if (child_name == "constraint") {
118  // default constraint for all containers
119  _default_constraint = child_value;
120  }
121  else if (child_name == "dap4constraint") {
122  // default function for all containers
123  _default_dap4_constraint = child_value;
124  }
125  else if (child_name == "dap4function") {
126  // default function for all containers
127  _default_dap4_function = child_value;
128  }
129  else if (child_name == "container") {
130  handle_container_element(action, child_node, child_value, props);
131  num_containers++;
132  }
133  else {
134  throw BESSyntaxUserError(string(action) + " Unrecognized child element: " + child_name, __FILE__, __LINE__);
135  }
136 #if 0
137  else if (child_name == "aggregate") {
138  handle_aggregate_element(action, child_node, child_value, props);
139  }
140 #endif
141 
142  // get the next child element
143  props.clear();
144  child_name.clear();
145  child_value.clear();
146  child_node = BESXMLUtils::GetNextChild(child_node, child_name, child_value, props);
147  }
148 
149  if (num_containers < 1)
150  throw BESSyntaxUserError(string(action) + " The define element must contain at least one container element", __FILE__, __LINE__);
151 
152  d_cmd_log_info += " as ";
153  bool first = true;
154  vector<string>::iterator i = container_names.begin();
155  vector<string>::iterator e = container_names.end();
156  for (; i != e; i++) {
157  if (!first) d_cmd_log_info += ",";
158  d_cmd_log_info += (*i);
159  first = false;
160  }
161 
162  if (container_constraints.size() || container_dap4constraints.size() || container_dap4functions.size() || container_attributes.size()) {
163  d_cmd_log_info += " with ";
164  first = true;
165  i = container_names.begin();
166  e = container_names.end();
167  for (; i != e; i++) {
168  if (container_constraints.count((*i))) {
169  if (!first) d_cmd_log_info += ",";
170  first = false;
171  d_cmd_log_info += (*i) + ".constraint=\"" + container_constraints[(*i)] + "\"";
172  }
173  if (container_dap4constraints.count((*i))) {
174  if (!first) d_cmd_log_info += ",";
175  first = false;
176  d_cmd_log_info += (*i) + ".dap4constraint=\"" + container_dap4constraints[(*i)] + "\"";
177  }
178  if (container_dap4functions.count((*i))) {
179  if (!first) d_cmd_log_info += ",";
180  first = false;
181  d_cmd_log_info += (*i) + ".dap4function=\"" + container_dap4functions[(*i)] + "\"";
182  }
183  if (container_attributes.count((*i))) {
184  if (!first) d_cmd_log_info += ",";
185  first = false;
186  d_cmd_log_info += (*i) + ".attributes=\"" + container_attributes[(*i)] + "\"";
187  }
188  }
189  }
190 
191  d_cmd_log_info += ";";
192 
193  // now that we've set the action, go get the response handler for the action
195 }
196 
220 void BESXMLDefineCommand::handle_container_element(const string &action, xmlNode *node, const string &/*value*/,
221  map<string, string> &props)
222 {
223  string name = props["name"];
224  if (name.empty()) {
225  string err = action + " command: container element missing name prop";
226  throw BESSyntaxUserError(err, __FILE__, __LINE__);
227  }
228 
229  container_names.push_back(name);
230 
231  container_store_names[name] = props["space"];
232 
233  bool have_constraint = false;
234  bool have_dap4constraint = false;
235  bool have_dap4function = false;
236  bool have_attributes = false;
237  string child_name;
238  string child_value;
239  string constraint;
240  string attributes;
241  map<string, string> child_props;
242  xmlNode *child_node = BESXMLUtils::GetFirstChild(node, child_name, child_value, child_props);
243  while (child_node) {
244  if (child_name == "constraint") {
245  if (child_props.size()) {
246  string err = action + " command: constraint element " + "should not contain properties";
247  throw BESSyntaxUserError(err, __FILE__, __LINE__);
248  }
249  if (child_value.empty()) {
250  string err = action + " command: constraint element " + "missing value";
251  throw BESSyntaxUserError(err, __FILE__, __LINE__);
252  }
253  if (have_constraint) {
254  string err = action + " command: container element " + "contains multiple constraint elements";
255  throw BESSyntaxUserError(err, __FILE__, __LINE__);
256  }
257  have_constraint = true;
258  container_constraints[name] = child_value;
259  }
260  else if (child_name == "dap4constraint") {
261  if (child_props.size()) {
262  string err = action + " command: constraint element " + "should not contain properties";
263  throw BESSyntaxUserError(err, __FILE__, __LINE__);
264  }
265  if (child_value.empty()) {
266  string err = action + " command: constraint element " + "missing value";
267  throw BESSyntaxUserError(err, __FILE__, __LINE__);
268  }
269  if (have_dap4constraint) {
270  string err = action + " command: container element " + "contains multiple constraint elements";
271  throw BESSyntaxUserError(err, __FILE__, __LINE__);
272  }
273  have_dap4constraint = true;
274  container_dap4constraints[name] = child_value;
275  }
276  else if (child_name == "dap4function") {
277  if (child_props.size()) {
278  string err = action + " command: dap4_function element " + "should not contain properties";
279  throw BESSyntaxUserError(err, __FILE__, __LINE__);
280  }
281  if (child_value.empty()) {
282  string err = action + " command: dap4_function element " + "missing value";
283  throw BESSyntaxUserError(err, __FILE__, __LINE__);
284  }
285  if (have_dap4function) {
286  string err = action + " command: container element " + "contains multiple dap4_function elements";
287  throw BESSyntaxUserError(err, __FILE__, __LINE__);
288  }
289  have_dap4function = true;
290  container_dap4functions[name] = child_value;
291  }
292  else if (child_name == "attributes") {
293  if (child_props.size()) {
294  string err = action + " command: attributes element " + "should not contain properties";
295  throw BESSyntaxUserError(err, __FILE__, __LINE__);
296  }
297  if (child_value.empty()) {
298  string err = action + " command: attributes element " + "missing value";
299  throw BESSyntaxUserError(err, __FILE__, __LINE__);
300  }
301  if (have_attributes) {
302  string err = action + " command: container element " + "contains multiple attributes elements";
303  throw BESSyntaxUserError(err, __FILE__, __LINE__);
304  }
305  have_attributes = true;
306  container_attributes[name] = child_value;
307  }
308 
309  // get the next child element
310  props.clear();
311  child_name.clear();
312  child_value.clear();
313  child_node = BESXMLUtils::GetNextChild(child_node, child_name, child_value, props);
314  }
315 }
316 
317 #if 0
331 void BESXMLDefineCommand::handle_aggregate_element(const string &action, xmlNode */*node*/, const string &/*value*/,
332  map<string, string> &props)
333 {
334  string handler = props["handler"];
335  string cmd = props["cmd"];
336  if (handler.empty()) {
337  string err = action + " command: must specify aggregation handler";
338  throw BESSyntaxUserError(err, __FILE__, __LINE__);
339  }
340  if (cmd.empty()) {
341  string err = action + " command: must specify aggregation cmd";
342  throw BESSyntaxUserError(err, __FILE__, __LINE__);
343  }
344 
345  d_xmlcmd_dhi.data[AGG_HANDLER] = handler;
346  d_xmlcmd_dhi.data[AGG_CMD] = cmd;
347  d_cmd_log_info += " aggregate using " + handler + " by " + cmd;
348 }
349 #endif
350 
351 
361 {
362  vector<string>::iterator i = container_names.begin();
363  vector<string>::iterator e = container_names.end();
364  for (; i != e; i++) {
365  // look for the specified container
366  BESContainer *c = 0;
367 
368  // Is a particular store is being used - this is container store
369  // not the definition store. If no store is named, search them all.
370  string store = container_store_names[(*i)];
371  if (!store.empty()) {
372  BESContainerStorage *cs = BESContainerStorageList::TheList()->find_persistence(store);
373  if (cs) c = cs->look_for((*i));
374  }
375  else {
376  c = BESContainerStorageList::TheList()->look_for((*i));
377  }
378 
379  if (c == 0)
380  throw BESSyntaxUserError(string("Could not find the container ") + (*i), __FILE__, __LINE__);
381 
382  // What use case do we have in which the "default" value of the constraint is not an empty string?
383  string constraint = container_constraints[(*i)];
384  if (constraint.empty()) constraint = _default_constraint;
385  c->set_constraint(constraint);
386 
387  // What use case do we have in which the "default" value of the dap4constraint is not an empty string?
388  string dap4constraint = container_dap4constraints[(*i)];
389  if (dap4constraint.empty()) dap4constraint = _default_dap4_constraint;
390  c->set_dap4_constraint(dap4constraint);
391 
392  // What use case do we have in which the "default" value of the dap4function is not an empty string?
393  string function = container_dap4functions[(*i)];
394  if (function.empty()) function = _default_dap4_function;
395  c->set_dap4_function(function);
396 
397  string attrs = container_attributes[(*i)];
398  c->set_attributes(attrs);
399  d_xmlcmd_dhi.containers.push_back(c);
400 
401  BESDEBUG("xml", "BESXMLDefineCommand::prep_request() - define using container: " << endl << *c << endl);
402  }
403 }
404 
412 void BESXMLDefineCommand::dump(ostream &strm) const
413 {
414  strm << BESIndent::LMarg << "BESXMLDefineCommand::dump - (" << (void *) this << ")" << endl;
415  BESIndent::Indent();
416  BESXMLCommand::dump(strm);
417  BESIndent::UnIndent();
418 }
419 
421 BESXMLDefineCommand::CommandBuilder(const BESDataHandlerInterface &base_dhi)
422 {
423  return new BESXMLDefineCommand(base_dhi);
424 }
425 
virtual BESContainer * look_for(const std::string &sym_name)
look for the specified container information in the list of persistent stores.
virtual BESContainerStorage * find_persistence(const std::string &persist_name)
find the persistence store with the given name
provides persistent storage for data storage information represented by a container.
virtual BESContainer * look_for(const std::string &sym_name)=0
looks for a container in this persistent store
A container is something that holds data. E.G., a netcdf file or a database entry.
Definition: BESContainer.h:65
void set_constraint(const std::string &s)
set the constraint for this container
Definition: BESContainer.h:118
void set_dap4_function(const std::string &s)
set the constraint for this container
Definition: BESContainer.h:136
void set_attributes(const std::string &attrs)
set desired attributes for this container
Definition: BESContainer.h:170
void set_dap4_constraint(const std::string &s)
set the constraint for this container
Definition: BESContainer.h:127
Structure storing information used by the BES to handle the request.
std::map< std::string, std::string > data
the map of string data that will be required for the current request.
std::string action
the response object requested, e.g. das, dds
exception thrown if an internal error is found and is fatal to the BES
error thrown if there is a user syntax error in the request or any other user error
Base class for the BES's commands.
Definition: BESXMLCommand.h:63
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual void set_response()
The request has been parsed, use the command action name to set the response handler.
std::string d_cmd_log_info
Used only for the log.
Definition: BESXMLCommand.h:74
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual void prep_request()
prepare the define command by making sure the containers exist
virtual void parse_request(xmlNode *node)
parse a define command.
static void GetNodeInfo(xmlNode *node, std::string &name, std::string &value, std::map< std::string, std::string > &props)
get the name, value if any, and any properties for the specified node
Definition: BESXMLUtils.cc:105
static xmlNode * GetFirstChild(xmlNode *node, std::string &child_name, std::string &child_value, std::map< std::string, std::string > &child_props)
get the first element child node for the given node
Definition: BESXMLUtils.cc:137
static xmlNode * GetNextChild(xmlNode *child_node, std::string &next_name, std::string &next_value, std::map< std::string, std::string > &next_props)
get the next element child node after the given child node
Definition: BESXMLUtils.cc:164