libdap
Updated for version 3.17.0
|
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