bes  Updated for version 3.20.6
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 <D4RValue.h>
28 #include <DMR.h>
29 #include <DDS.h>
30 #include <BaseType.h>
31 #include <Str.h>
32 #include <Structure.h>
33 #include <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 
47 void 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 
98 void 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 
174 libdap::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  BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Result Structure attrs: " << endl << dapResult->get_attr_table() << endl);
203 
204  }
205  else {
206  BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - Creating response object called "<< dapResult->name() << endl);
207 
208  libdap::Str *message = new libdap::Str("promoted_message");
209  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.");
210  dapResult->add_var_nocopy(message);
211 
212  // Mark String as read and queue for transmission
213  message->set_read_p(true);
214  message->set_send_p(true);
215 
216  }
217 
218  // Mark dapResult Structure as read and queue for transmission
219  dapResult->set_read_p(true);
220  dapResult->set_send_p(true);
221 
222 
223 
224  BESDEBUG(DEBUG_KEY, "DFU::wrapitup_worker() - END" << endl);
225  return dapResult;
226 
227 }
228 
229 
230 
254 #if 0
255 void wrapitup(int argc, libdap::BaseType *argv[], libdap::DDS &dds, libdap::BaseType **btpp) {
256 
257  std::string wrap_name=dds.get_dataset_name()+"_unwrap";
258 
259  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - BEGIN" << endl);
260 
261  libdap::Structure *dapResult = new libdap::Structure(wrap_name);
262 
263 
264  if(argc>0){
265  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Attempting to return arguments bundled into "<< wrap_name << endl);
266 
267  for(int i=0; i<argc ; i++){
268  libdap::BaseType *bt = argv[i];
269  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Reading "<< bt->name() << endl);
270  bt->read();
271  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Adding a copy of "<< bt->name() << " to " << dapResult->name() << endl);
272 
273  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
274  // This performs a deep copy on bt (ouch!), and we do it because in the current
275  // libdap API, when we delete parent structure the variable will be deleted too.
276  // Because we can't pluck a variable out of a DAP object without deleting it.
277  // @TODO Fix the libdap API to allow this operation without the copy/delete bits.
278  dapResult->add_var_nocopy(bt->ptr_duplicate());
279  // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
280  }
281  libdap::AttrTable &globals = dds.get_attr_table();
282  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Copying Global Attributes" << endl << globals << endl);
283 
284  libdap::AttrTable *newDatasetAttrTable = new libdap::AttrTable(globals);
285  dapResult->set_attr_table(*newDatasetAttrTable);
286  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Result Structure attrs: " << endl << dapResult->get_attr_table() << endl);
287 
288  }
289  else {
290  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - Creating response object called "<< dapResult->name() << endl);
291 
292  libdap::Str *message = new libdap::Str("promoted_message");
293  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.");
294  dapResult->add_var_nocopy(message);
295 
296  // Mark String as read and queue for transmission
297  message->set_read_p(true);
298  message->set_send_p(true);
299 
300  }
301 
302  // Mark dapResult Structure as read and queue for transmission
303  dapResult->set_read_p(true);
304  dapResult->set_send_p(true);
305 
306 
307  *btpp = dapResult;
308 
309  BESDEBUG(DEBUG_KEY, "DFU::wrapitup() - END" << endl);
310 }
311 #endif
312 
313 
314 void function_dap2_wrapitup(int argc, libdap::BaseType *argv[], libdap::DDS &dds, libdap::BaseType **btpp)
315 {
316  BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - BEGIN" << endl);
317 
318  BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - Building argument vector for wrapitup_worker()" << endl);
319  vector<libdap::BaseType*> args;
320  for(int i=0; i< argc; i++){
321  libdap::BaseType *bt = argv[i];
322  BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - Adding argument: "<< bt->name() << endl);
323  args.push_back(bt);
324  }
325 
326  *btpp = wrapitup_worker(args,dds.get_attr_table());
327 
328  BESDEBUG(DEBUG_KEY, "function_dap2_wrapitup() - END (result: "<< (*btpp)->name() << ")" << endl);
329  return;
330 }
331 
332 
333 libdap::BaseType *function_dap4_wrapitup(libdap::D4RValueList *dvl_args, libdap::DMR &dmr){
334 
335  BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - Building argument vector for wrapitup_worker()" << endl);
336  vector<libdap::BaseType*> args;
337  for(unsigned int i=0; i< dvl_args->size(); i++){
338  libdap::BaseType * bt = dvl_args->get_rvalue(i)->value(dmr);
339  BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - Adding argument: "<< bt->name() << endl);
340  args.push_back(bt);
341  }
342 
343 
344  libdap::BaseType *result = wrapitup_worker(args, dmr.root()->get_attr_table());
345 
346  BESDEBUG(DEBUG_KEY, "function_dap4_wrapitup() - END (result: "<< result->name() << ")" << endl);
347  return result;
348 
349 }
350 
BESUtil::endsWith
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition: BESUtil.cc:942