libdap Updated for version 3.20.9
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
63const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
64const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
65
66const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
67
68const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
69
70const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
71
72using namespace std;
73
74namespace libdap {
75
76void
77DMR::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_kb = dmr.d_max_response_size_kb;
98
99 d_ce_empty = dmr.d_ce_empty;
100
101 // Deep copy, using ptr_duplicate()
102 // d_root can only be a D4Group, so the thing returned by ptr_duplicate() must be a D4Group.
103 d_root = static_cast<D4Group*>(dmr.d_root->ptr_duplicate());
104 DBG(cerr << "dmr.d_root: " << dmr.d_root << endl);
105 DBG(cerr << "d_root (from ptr_dup(): " << d_root << endl);
106
107 //d_root = static_cast<D4Group*>(dmr.d_factory->NewVariable(dods_group_c, dmr.d_root->name()));
108}
109
122DMR::DMR(D4BaseTypeFactory *factory, const string &name)
123 : d_factory(factory), d_name(name), d_filename(""),
124 d_dap_major(4), d_dap_minor(0),
125 d_dmr_version("1.0"), d_request_xml_base(""),
126 d_namespace(c_dap40_namespace), d_max_response_size_kb(0),
127 d_ce_empty(false),d_root(0)
128{
129 // sets d_dap_version string and the two integer fields too
130 set_dap_version("4.0");
131}
132
154 : d_factory(factory), d_name(dds.get_dataset_name()),
155 d_filename(dds.filename()), d_dap_major(4), d_dap_minor(0),
156 d_dmr_version("1.0"), d_request_xml_base(""),
157 d_namespace(c_dap40_namespace), d_max_response_size_kb(0),d_ce_empty(false), d_root(0)
158{
159 // sets d_dap_version string and the two integer fields too
160 set_dap_version("4.0");
161
162 build_using_dds(dds);
163#if 0
164 for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
165 BaseType *new_var = (*i)->transform_to_dap4(root() /*group*/, root() /*container*/);
166 // If the variable being transformed is a Grid,
167 // then Grid::transform_to_dap4() will add all the arrays to the
168 // container (root() in this case) and return null, indicating that
169 // this code does not need to do anything to add the transformed variable.
170 if (new_var)
171 root()->add_var_nocopy(new_var);
172 }
173
174 // Now copy the global attributes
176#endif
177}
178
186 : d_factory(0), d_name(""), d_filename(""), d_dap_major(4), d_dap_minor(0),
187 d_dap_version("4.0"), d_dmr_version("1.0"), d_request_xml_base(""),
188 d_namespace(c_dap40_namespace), d_max_response_size_kb(0), d_ce_empty(false),d_root(0)
189{
190 // sets d_dap_version string and the two integer fields too
191 set_dap_version("4.0");
192}
193
195DMR::DMR(const DMR &rhs) : DapObj()
196{
197 m_duplicate(rhs);
198}
199
204{
205#if 1
206 delete d_root;
207#endif
208}
209
210DMR &
211DMR::operator=(const DMR &rhs)
212{
213 if (this == &rhs)
214 return *this;
215
216 m_duplicate(rhs);
217
218 return *this;
219}
220
230{
231 set_name(dds.get_dataset_name());
232 set_filename(dds.filename());
233
234 D4Group *root_grp = root();
235 for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
236 BaseType *d4_var = root()->var((*i)->name());
237 // Don't add duplicate variables. We have to make this check
238 // because some of the child variables may add arrays
239 // to the root object. For example, this happens in
240 // Grid with the Map Arrays - ndp - 05/08/17
241 if(!d4_var){
242 // no variable of this name is in the root group at this point. Add it.
243 DBG(cerr << __func__ << "() - Transforming top level variable: " <<
244 " (" << (*i)->type_name() << ":'" << (*i)->name() << "':"<<(void *)(*i) <<
245 ") (root:"<< root_grp << ")"<< endl; );
246 (*i)->transform_to_dap4(root_grp, root_grp);
247 DBG(cerr << __func__ << "() - top level variable: '" <<
248 (*i)->name() << "' (type:" << (*i)->type_name() << ") Transformed"<< endl; );
249 }
250 else {
251 DBG(cerr << __func__ << "() - Skipping variable: " <<
252 d4_var->type_name() << " " << d4_var->name() << " because a variable with" <<
253 " this name already exists in the root group." << endl; );
254 }
255 }
256
257 // Now copy the global attributes
259}
260
261#if 0
273DDS *DMR::getDDS(DMR &dmr)
274{
275 DBG( cerr << __func__ << "() - BEGIN" << endl);
276 D4Group *root = dmr.root();
277
278 BaseTypeFactory *btf = new BaseTypeFactory();
279 DDS *dds = new DDS(btf, dmr.name());
280 dds->filename(dmr.filename());
281 AttrTable *dds_at = &(dds->get_attr_table());
282
283 // Now copy the global attributes
284 // D4Attributes::load_AttrTable(dds_at,root->attributes());
285
286 // TODO Make this a unique_ptr<> and let the compiler delete it. jhrg 6/17/19
287 vector<BaseType *> *top_vars = root->transform_to_dap2(dds_at, true);
288 vector<BaseType *>::iterator vIter = top_vars->begin();
289 vector<BaseType *>::iterator vEnd = top_vars->end();
290 for (; vIter != vEnd; vIter++) {
291 dds->add_var_nocopy(*vIter);
292 }
293 delete top_vars;
294
295#if 0
296 set<string> shared_dim_candidates;
297
298 vector<BaseType *> dropped_vars;
299 for (D4Group::Vars_iter i = root->var_begin(), e = root->var_end(); i != e; ++i)
300 {
301 DBG( cerr << __func__ << "() - Processing top level variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to DDS." << endl; );
302 vector<BaseType *> *new_vars = (*i)->transform_to_dap2(&(dds->get_attr_table()));
303 if(new_vars!=0) {
304 vector<BaseType*>::iterator vIter = new_vars->begin();
305 vector<BaseType*>::iterator end = new_vars->end();
306 for(; vIter!=end; vIter++ ) {
307 BaseType *new_var = (*vIter);
308 DBG( cerr << __func__ << "() - Adding variable name: '"<< new_var->name() << "' " <<
309 "type: " << new_var->type() << " " <<
310 "type_name: " << new_var->type_name() << " to DDS." << endl; );
311 dds->add_var_nocopy(new_var);
312 Grid *grid = dynamic_cast <Grid *>(new_var);
313 if(grid) {
314 Grid::Map_iter m = grid->map_begin();
315 for(; m != grid->map_end(); m++) {
316 shared_dim_candidates.insert((*m)->name());
317 }
318 }
319 (*vIter) = 0;
320 }
321 delete new_vars;
322 }
323 else {
324 DBG( cerr << __func__ << "Adding variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to drop list." << endl; );
325 dropped_vars.push_back((*i));
326 }
327 }
328 AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_vars);
329 if(dv_table) {
330 DBG( cerr << __func__ << "() - Adding dropped variable AttrTable." << endl);
331 dds_at->append_container(dv_table,dv_table->get_name());
332 }
333
334 // Get all the child groups.
335 D4Group::groupsIter gIter = root->grp_begin();
336 D4Group::groupsIter gEnd = root->grp_end();
337 for(; gIter!=gEnd; gIter++) {
338 D4Group *grp = *gIter;
339 DBG( cerr << __func__ << "() - Processing D4Group " << grp->name() << endl);
340 vector<BaseType *> *d2_vars = grp->transform_to_dap2(dds_at);
341 if(d2_vars) {
342 DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variables." << endl);
343 vector<BaseType *>::iterator vIter = d2_vars->begin();
344 vector<BaseType *>::iterator vEnd = d2_vars->end();
345 for(; vIter!=vEnd; vIter++) {
346 DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variable: " << (*vIter)->name() << endl);
347 dds->add_var(*vIter);
348 }
349 }
350 }
351#endif
352
353 DBG( cerr << __func__ << "() - END" << endl);
354 return dds;
355}
356#endif
357
373DDS *
375{
376#if 0
377 return DMR::getDDS(*this);
378#else
379 DBG( cerr << __func__ << "() - BEGIN" << endl);
380
381#if 0
382 BaseTypeFactory *btf = new BaseTypeFactory();
383#endif
384 BaseTypeFactory btf;
385 DDS *dds = new DDS(&btf, name());
386 dds->filename(filename());
387
388 // Now copy the global attributes
389 // TODO Make this a unique_ptr<> and let the compiler delete it. jhrg 6/17/19
390 vector<BaseType *> *top_vars = root()->transform_to_dap2(&(dds->get_attr_table())/*, true*/);
391 for (vector<BaseType *>::iterator i = top_vars->begin(), e = top_vars->end(); i != e; i++) {
392 dds->add_var_nocopy(*i);
393 }
394 delete top_vars;
395
396 DBG( cerr << __func__ << "() - END" << endl);
397
398 dds->set_factory(0);
399 return dds;
400#endif
401}
402
409D4Group *
411{
412 if (!d_root) d_root = static_cast<D4Group*>(d_factory->NewVariable(dods_group_c, "/"));
413 return d_root;
414}
415
421void
422DMR::set_dap_version(const string &v)
423{
424 istringstream iss(v);
425
426 int major = -1, minor = -1;
427 char dot;
428 if (!iss.eof() && !iss.fail())
429 iss >> major;
430 if (!iss.eof() && !iss.fail())
431 iss >> dot;
432 if (!iss.eof() && !iss.fail())
433 iss >> minor;
434
435 if (major == -1 || minor == -1 or dot != '.')
436 throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
437
438 d_dap_version = v;
439
440 d_dap_major = major;
441 d_dap_minor = minor;
442
443 // Now set the related XML constants. These might be overwritten if
444 // the DMR instance is being built from a document parse, but if it's
445 // being constructed by a server the code to generate the XML document
446 // needs these values to match the DAP version information.
447 switch (d_dap_major) {
448 case 4:
449 d_namespace = c_dap40_namespace;
450 break;
451 default:
452 d_namespace = "";
453 break;
454 }
455}
456
468//[[deprecated("Use DMR::request_size_kb()")]]
469long DMR::request_size(bool constrained)
470{
471 return d_root->request_size(constrained);
472}
473
484uint64_t DMR::request_size_kb(bool constrained)
485{
486 return d_root->request_size_kb(constrained);
487}
488
489
490
491
499void
500DMR::print_dap4(XMLWriter &xml, bool constrained)
501{
502 if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
503 throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
504
505#if 0
506 // Reintroduce these if they are really useful. jhrg 4/15/13
507 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
508 (const xmlChar*) c_xml_namespace.c_str()) < 0)
509 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
510
511 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
512 < 0)
513 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
514
515 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
516 (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
517 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
518#endif
519
520 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*) get_namespace().c_str()) < 0)
521 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
522
523 if (!request_xml_base().empty()) {
524 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
525 (const xmlChar*)request_xml_base().c_str()) < 0)
526 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
527 }
528
529 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion", (const xmlChar*)dap_version().c_str()) < 0)
530 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
531
532 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*)dmr_version().c_str()) < 0)
533 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
534
535 if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
536 throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
537
538 root()->print_dap4(xml, constrained);
539
540 if (xmlTextWriterEndElement(xml.get_writer()) < 0)
541 throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
542}
543
544
552void
553DMR::dump(ostream &strm) const
554{
555 strm << DapIndent::LMarg << "DMR::dump - ("
556 << (void *)this << ")" << endl ;
557 DapIndent::Indent() ;
558 strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
559 strm << DapIndent::LMarg << "name: " << d_name << endl ;
560 strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
561 strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
562 strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
563
564 DapIndent::UnIndent() ;
565}
566
567} // namespace libdap
Contains the attributes for a dataset.
Definition: AttrTable.h:143
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
The basic data type for the DODS DAP types.
Definition: BaseType.h:118
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:379
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:320
virtual D4Attributes * attributes()
Definition: BaseType.cc:599
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:216
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
Vars_iter var_end()
Definition: Constructor.cc:364
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Definition: Constructor.cc:432
Vars_iter var_begin()
Definition: Constructor.cc:356
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
virtual BaseType * NewVariable(Type t, const string &name) const
groupsIter grp_begin()
Get an iterator to the start of the values.
Definition: D4Group.h:112
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:439
groupsIter grp_end()
Get an iterator to the end of the values.
Definition: D4Group.h:115
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
Transform the D4Group's variables to DAP2 variables.
Definition: D4Group.cc:692
long request_size(bool constrained)
Definition: D4Group.cc:402
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: D4Group.cc:603
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:644
string filename() const
Definition: DDS.cc:390
virtual AttrTable & get_attr_table()
Definition: DDS.cc:375
BaseTypeFactory * set_factory(BaseTypeFactory *factory)
Definition: DDS.h:253
string get_dataset_name() const
Definition: DDS.cc:359
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:830
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:842
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:617
virtual DDS * getDDS()
Build a DDS from a DMR.
Definition: DMR.cc:374
std::string name() const
Definition: DMR.h:119
void set_dap_version(const std::string &version_string)
Definition: DMR.cc:422
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 dump(std::ostream &strm) const
dumps information about this object
Definition: DMR.cc:553
virtual ~DMR()
Definition: DMR.cc:203
virtual void build_using_dds(DDS &dds)
Definition: DMR.cc:229
D4Group * root()
Definition: DMR.cc:410
long request_size(bool constrained)
Get the estimated response size, in kilobytes.
Definition: DMR.cc:469
uint64_t request_size_kb(bool constrained)
Compute the estimated response size, in kilobytes.
Definition: DMR.cc:484
std::string filename() const
Definition: DMR.h:136
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: DMR.cc:500
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
Definition: AlarmHandler.h:36