libdap Updated for version 3.20.10
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#include <memory>
41
42//#define DODS_DEBUG
43//#define DODS_DEBUG2
44
45#include "D4Group.h"
46#include "BaseType.h"
47#include "Array.h"
48#include "Grid.h"
49#include "DMR.h"
50#include "XMLWriter.h"
51#include "D4BaseTypeFactory.h"
52#include "D4Attributes.h"
53
54#include "DDS.h" // Included so DMRs can be built using a DDS for 'legacy' handlers
55
56#include "debug.h"
57#include "DapIndent.h"
58
64const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
65const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
66
67const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
68
69const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
70
71const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
72
73using namespace std;
74
75namespace libdap {
76
77void
78DMR::m_duplicate(const DMR &dmr)
79{
80 // This is needed because we use the factory to make a new instance of the root group
81 assert(dmr.OK());
82
83 d_factory = dmr.d_factory; // Shallow copy here
84
85 d_name = dmr.d_name;
86 d_filename = dmr.d_filename;
87
88 d_dap_major = dmr.d_dap_major;
89 d_dap_minor = dmr.d_dap_minor;
90 d_dap_version = dmr.d_dap_version; // String version of the protocol
91
92 d_dmr_version = dmr.d_dmr_version;
93
94 d_request_xml_base = dmr.d_request_xml_base;
95
96 d_namespace = dmr.d_namespace;
97
98 d_max_response_size_kb = dmr.d_max_response_size_kb;
99
100 d_ce_empty = dmr.d_ce_empty;
101
102 // Deep copy, using ptr_duplicate()
103 // d_root can only be a D4Group, so the thing returned by ptr_duplicate() must be a D4Group.
104 d_root = static_cast<D4Group*>(dmr.d_root->ptr_duplicate());
105 DBG(cerr << "dmr.d_root: " << dmr.d_root << endl);
106 DBG(cerr << "d_root (from ptr_dup(): " << d_root << endl);
107
108 //d_root = static_cast<D4Group*>(dmr.d_factory->NewVariable(dods_group_c, dmr.d_root->name()));
109}
110
123DMR::DMR(D4BaseTypeFactory *factory, const string &name)
124 : d_factory(factory), d_name(name), d_filename(""),
125 d_dap_major(4), d_dap_minor(0),
126 d_dmr_version("1.0"), d_request_xml_base(""),
127 d_namespace(c_dap40_namespace), d_max_response_size_kb(0),
128 d_ce_empty(false),d_root(0)
129{
130 // sets d_dap_version string and the two integer fields too
131 set_dap_version("4.0");
132}
133
155 : d_factory(factory), d_name(dds.get_dataset_name()),
156 d_filename(dds.filename()), d_dap_major(4), d_dap_minor(0),
157 d_dmr_version("1.0"), d_request_xml_base(""),
158 d_namespace(c_dap40_namespace), d_max_response_size_kb(0),d_ce_empty(false), d_root(0)
159{
160 // sets d_dap_version string and the two integer fields too
161 set_dap_version("4.0");
162
163 build_using_dds(dds);
164}
165
173 : d_factory(0), d_name(""), d_filename(""), d_dap_major(4), d_dap_minor(0),
174 d_dap_version("4.0"), d_dmr_version("1.0"), d_request_xml_base(""),
175 d_namespace(c_dap40_namespace), d_max_response_size_kb(0), d_ce_empty(false),d_root(0)
176{
177 // sets d_dap_version string and the two integer fields too
178 set_dap_version("4.0");
179}
180
182DMR::DMR(const DMR &rhs) : DapObj()
183{
184 m_duplicate(rhs);
185}
186
191{
192 delete d_root;
193}
194
195DMR &
196DMR::operator=(const DMR &rhs)
197{
198 if (this == &rhs)
199 return *this;
200 m_duplicate(rhs);
201 return *this;
202}
203
213{
214 set_name(dds.get_dataset_name());
215 set_filename(dds.filename());
216
217 D4Group *root_grp = root();
218 for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
219 BaseType *d4_var = root()->var((*i)->name());
220 // Don't add duplicate variables. We have to make this check
221 // because some of the child variables may add arrays
222 // to the root object. For example, this happens in
223 // Grid with the Map Arrays - ndp - 05/08/17
224 if(!d4_var){
225 // no variable of this name is in the root group at this point. Add it.
226 DBG(cerr << __func__ << "() - Transforming top level variable: " <<
227 " (" << (*i)->type_name() << ":'" << (*i)->name() << "':"<<(void *)(*i) <<
228 ") (root:"<< root_grp << ")"<< endl; );
229 (*i)->transform_to_dap4(root_grp, root_grp);
230 DBG(cerr << __func__ << "() - top level variable: '" <<
231 (*i)->name() << "' (type:" << (*i)->type_name() << ") Transformed"<< endl; );
232 }
233 else {
234 DBG(cerr << __func__ << "() - Skipping variable: " <<
235 d4_var->type_name() << " " << d4_var->name() << " because a variable with" <<
236 " this name already exists in the root group." << endl; );
237 }
238 }
239
240 // Now copy the global attributes
241 root()->attributes()->transform_to_dap4(dds.get_attr_table());
242}
243
259DDS *
261{
262 DBG( cerr << __func__ << "() - BEGIN" << endl);
263
264 BaseTypeFactory btf;
265 DDS *dds = new DDS(&btf, name());
266 dds->filename(filename());
267
268 // Now copy the global attributes
269 // TODO Make this a unique_ptr<> and let the compiler delete it. jhrg 6/17/19
270 // change made jhrg 2/4/22
271#if 1
272 unique_ptr< vector<BaseType *>> top_vars(root()->transform_to_dap2(&(dds->get_attr_table())/*, true*/));
273 for (vector<BaseType *>::iterator i = top_vars->begin(), e = top_vars->end(); i != e; i++) {
274 dds->add_var_nocopy(*i);
275 }
276#else
277 vector<BaseType *> *top_vars = root()->transform_to_dap2(&(dds->get_attr_table())/*, true*/);
278 for (vector<BaseType *>::iterator i = top_vars->begin(), e = top_vars->end(); i != e; i++) {
279 dds->add_var_nocopy(*i);
280 }
281 delete top_vars;
282#endif
283 DBG( cerr << __func__ << "() - END" << endl);
284
285 dds->set_factory(0);
286 return dds;
287}
288
295D4Group *
297{
298 if (!d_root) d_root = static_cast<D4Group*>(d_factory->NewVariable(dods_group_c, "/"));
299 return d_root;
300}
301
307void
308DMR::set_dap_version(const string &v)
309{
310 istringstream iss(v);
311
312 int major = -1, minor = -1;
313 char dot;
314 if (!iss.eof() && !iss.fail())
315 iss >> major;
316 if (!iss.eof() && !iss.fail())
317 iss >> dot;
318 if (!iss.eof() && !iss.fail())
319 iss >> minor;
320
321 if (major == -1 || minor == -1 or dot != '.')
322 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
323
324 d_dap_version = v;
325
326 d_dap_major = major;
327 d_dap_minor = minor;
328
329 // Now set the related XML constants. These might be overwritten if
330 // the DMR instance is being built from a document parse, but if it's
331 // being constructed by a server the code to generate the XML document
332 // needs these values to match the DAP version information.
333 switch (d_dap_major) {
334 case 4:
335 d_namespace = c_dap40_namespace;
336 break;
337 default:
338 d_namespace = "";
339 break;
340 }
341}
342
354//[[deprecated("Use DMR::request_size_kb()")]]
355long DMR::request_size(bool constrained)
356{
357 return d_root->request_size(constrained);
358}
359
370uint64_t DMR::request_size_kb(bool constrained)
371{
372 return d_root->request_size_kb(constrained);
373}
374
375
376
377
385void
386DMR::print_dap4(XMLWriter &xml, bool constrained)
387{
388 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
389 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
390
391#if 0
392 // Reintroduce these if they are really useful. jhrg 4/15/13
393 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
394 (const xmlChar*) c_xml_namespace.c_str()) < 0)
395 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
396
397 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
398 < 0)
399 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
400
401 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
402 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
403 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
404#endif
405
406 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*) get_namespace().c_str()) < 0)
407 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
408
409 if (!request_xml_base().empty()) {
410 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
411 (const xmlChar*)request_xml_base().c_str()) < 0)
412 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
413 }
414
415 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)dap_version().c_str()) < 0)
416 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
417
418 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*)dmr_version().c_str()) < 0)
419 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
420
421 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
422 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
423
424 root()->print_dap4(xml, constrained);
425
426 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
427 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
428}
429
430
438void
439DMR::dump(ostream &strm) const
440{
441 strm << DapIndent::LMarg << "DMR::dump - ("
442 << (void *)this << ")" << endl ;
443 DapIndent::Indent() ;
444 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
445 strm << DapIndent::LMarg << "name: " << d_name << endl ;
446 strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
447 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
448 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
449
450 DapIndent::UnIndent() ;
451}
452
453} // namespace libdap
The basic data type for the DODS DAP types.
Definition BaseType.h:118
virtual D4Attributes * attributes()
Definition BaseType.cc:595
BaseType * var(const string &name, bool exact_match=true, btp_stack *s=nullptr) override
btp_stack no longer needed; use back pointers (BaseType::get_parent())
virtual BaseType * NewVariable(Type t, const string &name) const
uint64_t request_size_kb(bool constrained)
Get the estimated size of a response in kilobytes. This method looks at the variables in the DDS and ...
Definition D4Group.cc:446
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
Transform the D4Group's variables to DAP2 variables.
Definition D4Group.cc:699
long request_size(bool constrained)
Definition D4Group.cc:409
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition D4Group.cc:610
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:567
string filename() const
Definition DDS.cc:316
virtual AttrTable & get_attr_table()
Definition DDS.cc:301
BaseTypeFactory * set_factory(BaseTypeFactory *factory)
Definition DDS.h:244
string get_dataset_name() const
Definition DDS.cc:285
Vars_iter var_begin()
Definition DDS.h:344
Vars_iter var_end()
Return an iterator.
Definition DDS.h:349
void dump(std::ostream &strm) const override
dumps information about this object
Definition DMR.cc:439
virtual DDS * getDDS()
Build a DDS from a DMR.
Definition DMR.cc:260
~DMR() override
Definition DMR.cc:190
std::string name() const
Definition DMR.h:119
void set_dap_version(const std::string &version_string)
Definition DMR.cc:308
std::string get_namespace() const
Get the namespace associated with the DMR.
Definition DMR.h:155
std::string request_xml_base() const
Get the URL that will return this DMR.
Definition DMR.h:149
virtual void build_using_dds(DDS &dds)
Definition DMR.cc:212
D4Group * root()
Definition DMR.cc:296
long request_size(bool constrained)
Get the estimated response size, in kilobytes.
Definition DMR.cc:355
uint64_t request_size_kb(bool constrained)
Compute the estimated response size, in kilobytes.
Definition DMR.cc:370
std::string filename() const
Definition DMR.h:136
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition DMR.cc:386
libdap base object for common functionality of libdap objects
Definition DapObj.h:51
A class for software fault reporting.
Definition InternalErr.h:65
top level DAP object to house generic methods