bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
DapFunctionUtils.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2
3// This file is part of the BES, a component
4// of the Hyrax Data Server
5
6// Copyright (c) 2016 OPeNDAP, Inc.
7// Authors: Nathan Potter <ndp@opendap.org>
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 OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25#include "config.h"
26
27#include <libdap/D4RValue.h>
28#include <libdap/DMR.h>
29#include <libdap/DDS.h>
30#include <libdap/BaseType.h>
31#include <libdap/Str.h>
32#include <libdap/Structure.h>
33#include <libdap/D4Group.h>
34
35#include <BESDebug.h>
36#include <BESUtil.h>
37#include <BESInternalError.h>
38
39#include "DapFunctionUtils.h"
40
41#define DEBUG_KEY "functions"
42
47void promote_atributes_to_global(libdap::Structure *sourceObj, libdap::DDS *fdds){
48
49 libdap::AttrTable sourceAttrTable = sourceObj->get_attr_table();
50
51 libdap::AttrTable::Attr_iter endIt = sourceAttrTable.attr_end();
52 libdap::AttrTable::Attr_iter it;
53 for (it = sourceAttrTable.attr_begin(); it != endIt; ++it) {
54 std::string childName = sourceAttrTable.get_name(it);
55 bool childIsContainer = sourceAttrTable.is_container(it);
56 BESDEBUG(DEBUG_KEY, "DFU::promote_atributes_to_global() - Processing attribute " << childName << endl );
57 if (childIsContainer) {
58 libdap::AttrTable* pClonedAttrTable = new libdap::AttrTable(*sourceAttrTable.get_attr_table(it));
59 fdds->get_attr_table().append_container(pClonedAttrTable, childName);
60 }
61 else {
62 string type = sourceAttrTable.get_type(it);
63 vector<string>* pAttrTokens = sourceAttrTable.get_attr_vector(it);
64 // append_attr makes a copy of the vector, so we don't have to do so here.
65 fdds->get_attr_table().append_attr(childName, type, pAttrTokens);
66 }
67 }
68}
69
70
98void promote_function_output_structures(libdap::DDS *fdds)
99{
100 BESDEBUG(DEBUG_KEY, "DFU::promote_function_output_structures() - BEGIN" << endl);
101
102 // Dump pointers to the values here temporarily... If we had methods in libdap
103 // that could be used to access the underlying erase() and insert() methods, we
104 // could skip the (maybe expensive) copy operations I use below. What we would
105 // need are ways to delete a Structure/Constructor without calling delete on its
106 // fields and ways to call vector::erase() and vector::insert(). Some of this
107 // exists, but it's not quite enough.
108 //
109 // Proposal: Make it so that the Structure/Constructor has a release() method
110 // that allows you take the members out of the instance with the contract
111 // that "The released members will be deleted deleted so that the
112 // Structure/Constructor object only need to drop it's reference to them".
113 // With that in place we might then be able to manipulate the DAP objects
114 // without excessive copying. We can use add_var_nocopy() to put things in,
115 // and we can use release() to pull things out.
116 //
117 // Assumption: add_var_nocopy() has the contract that the container to which
118 // the var is added will eventually delete the var.
119
120 std::vector<libdap::BaseType *> upVars;
121 std::vector<libdap::BaseType *> droppedContainers;
122 for (libdap::DDS::Vars_citer di = fdds->var_begin(), de = fdds->var_end(); di != de; ++di) {
123
124 libdap::Structure *collection = dynamic_cast<libdap::Structure *>(*di);
125 if (collection && BESUtil::endsWith(collection->name(), "_unwrap")) {
126 BESDEBUG(DEBUG_KEY, "DFU::promote_function_output_structures() - Promoting members of collection '" << collection->name() << "'" << endl);
127 // Once we promote the members we need to drop the parent collection
128 // but we can't do that while we're iterating over its contents
129 // so we'll cache the reference for later.
130 droppedContainers.push_back(collection);
131 // Promote the structures attributes to the DDS AttrTable.
132 promote_atributes_to_global(collection,fdds);
133 // We're going to 'flatten this structure' and return its fields
134 libdap::Structure::Vars_iter vi;
135 for (vi =collection->var_begin(); vi != collection->var_end(); ++vi) {
136 libdap::BaseType *origVar = *vi;
137 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
138 // This performs a deep copy on origVar (ouch!), and we do it because in the current
139 // libdap API, when we delete parent structure the variable will be deleted too.
140 // Because we can't pluck a variable out of a DAP object without deleting it.
141 // @TODO Fix the libdap API to allow this operation without the copy/delete bits.
142 libdap::BaseType *newVar = origVar->ptr_duplicate();
143 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
144 // This ensures that the variable's semantics are consistent
145 // with a top level variable.
146 newVar->set_parent(0);
147 // Add the new variable to the list of stuff to add back to the dataset.
148 upVars.push_back(newVar);
149 }
150 }
151 }
152 // Drop Promoted Containers
153 for(std::vector<libdap::BaseType *>::iterator it=droppedContainers.begin(); it != droppedContainers.end(); ++it) {
154 libdap::BaseType *bt = *it;
155 BESDEBUG(DEBUG_KEY, "DFU::promote_function_output_structures() - Deleting Promoted Collection '" << bt->name() << "' ptr: " << bt << endl);
156 // Delete the Container variable and ALL of it's children.
157 // @TODO Wouldn't it be nice if at this point it had no children? I think so too.
158 fdds->del_var(bt->name());
159 }
160
161 // Add (copied) promoted variables to top-level of DDS
162 for( std::vector<libdap::BaseType *>::iterator it = upVars.begin(); it != upVars.end(); it ++) {
163 libdap::BaseType *bt = *it;
164 BESDEBUG(DEBUG_KEY, "DFU::promote_function_output_structures() - Adding Promoted Variable '" << bt->name() << "' to DDS. ptr: " << bt << endl);
165 fdds->add_var(bt);
166 delete bt;
167 }
168
169 BESDEBUG(DEBUG_KEY, "DFU::promote_function_output_structures() - END" << endl);
170}
171
172
173
174libdap::BaseType *wrapitup_worker(vector<libdap::BaseType*> argv, libdap::AttrTable globals) {
175
176 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - BEGIN" << endl);
177
178 std::string wrap_name="thing_to_unwrap";
179 libdap::Structure *dapResult = new libdap::Structure(wrap_name);
180 int argc = argv.size();
181 if(argc>0){
182 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Attempting to return arguments bundled into "<< wrap_name << endl);
183
184 for(int i=0; i<argc ; i++){
185 libdap::BaseType *bt = argv[i];
186 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Reading "<< bt->name() << endl);
187 bt->read();
188 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Adding a copy of "<< bt->name() << " to " << dapResult->name() << endl);
189
190 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
191 // This performs a deep copy on bt (ouch!), and we do it because in the current
192 // libdap API, when we delete parent structure the variable will be deleted too.
193 // Because we can't pluck a variable out of a DAP object without deleting it.
194 // @TODO Fix the libdap API to allow this operation without the copy/delete bits.
195 dapResult->add_var_nocopy(bt->ptr_duplicate());
196 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
197 }
198 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Copying Global Attributes" << endl << globals << endl);
199
200 libdap::AttrTable *newDatasetAttrTable = new libdap::AttrTable(globals);
201 dapResult->set_attr_table(*newDatasetAttrTable);
202 delete newDatasetAttrTable;
203 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Result Structure attrs: " << endl << dapResult->get_attr_table() << endl);
204
205 }
206 else {
207 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Creating response object called "<< dapResult->name() << endl);
208
209 libdap::Str *message = new libdap::Str("promoted_message");
210 message->set_value("This libdap:Str object should appear at the top level of the response and not as a member of a libdap::Constructor type.");
211 dapResult->add_var_nocopy(message);
212
213 // Mark String as read and queue for transmission
214 message->set_read_p(true);
215 message->set_send_p(true);
216
217 }
218
219 // Mark dapResult Structure as read and queue for transmission
220 dapResult->set_read_p(true);
221 dapResult->set_send_p(true);
222
223
224
225 BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - END" << endl);
226 return dapResult;
227
228}
229
230
231
255#if 0
256void wrapitup(int argc, libdap::BaseType *argv[], libdap::DDS &dds, libdap::BaseType **btpp) {
257
258 std::string wrap_name=dds.get_dataset_name()+"_unwrap";
259
260 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - BEGIN" << endl);
261
262 libdap::Structure *dapResult = new libdap::Structure(wrap_name);
263
264
265 if(argc>0){
266 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Attempting to return arguments bundled into "<< wrap_name << endl);
267
268 for(int i=0; i<argc ; i++){
269 libdap::BaseType *bt = argv[i];
270 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Reading "<< bt->name() << endl);
271 bt->read();
272 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Adding a copy of "<< bt->name() << " to " << dapResult->name() << endl);
273
274 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
275 // This performs a deep copy on bt (ouch!), and we do it because in the current
276 // libdap API, when we delete parent structure the variable will be deleted too.
277 // Because we can't pluck a variable out of a DAP object without deleting it.
278 // @TODO Fix the libdap API to allow this operation without the copy/delete bits.
279 dapResult->add_var_nocopy(bt->ptr_duplicate());
280 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
281 }
282 libdap::AttrTable &globals = dds.get_attr_table();
283 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Copying Global Attributes" << endl << globals << endl);
284
285 libdap::AttrTable *newDatasetAttrTable = new libdap::AttrTable(globals);
286 dapResult->set_attr_table(*newDatasetAttrTable);
287 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Result Structure attrs: " << endl << dapResult->get_attr_table() << endl);
288
289 }
290 else {
291 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Creating response object called "<< dapResult->name() << endl);
292
293 libdap::Str *message = new libdap::Str("promoted_message");
294 message->set_value("This libdap:Str object should appear at the top level of the response and not as a member of a libdap::Constructor type.");
295 dapResult->add_var_nocopy(message);
296
297 // Mark String as read and queue for transmission
298 message->set_read_p(true);
299 message->set_send_p(true);
300
301 }
302
303 // Mark dapResult Structure as read and queue for transmission
304 dapResult->set_read_p(true);
305 dapResult->set_send_p(true);
306
307
308 *btpp = dapResult;
309
310 BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - END" << endl);
311}
312#endif
313
314
315void function_dap2_wrapitup(int argc, libdap::BaseType *argv[], libdap::DDS &dds, libdap::BaseType **btpp)
316{
317 BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - BEGIN" << endl);
318
319 BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - Building argument vector for wrapitup_worker()" << endl);
321 for(int i=0; i< argc; i++){
322 libdap::BaseType *bt = argv[i];
323 BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - Adding argument: "<< bt->name() << endl);
324 args.push_back(bt);
325 }
326
327 *btpp = wrapitup_worker(args,dds.get_attr_table());
328
329 BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - END (result: "<< (*btpp)->name() << ")" << endl);
330 return;
331}
332
333
334libdap::BaseType *function_dap4_wrapitup(libdap::D4RValueList *dvl_args, libdap::DMR &dmr){
335
336 BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - Building argument vector for wrapitup_worker()" << endl);
338 for(unsigned int i=0; i< dvl_args->size(); i++){
339 libdap::BaseType * bt = dvl_args->get_rvalue(i)->value(dmr);
340 BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - Adding argument: "<< bt->name() << endl);
341 args.push_back(bt);
342 }
343
344
345 libdap::BaseType *result = wrapitup_worker(args, dmr.root()->get_attr_table());
346
347 BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - END (result: "<< result->name() << ")" << endl);
348 return result;
349
350}
351
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition BESUtil.cc:837
STL class.