bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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
417
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
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.
void set_constraint(const std::string &s)
set the constraint for this container
void set_dap4_function(const std::string &s)
set the constraint for this container
void set_attributes(const std::string &attrs)
set desired attributes for this container
void set_dap4_constraint(const std::string &s)
set the constraint for this container
Structure storing information used by the BES to handle the request.
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.
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.
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
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
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
STL iterator class.