bes Updated for version 3.20.13
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
48using std::endl;
49using std::string;
50using std::vector;
51using std::ostream;
52using std::map;
53
54BESXMLDefineCommand::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
220void 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
337void 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
418void BESXMLDefineCommand::dump(ostream &strm) const
419{
420 strm << BESIndent::LMarg << "BESXMLDefineCommand::dump - (" << (void *) this << ")" << endl;
421 BESIndent::Indent();
423 BESIndent::UnIndent();
424}
425
427BESXMLDefineCommand::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