libdap  Updated for version 3.20.1
libdap4 is an implementation of OPeNDAP's DAP protocol.
DMR.cc
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
4 // Access Protocol.
5 
6 // Copyright (c) 2013 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 #include "config.h"
26 
27 #ifdef WIN32
28 #include <io.h>
29 #include <process.h>
30 #include <fstream>
31 #else
32 #include <unistd.h> // for alarm and dup
33 #include <sys/wait.h>
34 #endif
35 
36 #include <cassert>
37 
38 #include <iostream>
39 #include <sstream>
40 
41 //#define DODS_DEBUG
42 //#define DODS_DEBUG2
43 
44 #include "D4Group.h"
45 #include "BaseType.h"
46 #include "Array.h"
47 #include "Grid.h"
48 #include "DMR.h"
49 #include "XMLWriter.h"
50 #include "D4BaseTypeFactory.h"
51 #include "D4Attributes.h"
52 
53 #include "DDS.h" // Included so DMRs can be built using a DDS for 'legacy' handlers
54 
55 #include "debug.h"
56 #include "DapIndent.h"
57 
63 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
64 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
65 
66 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
67 
68 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
69 
70 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
71 
72 using namespace std;
73 
74 namespace libdap {
75 
76 void
77 DMR::m_duplicate(const DMR &dmr)
78 {
79  // This is needed because we use the factory to make a new instance of the root group
80  assert(dmr.OK());
81 
82  d_factory = dmr.d_factory; // Shallow copy here
83 
84  d_name = dmr.d_name;
85  d_filename = dmr.d_filename;
86 
87  d_dap_major = dmr.d_dap_major;
88  d_dap_minor = dmr.d_dap_minor;
89  d_dap_version = dmr.d_dap_version; // String version of the protocol
90 
91  d_dmr_version = dmr.d_dmr_version;
92 
93  d_request_xml_base = dmr.d_request_xml_base;
94 
95  d_namespace = dmr.d_namespace;
96 
97  d_max_response_size = dmr.d_max_response_size;
98 
99  // Deep copy, using ptr_duplicate()
100  // d_root can only be a D4Group, so the thing returned by ptr_duplicate() must be a D4Group.
101  d_root = static_cast<D4Group*>(dmr.d_root->ptr_duplicate());
102  DBG(cerr << "dmr.d_root: " << dmr.d_root << endl);
103  DBG(cerr << "d_root (from ptr_dup(): " << d_root << endl);
104 
105  //d_root = static_cast<D4Group*>(dmr.d_factory->NewVariable(dods_group_c, dmr.d_root->name()));
106 }
107 
120 DMR::DMR(D4BaseTypeFactory *factory, const string &name)
121  : d_factory(factory), d_name(name), d_filename(""),
122  d_dap_major(4), d_dap_minor(0),
123  d_dmr_version("1.0"), d_request_xml_base(""),
124  d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
125 {
126  // sets d_dap_version string and the two integer fields too
127  set_dap_version("4.0");
128 }
129 
151  : d_factory(factory), d_name(dds.get_dataset_name()),
152  d_filename(dds.filename()), d_dap_major(4), d_dap_minor(0),
153  d_dmr_version("1.0"), d_request_xml_base(""),
154  d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
155 {
156  // sets d_dap_version string and the two integer fields too
157  set_dap_version("4.0");
158 
159  build_using_dds(dds);
160 #if 0
161  for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
162  BaseType *new_var = (*i)->transform_to_dap4(root() /*group*/, root() /*container*/);
163  // If the variable being transformed is a Grid,
164  // then Grid::transform_to_dap4() will add all the arrays to the
165  // container (root() in this case) and return null, indicating that
166  // this code does not need to do anything to add the transformed variable.
167  if (new_var)
168  root()->add_var_nocopy(new_var);
169  }
170 
171  // Now copy the global attributes
173 #endif
174 }
175 
183  : d_factory(0), d_name(""), d_filename(""), d_dap_major(4), d_dap_minor(0),
184  d_dap_version("4.0"), d_dmr_version("1.0"), d_request_xml_base(""),
185  d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
186 {
187  // sets d_dap_version string and the two integer fields too
188  set_dap_version("4.0");
189 }
190 
192 DMR::DMR(const DMR &rhs) : DapObj()
193 {
194  m_duplicate(rhs);
195 }
196 
201 {
202 #if 1
203  delete d_root;
204 #endif
205 }
206 
207 DMR &
208 DMR::operator=(const DMR &rhs)
209 {
210  if (this == &rhs)
211  return *this;
212 
213  m_duplicate(rhs);
214 
215  return *this;
216 }
217 
227 {
228  set_name(dds.get_dataset_name());
229  set_filename(dds.filename());
230 
231  D4Group *root_grp = root();
232  for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
233  BaseType *d4_var = root()->var((*i)->name());
234  // Don't add duplicate variables. We have to make this check
235  // because some of the child variables may add arrays
236  // to the root object. For example, this happens in
237  // Grid with the Map Arrays - ndp - 05/08/17
238  if(!d4_var){
239  // no variable of this name is in the root group at this point. Add it.
240  DBG(cerr << __func__ << "() - Transforming top level variable: " <<
241  " (" << (*i)->type_name() << ":'" << (*i)->name() << "':"<<(void *)(*i) <<
242  ") (root:"<< root_grp << ")"<< endl; );
243  (*i)->transform_to_dap4(root_grp, root_grp);
244  DBG(cerr << __func__ << "() - top level variable: '" <<
245  (*i)->name() << "' (type:" << (*i)->type_name() << ") Transformed"<< endl; );
246  }
247  else {
248  DBG(cerr << __func__ << "() - Skipping variable: " <<
249  d4_var->type_name() << " " << d4_var->name() << " because a variable with" <<
250  " this name already exists in the root group." << endl; );
251  }
252  }
253 
254  // Now copy the global attributes
256 }
257 
258 #if 1
259 
270 DDS *DMR::getDDS(DMR &dmr)
271 {
272  DBG( cerr << __func__ << "() - BEGIN" << endl;);
273  D4Group *root = dmr.root();
274 
275  BaseTypeFactory *btf = new BaseTypeFactory();
276  DDS *dds = new DDS(btf, dmr.name());
277  dds->filename(dmr.filename());
278  AttrTable *dds_at = &(dds->get_attr_table());
279 
280  // Now copy the global attributes
281  // D4Attributes::load_AttrTable(dds_at,root->attributes());
282 
283  vector<BaseType *> *top_vars = root->transform_to_dap2(dds_at, true);
284 
285  vector<BaseType *>::iterator vIter = top_vars->begin();
286  vector<BaseType *>::iterator vEnd = top_vars->end();
287  for (; vIter != vEnd; vIter++) {
288  dds->add_var(*vIter);
289  }
290 
291 #if 0
292  set<string> shared_dim_candidates;
293 
294  vector<BaseType *> dropped_vars;
295  for (D4Group::Vars_iter i = root->var_begin(), e = root->var_end(); i != e; ++i)
296  {
297  DBG( cerr << __func__ << "() - Processing top level variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to DDS." << endl; );
298  vector<BaseType *> *new_vars = (*i)->transform_to_dap2(&(dds->get_attr_table()));
299  if(new_vars!=0) {
300  vector<BaseType*>::iterator vIter = new_vars->begin();
301  vector<BaseType*>::iterator end = new_vars->end();
302  for(; vIter!=end; vIter++ ) {
303  BaseType *new_var = (*vIter);
304  DBG( cerr << __func__ << "() - Adding variable name: '"<< new_var->name() << "' " <<
305  "type: " << new_var->type() << " " <<
306  "type_name: " << new_var->type_name() << " to DDS." << endl; );
307  dds->add_var_nocopy(new_var);
308  Grid *grid = dynamic_cast <Grid *>(new_var);
309  if(grid) {
310  Grid::Map_iter m = grid->map_begin();
311  for(; m != grid->map_end(); m++) {
312  shared_dim_candidates.insert((*m)->name());
313  }
314  }
315  (*vIter) = 0;
316  }
317  delete new_vars;
318  }
319  else {
320  DBG( cerr << __func__ << "Adding variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to drop list." << endl; );
321  dropped_vars.push_back((*i));
322  }
323  }
324  AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_vars);
325  if(dv_table) {
326  DBG( cerr << __func__ << "() - Adding dropped variable AttrTable." << endl;);
327  dds_at->append_container(dv_table,dv_table->get_name());
328  }
329 
330  // Get all the child groups.
331  D4Group::groupsIter gIter = root->grp_begin();
332  D4Group::groupsIter gEnd = root->grp_end();
333  for(; gIter!=gEnd; gIter++) {
334  D4Group *grp = *gIter;
335  DBG( cerr << __func__ << "() - Processing D4Group " << grp->name() << endl;);
336  vector<BaseType *> *d2_vars = grp->transform_to_dap2(dds_at);
337  if(d2_vars) {
338  DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variables." << endl;);
339  vector<BaseType *>::iterator vIter = d2_vars->begin();
340  vector<BaseType *>::iterator vEnd = d2_vars->end();
341  for(; vIter!=vEnd; vIter++) {
342  DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variable: " << (*vIter)->name() << endl;);
343  dds->add_var(*vIter);
344  }
345  }
346  }
347 #endif
348 
349  DBG( cerr << __func__ << "() - END" << endl;);
350  return dds;
351 }
352 
353 DDS *DMR::getDDS()
354 {
355  return DMR::getDDS(*this);
356 }
357 #endif
358 
359 D4Group *
361 {
362  if (!d_root) d_root = static_cast<D4Group*>(d_factory->NewVariable(dods_group_c, "/"));
363  return d_root;
364 }
365 
371 void
372 DMR::set_dap_version(const string &v)
373 {
374  istringstream iss(v);
375 
376  int major = -1, minor = -1;
377  char dot;
378  if (!iss.eof() && !iss.fail())
379  iss >> major;
380  if (!iss.eof() && !iss.fail())
381  iss >> dot;
382  if (!iss.eof() && !iss.fail())
383  iss >> minor;
384 
385  if (major == -1 || minor == -1 or dot != '.')
386  throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
387 
388  d_dap_version = v;
389 
390  d_dap_major = major;
391  d_dap_minor = minor;
392 
393  // Now set the related XML constants. These might be overwritten if
394  // the DMR instance is being built from a document parse, but if it's
395  // being constructed by a server the code to generate the XML document
396  // needs these values to match the DAP version information.
397  switch (d_dap_major) {
398  case 4:
399  d_namespace = c_dap40_namespace;
400  break;
401  default:
402  d_namespace = "";
403  break;
404  }
405 }
406 
417 long
418 DMR::request_size(bool constrained)
419 {
420  return d_root->request_size(constrained);
421 }
422 
430 void
431 DMR::print_dap4(XMLWriter &xml, bool constrained)
432 {
433  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
434  throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
435 
436 #if 0
437  // Reintroduce these if they are really useful. jhrg 4/15/13
438  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
439  (const xmlChar*) c_xml_namespace.c_str()) < 0)
440  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
441 
442  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
443  < 0)
444  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
445 
446  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
447  (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
448  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
449 #endif
450 
451  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*) get_namespace().c_str()) < 0)
452  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
453 
454  if (!request_xml_base().empty()) {
455  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
456  (const xmlChar*)request_xml_base().c_str()) < 0)
457  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
458  }
459 
460  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)dap_version().c_str()) < 0)
461  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
462 
463  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*)dmr_version().c_str()) < 0)
464  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
465 
466  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
467  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
468 
469  root()->print_dap4(xml, constrained);
470 
471  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
472  throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
473 }
474 
475 
483 void
484 DMR::dump(ostream &strm) const
485 {
486  strm << DapIndent::LMarg << "DMR::dump - ("
487  << (void *)this << ")" << endl ;
488  DapIndent::Indent() ;
489  strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
490  strm << DapIndent::LMarg << "name: " << d_name << endl ;
491  strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
492  strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
493  strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
494 
495  DapIndent::UnIndent() ;
496 }
497 
498 } // namespace libdap
std::string name() const
Definition: DMR.h:115
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:312
virtual BaseType * var(const string &name, bool exact_match=true, btp_stack *s=0)
btp_stack no longer needed; use back pointers (BaseType::get_parent())
Definition: Constructor.cc:267
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: DMR.cc:431
Contains the attributes for a dataset.
Definition: AttrTable.h:142
D4Group * root()
Definition: DMR.cc:360
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:799
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
STL namespace.
string filename() const
Definition: DDS.cc:387
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Definition: Constructor.cc:432
Map_iter map_end()
Definition: Grid.cc:537
virtual ~DMR()
Definition: DMR.cc:200
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:613
string get_dataset_name() const
Definition: DDS.cc:356
top level DAP object to house generic methods
Definition: AlarmHandler.h:35
A class for software fault reporting.
Definition: InternalErr.h:64
std::string filename() const
Definition: DMR.h:132
Map_iter map_begin()
Returns an iterator referencing the first Map vector.
Definition: Grid.cc:525
long request_size(bool constrained)
Definition: D4Group.cc:407
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual D4BaseTypeFactory * factory()
Definition: DMR.h:123
virtual Type type() const
Returns the type of the class instance.
Definition: BaseType.cc:357
std::string request_xml_base() const
Get the URL that will return this DMR.
Definition: DMR.h:145
long request_size(bool constrained)
Get the estimated response size, in kilo bytes.
Definition: DMR.cc:418
Holds the Grid data type.
Definition: Grid.h:122
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:216
virtual D4Attributes * attributes()
Definition: BaseType.cc:591
void set_dap_version(const std::string &version_string)
Definition: DMR.cc:372
virtual AttrTable & get_attr_table()
Definition: DDS.cc:372
virtual void build_using_dds(DDS &dds)
Definition: DMR.cc:226
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
DAP4 to DAP2 transform.
Definition: D4Group.cc:632
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:811
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap base object for common functionality of libdap objects
Definition: DapObj.h:50
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:371
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: D4Group.cc:572
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
std::string get_namespace() const
Get the namespace associated with the DMR.
Definition: DMR.h:151
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: DMR.cc:484
void add_var(BaseType *bt)
Adds a copy of the variable to the DDS. Using the ptr_duplicate() method, perform a deep copy on the ...
Definition: DDS.cc:586