libdap  Updated for version 3.20.0
libdap4 is an implementation of OPeNDAP's DAP protocol.
D4Attributes.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 //#define DODS_DEBUG
28 
29 #include "D4Attributes.h"
30 #include "D4AttributeType.h"
31 #include "InternalErr.h"
32 
33 #include "AttrTable.h"
34 
35 #include "util.h"
36 #include "debug.h"
37 #include "DapIndent.h"
38 
39 namespace libdap {
40 
44 string D4AttributeTypeToString(D4AttributeType at)
45 {
46  switch(at) {
47  case attr_null_c:
48  return "null";
49 
50  case attr_byte_c:
51  return "Byte";
52 
53  case attr_int16_c:
54  return "Int16";
55 
56  case attr_uint16_c:
57  return "UInt16";
58 
59  case attr_int32_c:
60  return "Int32";
61 
62  case attr_uint32_c:
63  return "UInt32";
64 
65  case attr_float32_c:
66  return "Float32";
67 
68  case attr_float64_c:
69  return "Float64";
70 
71  case attr_str_c:
72  return "String";
73 
74  case attr_url_c:
75  return "Url";
76 
77  // Added for DAP4
78  case attr_int8_c:
79  return "Int8";
80 
81  case attr_uint8_c:
82  return "UInt8";
83 
84  case attr_int64_c:
85  return "Int64";
86 
87  case attr_uint64_c:
88  return "UInt64";
89 
90  case attr_enum_c:
91  return "Enum";
92 
93  case attr_opaque_c:
94  return "Opaque";
95 
96  // These are specific to attributes while the other types are
97  // also supported by the variables. jhrg 4/17/13
98  case attr_container_c:
99  return "Container";
100 
101  case attr_otherxml_c:
102  return "OtherXML";
103 
104  default:
105  throw InternalErr(__FILE__, __LINE__, "Unsupported attribute type");
106  }
107 }
108 
109 D4AttributeType StringToD4AttributeType(string s)
110 {
111  downcase(s);
112 
113  if (s == "container")
114  return attr_container_c;
115 
116  else if (s == "byte")
117  return attr_byte_c;
118  else if (s == "int8")
119  return attr_int8_c;
120  else if (s == "uint8")
121  return attr_uint8_c;
122  else if (s == "int16")
123  return attr_int16_c;
124  else if (s == "uint16")
125  return attr_uint16_c;
126  else if (s == "int32")
127  return attr_int32_c;
128  else if (s == "uint32")
129  return attr_uint32_c;
130  else if (s == "int64")
131  return attr_int64_c;
132  else if (s == "uint64")
133  return attr_uint64_c;
134 
135  else if (s == "float32")
136  return attr_float32_c;
137  else if (s == "float64")
138  return attr_float64_c;
139 
140  else if (s == "string")
141  return attr_str_c;
142  else if (s == "url")
143  return attr_url_c;
144  else if (s == "otherxml")
145  return attr_otherxml_c;
146  else
147  return attr_null_c;
148 }
149 
150 void
151 D4Attribute::m_duplicate(const D4Attribute &src)
152 {
153  d_name = src.d_name;
154  d_type = src.d_type;
155  d_values = src.d_values;
156  if (src.d_attributes)
157  d_attributes = new D4Attributes(*src.d_attributes);
158  else
159  d_attributes = 0;
160 }
161 
162 D4Attribute::D4Attribute(const D4Attribute &src)
163 {
164  m_duplicate(src);
165 }
166 
167 D4Attribute::~D4Attribute()
168 {
169  delete d_attributes;
170 }
171 
172 D4Attribute &
173 D4Attribute::operator=(const D4Attribute &rhs)
174 {
175  if (this == &rhs) return *this;
176  m_duplicate(rhs);
177  return *this;
178 }
179 
180 D4Attributes *
181 D4Attribute::attributes()
182 {
183  if (!d_attributes) d_attributes = new D4Attributes();
184  return d_attributes;
185 }
186 
195 void
197 {
198  // for every attribute in at, copy it to this.
199  for (AttrTable::Attr_iter i = at.attr_begin(), e = at.attr_end(); i != e; ++i) {
200  string name = at.get_name(i);
201  AttrType type = at.get_attr_type(i);
202 
203  switch (type) {
204  case Attr_container: {
205  D4Attribute *a = new D4Attribute(name, attr_container_c);
206  D4Attributes *attributes = a->attributes(); // allocates a new object
207  attributes->transform_to_dap4(*at.get_attr_table(i));
208  add_attribute_nocopy(a);
209  break;
210  }
211  case Attr_byte: {
212  D4Attribute *a = new D4Attribute(name, attr_byte_c);
213  a->add_value_vector(*at.get_attr_vector(i));
214  add_attribute_nocopy(a);
215  break;
216  }
217  case Attr_int16: {
218  D4Attribute *a = new D4Attribute(name, attr_int16_c);
219  a->add_value_vector(*at.get_attr_vector(i));
220  add_attribute_nocopy(a);
221  break;
222  }
223  case Attr_uint16: {
224  D4Attribute *a = new D4Attribute(name, attr_uint16_c);
225  a->add_value_vector(*at.get_attr_vector(i));
226  add_attribute_nocopy(a);
227  break;
228  }
229  case Attr_int32: {
230  D4Attribute *a = new D4Attribute(name, attr_int32_c);
231  a->add_value_vector(*at.get_attr_vector(i));
232  add_attribute_nocopy(a);
233  break;
234  }
235  case Attr_uint32: {
236  D4Attribute *a = new D4Attribute(name, attr_uint32_c);
237  a->add_value_vector(*at.get_attr_vector(i));
238  add_attribute_nocopy(a);
239  break;
240  }
241  case Attr_float32: {
242  D4Attribute *a = new D4Attribute(name, attr_float32_c);
243  a->add_value_vector(*at.get_attr_vector(i));
244  add_attribute_nocopy(a);
245  break;
246  }
247  case Attr_float64: {
248  D4Attribute *a = new D4Attribute(name, attr_float64_c);
249  a->add_value_vector(*at.get_attr_vector(i));
250  add_attribute_nocopy(a);
251  break;
252  }
253  case Attr_string: {
254  D4Attribute *a = new D4Attribute(name, attr_str_c);
255  a->add_value_vector(*at.get_attr_vector(i));
256  add_attribute_nocopy(a);
257  break;
258  }
259  case Attr_url: {
260  D4Attribute *a = new D4Attribute(name, attr_url_c);
261  a->add_value_vector(*at.get_attr_vector(i));
262  add_attribute_nocopy(a);
263  break;
264  }
265  case Attr_other_xml: {
266  D4Attribute *a = new D4Attribute(name, attr_otherxml_c);
267  a->add_value_vector(*at.get_attr_vector(i));
268  add_attribute_nocopy(a);
269  break;
270  }
271  default:
272  throw InternalErr(__FILE__, __LINE__, "Unknown DAP2 attribute type in D4Attributes::copy_from_dap2()");
273  }
274  }
275 }
276 
277 
278 AttrType get_dap2_AttrType(D4AttributeType d4_type){
279  switch (d4_type) {
280  case attr_container_c: { return Attr_container; }
281  case attr_byte_c: { return Attr_byte; }
282  case attr_int16_c: { return Attr_int16; }
283  case attr_uint16_c: { return Attr_uint16; }
284  case attr_int32_c: { return Attr_int32; }
285  case attr_uint32_c: { return Attr_uint32; }
286  case attr_float32_c: { return Attr_float32; }
287  case attr_float64_c: { return Attr_float64; }
288  case attr_str_c: { return Attr_string; }
289  case attr_url_c: { return Attr_url; }
290  case attr_otherxml_c: { return Attr_other_xml; }
291  default:
292  throw InternalErr(__FILE__, __LINE__, "Unknown DAP4 attribute");
293  }
294 }
295 
296 
297 void
298 D4Attributes::load_AttrTable(AttrTable *d2_attr_table, D4Attributes *d4_attrs)
299 {
300  // cerr << __func__ << "() - Loading attribute table: '" << d2_attr_table->get_name() << "' addr: " << (void *)d2_attr_table << endl;
301 
302  // for every attribute in at, copy it to this.
303  for ( D4Attributes::D4AttributesIter i = d4_attrs->attribute_begin(), e = d4_attrs->attribute_end(); i != e; ++i) {
304  string name = (*i)->name();
305  D4AttributeType d4_attr_type = (*i)->type();
306  AttrType d2_attr_type = get_dap2_AttrType(d4_attr_type);
307  string d2_attr_type_name = AttrType_to_String(d2_attr_type);
308 
309  D4Attribute::D4AttributeIter vitr =(*i)->value_begin();
310  D4Attribute::D4AttributeIter end =(*i)->value_end();
311 
312  vector<string> values;
313  for(;vitr!=end; vitr++){
314  values.push_back((*vitr));
315  }
316 
317  switch (d4_attr_type) {
318  case attr_container_c: {
319  // Attr_container
320  AttrTable *child_attr_table = new AttrTable();
321  child_attr_table->set_name(name);
322  // cerr << __func__ << "() - Created child attribute table: " << name << " addr: " << (void *)child_attr_table << endl;
323  load_AttrTable(child_attr_table,(*i)->attributes());
324  d2_attr_table->append_container(child_attr_table,name);
325  break;
326  }
327  default:{
328  // cerr << __func__ << "() - "<< name << " has " << values.size() << " value(s). d2_attr_type_name: " << d2_attr_type_name << endl;
329  d2_attr_table->append_attr(name,d2_attr_type_name, &values);
330  break;
331  }
332  }
333  }
334 }
335 
336 
345 {
346  AttrTable *my_pretty_pony = new AttrTable();
347  load_AttrTable(my_pretty_pony, this);
348  my_pretty_pony->set_name(name);
349  return my_pretty_pony;
350 }
351 
352 
353 D4Attribute *
354 D4Attributes::find_depth_first(const string &name, D4AttributesIter i)
355 {
356  if (i == attribute_end())
357  return 0;
358  else if ((*i)->name() == name)
359  return *i;
360  else if ((*i)->type() == attr_container_c)
361  return find_depth_first(name, (*i)->attributes()->attribute_begin());
362  else
363  return find_depth_first(name, ++i);
364 }
365 
366 D4Attribute *
367 D4Attributes::find(const string &name)
368 {
369  return find_depth_first(name, attribute_begin());
370 }
371 
375 D4Attribute *
376 D4Attributes::get(const string &fqn)
377 {
378  // name1.name2.name3
379  // name1
380  // name1.name2
381  size_t pos = fqn.find('.');
382  string part = fqn.substr(0, pos);
383  string rest= "";
384 
385  if (pos != string::npos)
386  rest = fqn.substr(pos + 1);
387 
388  DBG(cerr << "part: '" << part << "'; rest: '" << rest << "'" << endl);
389 
390  if (!part.empty()) {
391  if (!rest.empty()) {
392  D4AttributesIter i = attribute_begin();
393  while (i != attribute_end()) {
394  if ((*i)->name() == part && (*i)->type() == attr_container_c)
395  return (*i)->attributes()->get(rest);
396  ++i;
397  }
398  }
399  else {
400  D4AttributesIter i = attribute_begin();
401  while (i != attribute_end()) {
402  if ((*i)->name() == part)
403  return (*i);
404  ++i;
405  }
406  }
407  }
408 
409  return 0;
410 }
411 
412 void
413 D4Attribute::print_dap4(XMLWriter &xml) const
414 {
415  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Attribute") < 0)
416  throw InternalErr(__FILE__, __LINE__, "Could not write Attribute element");
417  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "name", (const xmlChar*)name().c_str()) < 0)
418  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for name");
419  if (xmlTextWriterWriteAttribute(xml.get_writer(), (const xmlChar*) "type", (const xmlChar*) D4AttributeTypeToString(type()).c_str()) < 0)
420  throw InternalErr(__FILE__, __LINE__, "Could not write attribute for type");
421 
422  switch (type()) {
423  case attr_container_c:
424  if (!d_attributes)
425  throw InternalErr(__FILE__, __LINE__, "Null Attribute container");
426  d_attributes->print_dap4(xml);
427  break;
428 
429  case attr_otherxml_c:
430  if (num_values() != 1)
431  throw Error("OtherXML attributes cannot be vector-valued.");
432  if (xmlTextWriterWriteRaw(xml.get_writer(), (const xmlChar*) value(0).c_str()) < 0)
433  throw InternalErr(__FILE__, __LINE__, "Could not write OtherXML value");
434  break;
435 
436  default: {
437  // Assume only valid types make it into instances
438  D4AttributeCIter i = d_values.begin();//value_begin();
439  while (i != d_values.end()) {
440  if (xmlTextWriterStartElement(xml.get_writer(), (const xmlChar*) "Value") < 0)
441  throw InternalErr(__FILE__, __LINE__, "Could not write value element");
442 
443  if (xmlTextWriterWriteString(xml.get_writer(), (const xmlChar*) (*i++).c_str()) < 0)
444  throw InternalErr(__FILE__, __LINE__, "Could not write attribute value");
445 
446  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
447  throw InternalErr(__FILE__, __LINE__, "Could not end value element");
448  }
449 
450  break;
451  }
452  }
453 
454  if (xmlTextWriterEndElement(xml.get_writer()) < 0)
455  throw InternalErr(__FILE__, __LINE__, "Could not end Attribute element");
456 }
457 
466 void
467 D4Attribute::dump(ostream &strm) const
468 {
469  strm << DapIndent::LMarg << "D4Attribute::dump - (" << (void *)this << ")" << endl;
470 
471  DapIndent::Indent() ;
472 
473  XMLWriter xml;
474  print_dap4(xml);
475  strm << DapIndent::LMarg << xml.get_doc() << flush;
476 
477  DapIndent::UnIndent() ;
478 }
479 
480 
481 void
482 D4Attributes::print_dap4(XMLWriter &xml) const
483 {
484  if (empty())
485  return;
486 
487  D4AttributesCIter i = d_attrs.begin();
488  while (i != d_attrs.end()) {
489  (*i++)->print_dap4(xml);
490  }
491 }
492 
501 void
502 D4Attributes::dump(ostream &strm) const
503 {
504  strm << DapIndent::LMarg << "D4Attributes::dump - (" << (void *)this << ")" << endl;
505 
506  DapIndent::Indent() ;
507 
508  XMLWriter xml;
509  print_dap4(xml);
510  strm << DapIndent::LMarg << xml.get_doc() << flush;
511 
512  DapIndent::UnIndent() ;
513 }
514 
515 
516 } // namespace libdap
517 
AttrTable * get_AttrTable(const std::string name)
copy attributes from DAP4 to DAP2
virtual void dump(ostream &strm) const
dumps information about this object
virtual Attr_iter attr_end()
Definition: AttrTable.cc:719
void downcase(string &s)
Definition: util.cc:563
D4AttributesIter attribute_begin()
Get an iterator to the start of the enumerations.
Definition: D4Attributes.h:146
Contains the attributes for a dataset.
Definition: AttrTable.h:142
string AttrType_to_String(const AttrType at)
Definition: AttrTable.cc:97
virtual string get_name() const
Get the name of this attribute table.
Definition: AttrTable.cc:238
top level DAP object to house generic methods
Definition: AlarmHandler.h:35
A class for software fault reporting.
Definition: InternalErr.h:64
virtual AttrTable * append_container(const string &name)
Add a container to the attribute table.
Definition: AttrTable.cc:410
virtual AttrTable * get_attr_table(const string &name)
Get an attribute container.
Definition: AttrTable.cc:607
virtual Attr_iter attr_begin()
Definition: AttrTable.cc:711
virtual unsigned int append_attr(const string &name, const string &type, const string &value)
Add an attribute to the table.
Definition: AttrTable.cc:307
virtual AttrType get_attr_type(const string &name)
Get the type of an attribute.
Definition: AttrTable.cc:621
D4AttributesIter attribute_end()
Get an iterator to the end of the enumerations.
Definition: D4Attributes.h:149
virtual vector< string > * get_attr_vector(const string &name)
Get a vector-valued attribute.
Definition: AttrTable.cc:653
D4Attribute * get(const string &fqn)
A class for error processing.
Definition: Error.h:90
string D4AttributeTypeToString(D4AttributeType at)
Definition: D4Attributes.cc:44
virtual void set_name(const string &n)
Set the name of this attribute table.
Definition: AttrTable.cc:245
void transform_to_dap4(AttrTable &at)
copy attributes from DAP2 to DAP4
AttrType
Definition: AttrTable.h:81
virtual void dump(ostream &strm) const
dumps information about this object