DMR.cc
// -*- mode: c++; c-basic-offset:4 -*-
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.
// Copyright (c) 2013 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
#include "config.h"
#ifdef WIN32
#include <fstream>
#include <io.h>
#include <process.h>
#endif
#include <iostream>
#include <memory>
#include <sstream>
#include "Array.h"
#include "BaseType.h"
#include "D4Attributes.h"
#include "D4BaseTypeFactory.h"
#include "D4Group.h"
#include "DMR.h"
#include "Grid.h"
#include "XMLWriter.h"
#include "DDS.h" // Included so DMRs can be built using a DDS for 'legacy' handlers
#include "DapIndent.h"
#include "debug.h"
using namespace std;
namespace libdap {
void DMR::m_duplicate(const DMR &dmr) {
d_factory = dmr.d_factory; // Shallow copy here
d_name = dmr.d_name;
d_filename = dmr.d_filename;
d_dap_major = dmr.d_dap_major;
d_dap_minor = dmr.d_dap_minor;
d_dap_version = dmr.d_dap_version; // String version of the protocol
d_dmr_version = dmr.d_dmr_version;
d_request_xml_base = dmr.d_request_xml_base;
d_namespace = dmr.d_namespace;
d_max_response_size_kb = dmr.d_max_response_size_kb;
d_ce_empty = dmr.d_ce_empty;
// Deep copy, using ptr_duplicate()
// d_root can only be a D4Group, so the thing returned by ptr_duplicate() must be a D4Group.
d_root = static_cast<D4Group *>(dmr.d_root->ptr_duplicate());
DBG(cerr << "dmr.d_root: " << dmr.d_root << endl);
DBG(cerr << "d_root (from ptr_dup(): " << d_root << endl);
}
DMR::DMR(D4BaseTypeFactory *factory, const string &name) : d_factory(factory), d_name(name) {}
DMR::DMR(D4BaseTypeFactory *factory, DDS &dds)
: d_factory(factory), d_name(dds.get_dataset_name()), d_filename(dds.filename()) {
build_using_dds(dds);
}
DMR::DMR(const DMR &rhs) : DapObj() { m_duplicate(rhs); }
DMR::~DMR() { delete d_root; }
DMR &DMR::operator=(const DMR &rhs) {
if (this == &rhs)
return *this;
m_duplicate(rhs);
return *this;
}
void DMR::build_using_dds(DDS &dds) {
set_name(dds.get_dataset_name());
set_filename(dds.filename());
D4Group *root_grp = root();
for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
BaseType *d4_var = root()->var((*i)->name());
// Don't add duplicate variables. We have to make this check
// because some of the child variables may add arrays
// to the root object. For example, this happens in
// Grid with the Map Arrays - ndp - 05/08/17
if (!d4_var) {
// no variable of this name is in the root group at this point. Add it.
DBG(cerr << __func__ << "() - Transforming top level variable: " << " (" << (*i)->type_name() << ":'"
<< (*i)->name() << "':" << (void *)(*i) << ") (root:" << root_grp << ")" << endl;);
(*i)->transform_to_dap4(root_grp, root_grp);
DBG(cerr << __func__ << "() - top level variable: '" << (*i)->name() << "' (type:" << (*i)->type_name()
<< ") Transformed" << endl;);
} else {
DBG(cerr << __func__ << "() - Skipping variable: " << d4_var->type_name() << " " << d4_var->name()
<< " because a variable with" << " this name already exists in the root group." << endl;);
}
}
// Now copy the global attributes
root()->attributes()->transform_to_dap4(dds.get_attr_table());
}
DDS *DMR::getDDS() {
DBG(cerr << __func__ << "() - BEGIN" << endl);
BaseTypeFactory btf;
DDS *dds = new DDS(&btf, name());
dds->filename(filename());
// Now copy the global attributes
// TODO Make this a unique_ptr<> and let the compiler delete it. jhrg 6/17/19
// change made jhrg 2/4/22
#if 1
unique_ptr<vector<BaseType *>> top_vars(root()->transform_to_dap2(&(dds->get_attr_table()) /*, true*/));
for (vector<BaseType *>::iterator i = top_vars->begin(), e = top_vars->end(); i != e; i++) {
dds->add_var_nocopy(*i);
}
#else
vector<BaseType *> *top_vars = root()->transform_to_dap2(&(dds->get_attr_table()) /*, true*/);
for (vector<BaseType *>::iterator i = top_vars->begin(), e = top_vars->end(); i != e; i++) {
dds->add_var_nocopy(*i);
}
delete top_vars;
#endif
DBG(cerr << __func__ << "() - END" << endl);
dds->set_factory(0);
return dds;
}
D4Group *DMR::root() {
if (!d_root)
d_root = static_cast<D4Group *>(d_factory->NewVariable(dods_group_c, "/"));
return d_root;
}
void DMR::set_dap_version(const string &v) {
istringstream iss(v);
int major = -1, minor = -1;
char dot;
if (!iss.eof() && !iss.fail())
iss >> major;
if (!iss.eof() && !iss.fail())
iss >> dot;
if (!iss.eof() && !iss.fail())
iss >> minor;
if (major == -1 || minor == -1 or dot != '.')
throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
d_dap_version = v;
d_dap_major = major;
d_dap_minor = minor;
// Now set the related XML constants. These might be overwritten if
// the DMR instance is being built from a document parse, but if it's
// being constructed by a server the code to generate the XML document
// needs these values to match the DAP version information.
switch (d_dap_major) {
case 4:
d_namespace = c_dap40_namespace;
break;
default:
d_namespace = "";
break;
}
}
//[[deprecated("Use DMR::request_size_kb()")]]
long DMR::request_size(bool constrained) { return d_root->request_size(constrained); }
uint64_t DMR::request_size_kb(bool constrained) { return d_root->request_size_kb(constrained); }
void DMR::print_dap4(XMLWriter &xml, bool constrained) {
if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar *)"Dataset") < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"xmlns",
(const xmlChar *)get_namespace().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
if (!request_xml_base().empty()) {
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"xml:base",
(const xmlChar *)request_xml_base().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
}
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"dapVersion",
(const xmlChar *)dap_version().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"dmrVersion",
(const xmlChar *)dmr_version().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar *)"name", (const xmlChar *)name().c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
root()->print_dap4(xml, constrained);
if (xmlTextWriterEndElement(xml.get_writer()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
}
bool DMR::is_dap4_projected(std::vector<string> &inventory) {
bool has_dap4 = root()->attributes()->has_dap4_types(root()->FQN(), inventory);
for (const auto var : root()->variables()) {
has_dap4 |= var->is_dap4_projected(inventory);
}
for (const auto grp : root()->groups()) {
has_dap4 |= grp->is_dap4_projected(inventory);
}
return has_dap4;
}
void DMR::dump(ostream &strm) const {
strm << DapIndent::LMarg << "DMR::dump - (" << (void *)this << ")" << endl;
DapIndent::Indent();
strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl;
strm << DapIndent::LMarg << "name: " << d_name << endl;
strm << DapIndent::LMarg << "filename: " << d_filename << endl;
strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
DapIndent::UnIndent();
}
} // namespace libdap
BaseType
libdap::BaseTypeFactory
Definition BaseTypeFactory.h:79
libdap::Constructor::var
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())
Definition Constructor.cc:191
libdap::D4BaseTypeFactory
Definition D4BaseTypeFactory.h:71
libdap::D4Group
Definition D4Group.h:44
libdap::D4Group::transform_to_dap2
std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table) override
Transform the D4Group's variables to DAP2 variables.
Definition D4Group.cc:723
libdap::DDS
Definition DDS.h:176
libdap::DDS::add_var_nocopy
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition DDS.cc:504
libdap::DDS::filename
string filename() const
Definition DDS.cc:287
libdap::DDS::get_attr_table
virtual AttrTable & get_attr_table()
Definition DDS.cc:276
libdap::DDS::set_factory
BaseTypeFactory * set_factory(BaseTypeFactory *factory)
Definition DDS.h:239
libdap::DDS::get_dataset_name
string get_dataset_name() const
Definition DDS.cc:268
libdap::DDS::var_begin
Vars_iter var_begin()
Definition DDS.h:336
libdap::DDS::var_end
Vars_iter var_end()
Return an iterator.
Definition DDS.h:341
libdap::DMR
Definition DMR.h:56
libdap::DMR::dump
void dump(std::ostream &strm) const override
dumps information about this object
Definition DMR.cc:362
libdap::DMR::getDDS
virtual DDS * getDDS()
Build a DDS from a DMR.
Definition DMR.cc:194
libdap::DMR::~DMR
~DMR() override
Definition DMR.cc:132
libdap::DMR::m_duplicate
void m_duplicate(const DMR &dmr)
Copy the contents of the given DMR into this one. This is defined because the we perform a deep copy ...
Definition DMR.cc:60
libdap::DMR::name
std::string name() const
Definition DMR.h:125
libdap::DMR::set_dap_version
void set_dap_version(const std::string &version_string)
Definition DMR.cc:239
libdap::DMR::get_namespace
std::string get_namespace() const
Get the namespace associated with the DMR.
Definition DMR.h:161
libdap::DMR::request_xml_base
std::string request_xml_base() const
Get the URL that will return this DMR.
Definition DMR.h:155
libdap::DMR::is_dap4_projected
virtual bool is_dap4_projected(std::vector< string > &inventory)
Scans the inventory of projected variables and their attributes for projected DAP4 types....
Definition DMR.cc:343
libdap::DMR::build_using_dds
virtual void build_using_dds(DDS &dds)
Definition DMR.cc:151
libdap::DMR::root
D4Group * root()
Definition DMR.cc:228
libdap::DMR::request_size
long request_size(bool constrained)
Get the estimated response size, in kilobytes.
Definition DMR.cc:285
libdap::DMR::request_size_kb
uint64_t request_size_kb(bool constrained)
Compute the estimated response size, in kilobytes.
Definition DMR.cc:297
libdap::DMR::filename
std::string filename() const
Definition DMR.h:142
libdap::DMR::factory
virtual D4BaseTypeFactory * factory()
Definition DMR.h:133
libdap::DMR::print_dap4
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition DMR.cc:306
libdap::DapObj
libdap base object for common functionality of libdap objects
Definition DapObj.h:49
libdap::InternalErr
A class for software fault reporting.
Definition InternalErr.h:61
libdap::XMLWriter
Definition XMLWriter.h:39
libdap
top level DAP object to house generic methods
Definition AlarmHandler.h:35
libdap::var
virtual BaseType * var(const string &name="", bool exact_match=true, btp_stack *s=nullptr)
Returns a pointer to a member of a constructor class.