libdap  Updated for version 3.17.0
DMR.cc
00001 // -*- mode: c++; c-basic-offset:4 -*-
00002 
00003 // This file is part of libdap, A C++ implementation of the OPeNDAP Data
00004 // Access Protocol.
00005 
00006 // Copyright (c) 2013 OPeNDAP, Inc.
00007 // Author: James Gallagher <jgallagher@opendap.org>
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Lesser General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2.1 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Lesser General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Lesser General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 //
00023 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
00024 
00025 #include "config.h"
00026 
00027 #ifdef WIN32
00028 #include <io.h>
00029 #include <process.h>
00030 #include <fstream>
00031 #else
00032 #include <unistd.h>    // for alarm and dup
00033 #include <sys/wait.h>
00034 #endif
00035 
00036 #include <cassert>
00037 
00038 #include <iostream>
00039 #include <sstream>
00040 
00041 //#define DODS_DEBUG
00042 //#define DODS_DEBUG2
00043 
00044 #include "D4Group.h"
00045 #include "BaseType.h"
00046 #include "Array.h"
00047 #include "DMR.h"
00048 #include "XMLWriter.h"
00049 #include "D4BaseTypeFactory.h"
00050 #include "D4Attributes.h"
00051 
00052 #include "DDS.h"        // Included so DMRs can be built using a DDS for 'legacy' handlers
00053 
00054 #include "debug.h"
00055 
00061 const string c_xml_xsi = "http://www.w3.org/2001/XMLSchema-instance";
00062 const string c_xml_namespace = "http://www.w3.org/XML/1998/namespace";
00063 
00064 const string c_default_dap40_schema_location = "http://xml.opendap.org/dap/dap4.0.xsd";
00065 
00066 const string c_dap40_namespace = "http://xml.opendap.org/ns/DAP/4.0#";
00067 
00068 const string c_dap_40_n_sl = c_dap40_namespace + " " + c_default_dap40_schema_location;
00069 
00070 using namespace std;
00071 
00072 namespace libdap {
00073 
00074 void
00075 DMR::m_duplicate(const DMR &dmr)
00076 {
00077     // This is needed because we use the factory to make a new instance of the root group
00078     assert(dmr.OK());
00079 
00080     d_factory = dmr.d_factory; // Shallow copy here
00081 
00082     d_name = dmr.d_name;
00083     d_filename = dmr.d_filename;
00084 
00085     d_dap_major = dmr.d_dap_major;
00086     d_dap_minor = dmr.d_dap_minor;
00087     d_dap_version = dmr.d_dap_version;       // String version of the protocol
00088 
00089     d_dmr_version = dmr.d_dmr_version;
00090 
00091     d_request_xml_base = dmr.d_request_xml_base;
00092 
00093     d_namespace = dmr.d_namespace;
00094 
00095     d_max_response_size = dmr.d_max_response_size;
00096 
00097     // Deep copy, using ptr_duplicate()
00098     d_root = dmr.d_root->ptr_duplicate();
00099     DBG(cerr << "dmr.d_root: " << dmr.d_root << endl);
00100     DBG(cerr << "d_root (from ptr_dup(): " << d_root << endl);
00101 
00102     //d_root = static_cast<D4Group*>(dmr.d_factory->NewVariable(dods_group_c, dmr.d_root->name()));
00103 }
00104 
00117 DMR::DMR(D4BaseTypeFactory *factory, const string &name)
00118         : d_factory(factory), d_name(name), d_filename(""),
00119           d_dap_major(4), d_dap_minor(0),
00120           d_dmr_version("1.0"), d_request_xml_base(""),
00121           d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
00122 {
00123     // sets d_dap_version string and the two integer fields too
00124     set_dap_version("4.0");
00125 }
00126 
00147 DMR::DMR(D4BaseTypeFactory *factory, DDS &dds)
00148         : d_factory(factory), d_name(dds.get_dataset_name()),
00149           d_filename(dds.filename()), d_dap_major(4), d_dap_minor(0),
00150           d_dmr_version("1.0"), d_request_xml_base(""),
00151           d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
00152 {
00153     // sets d_dap_version string and the two integer fields too
00154     set_dap_version("4.0");
00155 
00156     build_using_dds(dds);
00157 #if 0
00158     for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
00159         BaseType *new_var = (*i)->transform_to_dap4(root() /*group*/, root() /*container*/);
00160         // If the variable being transformed is a Grid,
00161         // then Grid::transform_to_dap4() will add all the arrays to the
00162         // container (root() in this case) and return null, indicating that
00163         // this code does not need to do anything to add the transformed variable.
00164         if (new_var)
00165                 root()->add_var_nocopy(new_var);
00166     }
00167 
00168     // Now copy the global attributes
00169     root()->attributes()->transform_to_dap4(dds.get_attr_table());
00170 #endif
00171 }
00172 
00179 DMR::DMR()
00180         : d_factory(0), d_name(""), d_filename(""), d_dap_major(4), d_dap_minor(0),
00181           d_dap_version("4.0"), d_dmr_version("1.0"), d_request_xml_base(""),
00182           d_namespace(c_dap40_namespace), d_max_response_size(0), d_root(0)
00183 {
00184     // sets d_dap_version string and the two integer fields too
00185     set_dap_version("4.0");
00186 }
00187 
00189 DMR::DMR(const DMR &rhs) : DapObj()
00190 {
00191     m_duplicate(rhs);
00192 }
00193 
00197 DMR::~DMR()
00198 {
00199 #if 1
00200     delete d_root;
00201 #endif
00202 }
00203 
00204 DMR &
00205 DMR::operator=(const DMR &rhs)
00206 {
00207     if (this == &rhs)
00208         return *this;
00209 
00210     m_duplicate(rhs);
00211 
00212     return *this;
00213 }
00214 
00223 void DMR::build_using_dds(DDS &dds)
00224 {
00225         set_name(dds.get_dataset_name());
00226         set_filename(dds.filename());
00227 
00228         for (DDS::Vars_iter i = dds.var_begin(), e = dds.var_end(); i != e; ++i) {
00229                 BaseType *new_var = (*i)->transform_to_dap4(root() /*group*/, root() /*container*/);
00230                 // If the variable being transformed is a Grid,
00231                 // then Grid::transform_to_dap4() will add all the arrays to the
00232                 // container (root() in this case) and return null, indicating that
00233                 // this code does not need to do anything to add the transformed variable.
00234                 if (new_var) root()->add_var_nocopy(new_var);
00235         }
00236 
00237         // Now copy the global attributes
00238         root()->attributes()->transform_to_dap4(dds.get_attr_table());
00239 }
00240 
00241 D4Group *
00242 DMR::root()
00243 {
00244         if (!d_root) d_root = static_cast<D4Group*>(d_factory->NewVariable(dods_group_c, "/"));
00245         return d_root;
00246 }
00247 
00253 void
00254 DMR::set_dap_version(const string &v)
00255 {
00256     istringstream iss(v);
00257 
00258     int major = -1, minor = -1;
00259     char dot;
00260     if (!iss.eof() && !iss.fail())
00261         iss >> major;
00262     if (!iss.eof() && !iss.fail())
00263         iss >> dot;
00264     if (!iss.eof() && !iss.fail())
00265         iss >> minor;
00266 
00267     if (major == -1 || minor == -1 or dot != '.')
00268         throw InternalErr(__FILE__, __LINE__, "Could not parse dap version. Value given: " + v);
00269 
00270     d_dap_version = v;
00271 
00272     d_dap_major = major;
00273     d_dap_minor = minor;
00274 
00275     // Now set the related XML constants. These might be overwritten if
00276     // the DMR instance is being built from a document parse, but if it's
00277     // being constructed by a server the code to generate the XML document
00278     // needs these values to match the DAP version information.
00279     switch (d_dap_major) {
00280         case 4:
00281             d_namespace = c_dap40_namespace;
00282             break;
00283         default:
00284             d_namespace = "";
00285             break;
00286     }
00287 }
00288 
00299 long
00300 DMR::request_size(bool constrained)
00301 {
00302     return d_root->request_size(constrained);
00303 }
00304 
00312 void
00313 DMR::print_dap4(XMLWriter &xml, bool constrained)
00314 {
00315     if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Dataset") < 0)
00316         throw InternalErr(__FILE__, __LINE__, "Could not write Dataset element");
00317 
00318 #if 0
00319     // Reintroduce these if they are really useful. jhrg 4/15/13
00320     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xml",
00321             (const xmlChar*) c_xml_namespace.c_str()) < 0)
00322         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xml");
00323 
00324     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns:xsi", (const xmlChar*) c_xml_xsi.c_str())
00325             < 0)
00326         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:xsi");
00327 
00328     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xsi:schemaLocation",
00329             (const xmlChar*) c_dap_40_n_sl.c_str()) < 0)
00330         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns:schemaLocation");
00331 #endif
00332 
00333     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xmlns", (const xmlChar*) get_namespace().c_str()) < 0)
00334         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xmlns");
00335 
00336     if (!request_xml_base().empty()) {
00337         if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "xml:base",
00338                 (const xmlChar*)request_xml_base().c_str()) < 0)
00339             throw InternalErr(__FILE__, __LINE__, "Could not write attribute for xml:base");
00340     }
00341 
00342     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dapVersion",  (const xmlChar*)dap_version().c_str()) < 0)
00343         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
00344 
00345     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "dmrVersion", (const xmlChar*)dmr_version().c_str()) < 0)
00346         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for dapVersion");
00347 
00348     if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
00349         throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
00350 
00351     root()->print_dap4(xml, constrained);
00352 
00353     if (xmlTextWriterEndElement(xml.get_writer()) < 0)
00354         throw InternalErr(__FILE__, __LINE__, "Could not end the top-level Group element");
00355 }
00356 
00357 
00365 void
00366 DMR::dump(ostream &strm) const
00367 {
00368     strm << DapIndent::LMarg << "DMR::dump - ("
00369     << (void *)this << ")" << endl ;
00370     DapIndent::Indent() ;
00371     strm << DapIndent::LMarg << "factory: " << (void *)d_factory << endl ;
00372     strm << DapIndent::LMarg << "name: " << d_name << endl ;
00373     strm << DapIndent::LMarg << "filename: " << d_filename << endl ;
00374     strm << DapIndent::LMarg << "protocol major: " << d_dap_major << endl;
00375     strm << DapIndent::LMarg << "protocol minor: " << d_dap_minor << endl;
00376 
00377     DapIndent::UnIndent() ;
00378 }
00379 
00380 } // namespace libdap