bes  Updated for version 3.20.10
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  // HYRAX-316, the empty constraint now is legal. It is used to transfer the whole file.
250 #if 0
251  if (child_value.empty()) {
252  string err = action + " command: constraint element " + "missing value";
253  throw BESSyntaxUserError(err, __FILE__, __LINE__);
254  }
255 #endif
256  if (have_constraint) {
257  string err = action + " command: container element " + "contains multiple constraint elements";
258  throw BESSyntaxUserError(err, __FILE__, __LINE__);
259  }
260  have_constraint = true;
261  container_constraints[name] = child_value;
262  }
263  else if (child_name == "dap4constraint") {
264  if (child_props.size()) {
265  string err = action + " command: constraint element " + "should not contain properties";
266  throw BESSyntaxUserError(err, __FILE__, __LINE__);
267  }
268  // HYRAX-316, the empty constraint now is legal. It is used to transfer the whole file.
269 #if 0
270  if (child_value.empty()) {
271  string err = action + " command: constraint element " + "missing value";
272  throw BESSyntaxUserError(err, __FILE__, __LINE__);
273  }
274 #endif
275  if (have_dap4constraint) {
276  string err = action + " command: container element " + "contains multiple constraint elements";
277  throw BESSyntaxUserError(err, __FILE__, __LINE__);
278  }
279  have_dap4constraint = true;
280  container_dap4constraints[name] = child_value;
281  }
282  else if (child_name == "dap4function") {
283  if (child_props.size()) {
284  string err = action + " command: dap4_function element " + "should not contain properties";
285  throw BESSyntaxUserError(err, __FILE__, __LINE__);
286  }
287  if (child_value.empty()) {
288  string err = action + " command: dap4_function element " + "missing value";
289  throw BESSyntaxUserError(err, __FILE__, __LINE__);
290  }
291  if (have_dap4function) {
292  string err = action + " command: container element " + "contains multiple dap4_function elements";
293  throw BESSyntaxUserError(err, __FILE__, __LINE__);
294  }
295  have_dap4function = true;
296  container_dap4functions[name] = child_value;
297  }
298  else if (child_name == "attributes") {
299  if (child_props.size()) {
300  string err = action + " command: attributes element " + "should not contain properties";
301  throw BESSyntaxUserError(err, __FILE__, __LINE__);
302  }
303  if (child_value.empty()) {
304  string err = action + " command: attributes element " + "missing value";
305  throw BESSyntaxUserError(err, __FILE__, __LINE__);
306  }
307  if (have_attributes) {
308  string err = action + " command: container element " + "contains multiple attributes elements";
309  throw BESSyntaxUserError(err, __FILE__, __LINE__);
310  }
311  have_attributes = true;
312  container_attributes[name] = child_value;
313  }
314 
315  // get the next child element
316  props.clear();
317  child_name.clear();
318  child_value.clear();
319  child_node = BESXMLUtils::GetNextChild(child_node, child_name, child_value, props);
320  }
321 }
322 
323 #if 0
337 void BESXMLDefineCommand::handle_aggregate_element(const string &action, xmlNode */*node*/, const string &/*value*/,
338  map<string, string> &props)
339 {
340  string handler = props["handler"];
341  string cmd = props["cmd"];
342  if (handler.empty()) {
343  string err = action + " command: must specify aggregation handler";
344  throw BESSyntaxUserError(err, __FILE__, __LINE__);
345  }
346  if (cmd.empty()) {
347  string err = action + " command: must specify aggregation cmd";
348  throw BESSyntaxUserError(err, __FILE__, __LINE__);
349  }
350 
351  d_xmlcmd_dhi.data[AGG_HANDLER] = handler;
352  d_xmlcmd_dhi.data[AGG_CMD] = cmd;
353  d_cmd_log_info += " aggregate using " + handler + " by " + cmd;
354 }
355 #endif
356 
357 
367 {
368  vector<string>::iterator i = container_names.begin();
369  vector<string>::iterator e = container_names.end();
370  for (; i != e; i++) {
371  // look for the specified container
372  BESContainer *c = 0;
373 
374  // Is a particular store is being used - this is container store
375  // not the definition store. If no store is named, search them all.
376  string store = container_store_names[(*i)];
377  if (!store.empty()) {
378  BESContainerStorage *cs = BESContainerStorageList::TheList()->find_persistence(store);
379  if (cs) c = cs->look_for((*i));
380  }
381  else {
382  c = BESContainerStorageList::TheList()->look_for((*i));
383  }
384 
385  if (c == 0)
386  throw BESSyntaxUserError(string("Could not find the container ") + (*i), __FILE__, __LINE__);
387 
388  // What use case do we have in which the "default" value of the constraint is not an empty string?
389  string constraint = container_constraints[(*i)];
390  if (constraint.empty()) constraint = _default_constraint;
391  c->set_constraint(constraint);
392 
393  // What use case do we have in which the "default" value of the dap4constraint is not an empty string?
394  string dap4constraint = container_dap4constraints[(*i)];
395  if (dap4constraint.empty()) dap4constraint = _default_dap4_constraint;
396  c->set_dap4_constraint(dap4constraint);
397 
398  // What use case do we have in which the "default" value of the dap4function is not an empty string?
399  string function = container_dap4functions[(*i)];
400  if (function.empty()) function = _default_dap4_function;
401  c->set_dap4_function(function);
402 
403  string attrs = container_attributes[(*i)];
404  c->set_attributes(attrs);
405  d_xmlcmd_dhi.containers.push_back(c);
406 
407  BESDEBUG("xml", "BESXMLDefineCommand::prep_request() - define using container: " << endl << *c << endl);
408  }
409 }
410 
418 void BESXMLDefineCommand::dump(ostream &strm) const
419 {
420  strm << BESIndent::LMarg << "BESXMLDefineCommand::dump - (" << (void *) this << ")" << endl;
421  BESIndent::Indent();
422  BESXMLCommand::dump(strm);
423  BESIndent::UnIndent();
424 }
425 
427 BESXMLDefineCommand::CommandBuilder(const BESDataHandlerInterface &base_dhi)
428 {
429  return new BESXMLDefineCommand(base_dhi);
430 }
431 
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:109
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:143
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:170