bes  Updated for version 3.19.1
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 "BESXMLDefineCommand.h"
34 #include "BESContainerStorageList.h"
35 #include "BESContainerStorage.h"
36 #include "BESXMLUtils.h"
37 #include "BESUtil.h"
38 #include "BESResponseNames.h"
39 #include "BESDataNames.h"
40 #include "BESSyntaxUserError.h"
41 #include "BESDebug.h"
42 
43 BESXMLDefineCommand::BESXMLDefineCommand(const BESDataHandlerInterface &base_dhi) :
44  BESXMLCommand(base_dhi), _default_constraint(""), _default_dap4_constraint(""), _default_dap4_function("")
45 {
46 }
47 
66 {
67  string value; // element value, should not be any
68  string def_name; // definition name
69  string def_space; // definition storage space
70  string action; // element name, which is the request action
71  map<string, string> props; // element properties. Should contain name
72  // and optionally space
73 
74  BESXMLUtils::GetNodeInfo(node, action, value, props);
75  if (action != DEFINE_RESPONSE_STR) {
76  string err = "The specified command " + action + " is not a set context command";
77  throw BESSyntaxUserError(err, __FILE__, __LINE__);
78  }
79 
80  d_xmlcmd_dhi.action = DEFINE_RESPONSE;
81 
82  def_name = props["name"];
83  if (def_name.empty()) {
84  string err = action + " command: definition name missing";
85  throw BESSyntaxUserError(err, __FILE__, __LINE__);
86  }
87 
88  d_xmlcmd_dhi.data[DEF_NAME] = def_name;
89  d_cmd_log_info = (string) "define " + def_name;
90 
91  def_space = props["space"];
92  if (!def_space.empty()) {
93  d_cmd_log_info += " in " + def_space;
94  }
95  d_xmlcmd_dhi.data[STORE_NAME] = def_space;
96 
97  int num_containers = 0;
98  string child_name;
99  string child_value;
100  props.clear();
101  xmlNode *child_node = BESXMLUtils::GetFirstChild(node, child_name, child_value, props);
102  while (child_node) {
103  if (child_name == "constraint") {
104  // default constraint for all containers
105  _default_constraint = child_value;
106  }
107  else if (child_name == "dap4constraint") {
108  // default function for all containers
109  _default_dap4_constraint = child_value;
110  }
111  else if (child_name == "dap4function") {
112  // default function for all containers
113  _default_dap4_function = child_value;
114  }
115  else if (child_name == "container") {
116  handle_container_element(action, child_node, child_value, props);
117  num_containers++;
118  }
119  else if (child_name == "aggregate") {
120  handle_aggregate_element(action, child_node, child_value, props);
121  }
122 
123  // get the next child element
124  props.clear();
125  child_name.clear();
126  child_value.clear();
127  child_node = BESXMLUtils::GetNextChild(child_node, child_name, child_value, props);
128  }
129 
130  if (num_containers < 1) {
131  string err = action + "The define element must contain at least " + "one container element";
132  throw BESSyntaxUserError(err, __FILE__, __LINE__);
133  }
134 
135  d_cmd_log_info += " as ";
136  bool first = true;
137  vector<string>::iterator i = _containers.begin();
138  vector<string>::iterator e = _containers.end();
139  for (; i != e; i++) {
140  if (!first) d_cmd_log_info += ",";
141  d_cmd_log_info += (*i);
142  first = false;
143  }
144 
145  if (_constraints.size() || _dap4constraints.size() || _dap4functions.size() || _attributes.size()) {
146  d_cmd_log_info += " with ";
147  first = true;
148  i = _containers.begin();
149  e = _containers.end();
150  for (; i != e; i++) {
151  if (_constraints.count((*i))) {
152  if (!first) d_cmd_log_info += ",";
153  first = false;
154  d_cmd_log_info += (*i) + ".constraint=\"" + _constraints[(*i)] + "\"";
155  }
156  if (_dap4constraints.count((*i))) {
157  if (!first) d_cmd_log_info += ",";
158  first = false;
159  d_cmd_log_info += (*i) + ".dap4constraint=\"" + _dap4constraints[(*i)] + "\"";
160  }
161  if (_dap4functions.count((*i))) {
162  if (!first) d_cmd_log_info += ",";
163  first = false;
164  d_cmd_log_info += (*i) + ".dap4function=\"" + _dap4functions[(*i)] + "\"";
165  }
166  if (_attributes.count((*i))) {
167  if (!first) d_cmd_log_info += ",";
168  first = false;
169  d_cmd_log_info += (*i) + ".attributes=\"" + _attributes[(*i)] + "\"";
170  }
171  }
172  }
173 
174  d_cmd_log_info += ";";
175 
176  BESDEBUG("xml", "BESXMLDefineCommand::parse_request() - _str_cmd: " << d_cmd_log_info << endl);
177 
178  // now that we've set the action, go get the response handler for the
179  // action
181 }
182 
197 void BESXMLDefineCommand::handle_container_element(const string &action, xmlNode *node, const string &/*value*/,
198  map<string, string> &props)
199 {
200  string name = props["name"];
201  if (name.empty()) {
202  string err = action + " command: container element missing name prop";
203  throw BESSyntaxUserError(err, __FILE__, __LINE__);
204  }
205 
206  _containers.push_back(name);
207 
208  string space = props["space"];
209  _stores[name] = space;
210 
211  bool have_constraint = false;
212  bool have_dap4constraint = false;
213  bool have_dap4function = false;
214  bool have_attributes = false;
215  string child_name;
216  string child_value;
217  string constraint;
218  string attributes;
219  map<string, string> child_props;
220  xmlNode *child_node = BESXMLUtils::GetFirstChild(node, child_name, child_value, child_props);
221  while (child_node) {
222  if (child_name == "constraint") {
223  if (child_props.size()) {
224  string err = action + " command: constraint element " + "should not contain properties";
225  throw BESSyntaxUserError(err, __FILE__, __LINE__);
226  }
227  if (child_value.empty()) {
228  string err = action + " command: constraint element " + "missing value";
229  throw BESSyntaxUserError(err, __FILE__, __LINE__);
230  }
231  if (have_constraint) {
232  string err = action + " command: container element " + "contains multiple constraint elements";
233  throw BESSyntaxUserError(err, __FILE__, __LINE__);
234  }
235  have_constraint = true;
236  _constraints[name] = child_value;
237  }
238  else if (child_name == "dap4constraint") {
239  if (child_props.size()) {
240  string err = action + " command: constraint element " + "should not contain properties";
241  throw BESSyntaxUserError(err, __FILE__, __LINE__);
242  }
243  if (child_value.empty()) {
244  string err = action + " command: constraint element " + "missing value";
245  throw BESSyntaxUserError(err, __FILE__, __LINE__);
246  }
247  if (have_dap4constraint) {
248  string err = action + " command: container element " + "contains multiple constraint elements";
249  throw BESSyntaxUserError(err, __FILE__, __LINE__);
250  }
251  have_dap4constraint = true;
252  _dap4constraints[name] = child_value;
253  }
254  else if (child_name == "dap4function") {
255  if (child_props.size()) {
256  string err = action + " command: dap4_function element " + "should not contain properties";
257  throw BESSyntaxUserError(err, __FILE__, __LINE__);
258  }
259  if (child_value.empty()) {
260  string err = action + " command: dap4_function element " + "missing value";
261  throw BESSyntaxUserError(err, __FILE__, __LINE__);
262  }
263  if (have_dap4function) {
264  string err = action + " command: container element " + "contains multiple dap4_function elements";
265  throw BESSyntaxUserError(err, __FILE__, __LINE__);
266  }
267  have_dap4function = true;
268  _dap4functions[name] = child_value;
269  }
270  else if (child_name == "attributes") {
271  if (child_props.size()) {
272  string err = action + " command: attributes element " + "should not contain properties";
273  throw BESSyntaxUserError(err, __FILE__, __LINE__);
274  }
275  if (child_value.empty()) {
276  string err = action + " command: attributes element " + "missing value";
277  throw BESSyntaxUserError(err, __FILE__, __LINE__);
278  }
279  if (have_attributes) {
280  string err = action + " command: container element " + "contains multiple attributes elements";
281  throw BESSyntaxUserError(err, __FILE__, __LINE__);
282  }
283  have_attributes = true;
284  _attributes[name] = child_value;
285  }
286 
287  // get the next child element
288  props.clear();
289  child_name.clear();
290  child_value.clear();
291  child_node = BESXMLUtils::GetNextChild(child_node, child_name, child_value, props);
292  }
293 }
294 
306 void BESXMLDefineCommand::handle_aggregate_element(const string &action, xmlNode */*node*/, const string &/*value*/,
307  map<string, string> &props)
308 {
309  string handler = props["handler"];
310  string cmd = props["cmd"];
311  if (handler.empty()) {
312  string err = action + " command: must specify aggregation handler";
313  throw BESSyntaxUserError(err, __FILE__, __LINE__);
314  }
315  if (cmd.empty()) {
316  string err = action + " command: must specify aggregation cmd";
317  throw BESSyntaxUserError(err, __FILE__, __LINE__);
318  }
319 
320  d_xmlcmd_dhi.data[AGG_HANDLER] = handler;
321  d_xmlcmd_dhi.data[AGG_CMD] = cmd;
322  d_cmd_log_info += " aggregate using " + handler + " by " + cmd;
323 }
324 
328 {
329  vector<string>::iterator i = _containers.begin();
330  vector<string>::iterator e = _containers.end();
331  for (; i != e; i++) {
332  // look for the specified container
333  BESContainer *c = 0;
334 
335  // first see if a particular store is being used
336  string store = _stores[(*i)];
337  if (!store.empty()) {
338  BESContainerStorage *cs = BESContainerStorageList::TheList()->find_persistence(store);
339  if (cs) c = cs->look_for((*i));
340  }
341  else {
342  c = BESContainerStorageList::TheList()->look_for((*i));
343  }
344 
345  // I don't understand this test. If 'c' is null, then the code below will
346  // fail. If 'c' is not null, then what does it matter that the
347  // BES.Container.Persistence is set to 'nice' - dereferencing 'c' is still
348  // not going to work. I'm changing the test to be 'if (c == 0)...'.
349  // jhrg 10/23/15
350  //
351  // if (!c && BESContainerStorageList::TheList()->isnice() == false) {
352 
353  if (c == 0)
354  throw BESSyntaxUserError(string("Could not find the container ") + (*i), __FILE__, __LINE__);
355 
356  // What use case do we have in which the "default" value of the constraint is not an empty string?
357  string constraint = _constraints[(*i)];
358  if (constraint.empty()) constraint = _default_constraint;
359  c->set_constraint(constraint);
360 
361  // What use case do we have in which the "default" value of the dap4constraint is not an empty string?
362  string dap4constraint = _dap4constraints[(*i)];
363  if (dap4constraint.empty()) dap4constraint = _default_dap4_constraint;
364  c->set_dap4_constraint(dap4constraint);
365 
366  // What use case do we have in which the "default" value of the dap4function is not an empty string?
367  string function = _dap4functions[(*i)];
368  if (function.empty()) function = _default_dap4_function;
369  c->set_dap4_function(function);
370 
371  string attrs = _attributes[(*i)];
372  c->set_attributes(attrs);
373  d_xmlcmd_dhi.containers.push_back(c);
374 
375  BESDEBUG("xml", "BESXMLDefineCommand::prep_request() - define using container: " << endl << *c << endl);
376  }
377 }
378 
386 void BESXMLDefineCommand::dump(ostream &strm) const
387 {
388  strm << BESIndent::LMarg << "BESXMLDefineCommand::dump - (" << (void *) this << ")" << endl;
389  BESIndent::Indent();
390  BESXMLCommand::dump(strm);
391  BESIndent::UnIndent();
392 }
393 
395 BESXMLDefineCommand::CommandBuilder(const BESDataHandlerInterface &base_dhi)
396 {
397  return new BESXMLDefineCommand(base_dhi);
398 }
399 
provides persistent storage for data storage information represented by a container.
static xmlNode * GetFirstChild(xmlNode *node, string &child_name, string &child_value, map< string, string > &child_props)
get the first element child node for the given node
Definition: BESXMLUtils.cc:133
virtual void dump(ostream &strm) const
dumps information about this object
virtual void dump(ostream &strm) const
dumps information about this object
virtual BESContainerStorage * find_persistence(const string &persist_name)
find the persistence store with the given name
static xmlNode * GetNextChild(xmlNode *child_node, string &next_name, string &next_value, map< string, string > &next_props)
get the next element child node after the given child node
Definition: BESXMLUtils.cc:160
static void GetNodeInfo(xmlNode *node, string &name, string &value, map< string, string > &props)
get the name, value if any, and any properties for the specified node
Definition: BESXMLUtils.cc:101
virtual BESContainer * look_for(const string &sym_name)=0
looks for a container in this persistent store
error thrown if there is a user syntax error in the request or any other user error
virtual void parse_request(xmlNode *node)
parse a show command. No properties or children elements
virtual void set_response()
The request has been parsed, use the command action name to set the response handler.
virtual void prep_request()
prepare the define command by making sure the containers exist
void set_constraint(const string &s)
set the constraint for this container
Definition: BESContainer.h:104
void set_dap4_constraint(const string &s)
set the constraint for this container
Definition: BESContainer.h:113
void set_attributes(const string &attrs)
set desired attributes for this container
Definition: BESContainer.h:151
void set_dap4_function(const string &s)
set the constraint for this container
Definition: BESContainer.h:122
Structure storing information used by the BES to handle the request.
virtual BESContainer * look_for(const string &sym_name)
look for the specified container information in the list of persistent stores.
map< string, string > data
the map of string data that will be required for the current request.
A container is something that holds data. I.E. a netcdf file or a database entry.
Definition: BESContainer.h:60
string action
the response object requested, e.g. das, dds
std::string d_cmd_log_info
Used only for the log.
Definition: BESXMLCommand.h:62