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 <io.h>
#include <process.h>
#include <fstream>
#else
#include <unistd.h> // for alarm and dup
#include <sys/wait.h>
#endif
#include <cassert>
#include <iostream>
#include <sstream>
//#define DODS_DEBUG
//#define DODS_DEBUG2
#include "D4Group.h"
#include "BaseType.h"
#include "Array.h"
#include "Grid.h"
#include "DMR.h"
#include "XMLWriter.h"
#include "D4BaseTypeFactory.h"
#include "D4Attributes.h"
#include "DDS.h" // Included so DMRs can be built using a DDS for 'legacy' handlers
#include "debug.h"
#include "DapIndent.h"
const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
using namespace std;
namespace libdap {
void
DMR::m_duplicate(const DMR &dmr)
{
// This is needed because we use the factory to make a new instance of the root group
assert(dmr.OK());
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 = dmr.d_max_response_size;
// 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);
//d_root = static_cast<D4Group*>(dmr.d_factory->NewVariable(dods_group_c, dmr.d_root->name()));
}
DMR::DMR(D4BaseTypeFactory *factory, const string &name)
: d_factory(factory), d_name(name), d_filename(""),
d_dap_major(4), d_dap_minor(0),
d_dmr_version("1.0"), d_request_xml_base(""),
d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
{
// sets d_dap_version string and the two integer fields too
set_dap_version("4.0");
}
DMR::DMR(D4BaseTypeFactory *factory, DDS &dds)
: d_factory(factory), d_name(dds.get_dataset_name()),
d_filename(dds.filename()), d_dap_major(4), d_dap_minor(0),
d_dmr_version("1.0"), d_request_xml_base(""),
d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
{
// sets d_dap_version string and the two integer fields too
set_dap_version("4.0");
build_using_dds(dds);
#if 0
for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
BaseType *new_var = (*i)->transform_to_dap4(root() /*group*/, root() /*container*/);
// If the variable being transformed is a Grid,
// then Grid::transform_to_dap4() will add all the arrays to the
// container (root() in this case) and return null, indicating that
// this code does not need to do anything to add the transformed variable.
if (new_var)
root()->add_var_nocopy(new_var);
}
// Now copy the global attributes
root()->attributes()->transform_to_dap4(dds.get_attr_table());
#endif
}
DMR::DMR()
: d_factory(0), d_name(""), d_filename(""), d_dap_major(4), d_dap_minor(0),
d_dap_version("4.0"), d_dmr_version("1.0"), d_request_xml_base(""),
d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
{
// sets d_dap_version string and the two integer fields too
set_dap_version("4.0");
}
DMR::DMR(const DMR &rhs) : DapObj()
{
m_duplicate(rhs);
}
DMR::~DMR()
{
#if 1
delete d_root;
#endif
}
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());
}
#if 0
DDS *DMR::getDDS(DMR &dmr)
{
DBG( cerr << __func__ << "() - BEGIN" << endl);
D4Group *root = dmr.root();
BaseTypeFactory *btf = new BaseTypeFactory();
DDS *dds = new DDS(btf, dmr.name());
dds->filename(dmr.filename());
AttrTable *dds_at = &(dds->get_attr_table());
// Now copy the global attributes
// D4Attributes::load_AttrTable(dds_at,root->attributes());
// TODO Make this a unique_ptr<> and let the compiler delete it. jhrg 6/17/19
vector<BaseType *> *top_vars = root->transform_to_dap2(dds_at, true);
vector<BaseType *>::iterator vIter = top_vars->begin();
vector<BaseType *>::iterator vEnd = top_vars->end();
for (; vIter != vEnd; vIter++) {
dds->add_var_nocopy(*vIter);
}
delete top_vars;
#if 0
set<string> shared_dim_candidates;
vector<BaseType *> dropped_vars;
for (D4Group::Vars_iter i = root->var_begin(), e = root->var_end(); i != e; ++i)
{
DBG( cerr << __func__ << "() - Processing top level variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to DDS." << endl; );
vector<BaseType *> *new_vars = (*i)->transform_to_dap2(&(dds->get_attr_table()));
if(new_vars!=0) {
vector<BaseType*>::iterator vIter = new_vars->begin();
vector<BaseType*>::iterator end = new_vars->end();
for(; vIter!=end; vIter++ ) {
BaseType *new_var = (*vIter);
DBG( cerr << __func__ << "() - Adding variable name: '"<< new_var->name() << "' " <<
"type: " << new_var->type() << " " <<
"type_name: " << new_var->type_name() << " to DDS." << endl; );
dds->add_var_nocopy(new_var);
Grid *grid = dynamic_cast <Grid *>(new_var);
if(grid) {
Grid::Map_iter m = grid->map_begin();
for(; m != grid->map_end(); m++) {
shared_dim_candidates.insert((*m)->name());
}
}
(*vIter) = 0;
}
delete new_vars;
}
else {
DBG( cerr << __func__ << "Adding variable '"<< (*i)->type_name() << " " << (*i)->name() << "' to drop list." << endl; );
dropped_vars.push_back((*i));
}
}
AttrTable *dv_table = Constructor::make_dropped_vars_attr_table(&dropped_vars);
if(dv_table) {
DBG( cerr << __func__ << "() - Adding dropped variable AttrTable." << endl);
dds_at->append_container(dv_table,dv_table->get_name());
}
// Get all the child groups.
D4Group::groupsIter gIter = root->grp_begin();
D4Group::groupsIter gEnd = root->grp_end();
for(; gIter!=gEnd; gIter++) {
D4Group *grp = *gIter;
DBG( cerr << __func__ << "() - Processing D4Group " << grp->name() << endl);
vector<BaseType *> *d2_vars = grp->transform_to_dap2(dds_at);
if(d2_vars) {
DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variables." << endl);
vector<BaseType *>::iterator vIter = d2_vars->begin();
vector<BaseType *>::iterator vEnd = d2_vars->end();
for(; vIter!=vEnd; vIter++) {
DBG( cerr << __func__ << "() - Processing " << grp->name() << " Member Variable: " << (*vIter)->name() << endl);
dds->add_var(*vIter);
}
}
}
#endif
DBG( cerr << __func__ << "() - END" << endl);
return dds;
}
#endif
DDS *
DMR::getDDS()
{
#if 0
return DMR::getDDS(*this);
#else
DBG( cerr << __func__ << "() - BEGIN" << endl);
#if 0
BaseTypeFactory *btf = new BaseTypeFactory();
#endif
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
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;
DBG( cerr << __func__ << "() - END" << endl);
dds->set_factory(0);
return dds;
#endif
}
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;
}
}
long
DMR::request_size(bool constrained)
{
return d_root->request_size(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 0
// Reintroduce these if they are really useful. jhrg 4/15/13
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
(const xmlChar*) c_xml_namespace.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
< 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
(const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
#endif
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");
}
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
libdap::BaseTypeFactory
Definition: BaseTypeFactory.h:80
libdap::DMR::getDDS
virtual DDS * getDDS()
Build a DDS from a DMR.
Definition: DMR.cc:371
libdap::DMR::request_size
long request_size(bool constrained)
Get the estimated response size, in kilo bytes.
Definition: DMR.cc:465
libdap::DMR::set_dap_version
void set_dap_version(const std::string &version_string)
Definition: DMR.cc:419
libdap::BaseType::transform_to_dap4
virtual void transform_to_dap4(D4Group *root, Constructor *container)
DAP2 to DAP4 transform.
Definition: BaseType.cc:216
libdap::Constructor::var_end
Vars_iter var_end()
Definition: Constructor.cc:364
libdap::XMLWriter
Definition: XMLWriter.h:39
libdap::DMR::~DMR
virtual ~DMR()
Definition: DMR.cc:200
libdap::BaseType::name
virtual string name() const
Returns the name of the class instance.
Definition: BaseType.cc:320
libdap::DDS::filename
string filename() const
Definition: DDS.cc:387
libdap::DMR::request_xml_base
std::string request_xml_base() const
Get the URL that will return this DMR.
Definition: DMR.h:145
libdap::InternalErr
A class for software fault reporting.
Definition: InternalErr.h:64
libdap::DDS::add_var
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
libdap::DDS::get_attr_table
virtual AttrTable & get_attr_table()
Definition: DDS.cc:372
libdap::DMR::root
D4Group * root()
Definition: DMR.cc:407
libdap::D4Group::request_size
long request_size(bool constrained)
Definition: D4Group.cc:409
libdap::D4Group
Definition: D4Group.h:43
libdap::BaseType::attributes
virtual D4Attributes * attributes()
Definition: BaseType.cc:599
libdap::Constructor::add_var_nocopy
virtual void add_var_nocopy(BaseType *bt, Part part=nil)
Definition: Constructor.cc:432
libdap
top level DAP object to house generic methods
Definition: AlarmHandler.h:35
libdap::DapObj
libdap base object for common functionality of libdap objects
Definition: DapObj.h:50
libdap::DMR::get_namespace
std::string get_namespace() const
Get the namespace associated with the DMR.
Definition: DMR.h:151
libdap::D4Attributes::transform_to_dap4
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
Definition: D4Attributes.cc:196
libdap::DDS::add_var_nocopy
void add_var_nocopy(BaseType *bt)
Adds the variable to the DDS.
Definition: DDS.cc:613
libdap::D4Group::grp_begin
groupsIter grp_begin()
Get an iterator to the start of the values.
Definition: D4Group.h:111
libdap::AttrTable
Contains the attributes for a dataset.
Definition: AttrTable.h:142
libdap::D4Group::transform_to_dap2
virtual std::vector< BaseType * > * transform_to_dap2(AttrTable *parent_attr_table)
Transform the D4Group's variables to DAP2 variables.
Definition: D4Group.cc:663
libdap::DMR::dump
virtual void dump(std::ostream &strm) const
dumps information about this object
Definition: DMR.cc:531
libdap::DDS::var_begin
Vars_iter var_begin()
Return an iterator to the first variable.
Definition: DDS.cc:799
libdap::D4Group::print_dap4
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: D4Group.cc:574
libdap::DDS::get_dataset_name
string get_dataset_name() const
Definition: DDS.cc:356
libdap::D4Group::grp_end
groupsIter grp_end()
Get an iterator to the end of the values.
Definition: D4Group.h:114
libdap::DMR::name
std::string name() const
Definition: DMR.h:115
libdap::DDS::set_factory
BaseTypeFactory * set_factory(BaseTypeFactory *factory)
Definition: DDS.h:253
libdap::DMR::build_using_dds
virtual void build_using_dds(DDS &dds)
Definition: DMR.cc:226
libdap::DMR::DMR
DMR()
Definition: DMR.cc:182
libdap::DMR
Definition: DMR.h:53
libdap::D4BaseTypeFactory
Definition: D4BaseTypeFactory.h:72
libdap::DDS
Definition: DDS.h:183
libdap::DMR::filename
std::string filename() const
Definition: DMR.h:132
libdap::BaseType
The basic data type for the DODS DAP types.
Definition: BaseType.h:117
libdap::AttrTable::append_container
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
libdap::Constructor::var_begin
Vars_iter var_begin()
Definition: Constructor.cc:356
libdap::BaseType::type_name
virtual string type_name() const
Returns the type of the class instance as a string.
Definition: BaseType.cc:379
libdap::DDS::var_end
Vars_iter var_end()
Return an iterator.
Definition: DDS.cc:811
libdap::DMR::print_dap4
void print_dap4(XMLWriter &xml, bool constrained=false)
Definition: DMR.cc:478
libdap::Constructor::var
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