bes  Updated for version 3.20.6
DimensionElement.cc
1 // This file is part of the "NcML Module" project, a BES module designed
3 // to allow NcML files to be used to be used as a wrapper to add
4 // AIS to existing datasets of any format.
5 //
6 // Copyright (c) 2009 OPeNDAP, Inc.
7 // Author: Michael Johnson <m.johnson@opendap.org>
8 //
9 // For more information, please also see the main website: http://opendap.org/
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // Please see the files COPYING and COPYRIGHT for more information on the GLPL.
26 //
27 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29 #include "DimensionElement.h"
30 #include "NCMLDebug.h"
31 #include "NCMLParser.h"
32 #include "NCMLUtil.h"
33 #include "NetcdfElement.h"
34 #include <sstream>
35 #include <Array.h>
36 
37 using std::string;
38 using std::stringstream;
39 
40 namespace ncml_module {
41 // the parse name of the element
42 const string DimensionElement::_sTypeName = "dimension";
43 const vector<string> DimensionElement::_sValidAttributes = getValidAttributes();
44 
45 DimensionElement::DimensionElement() :
46  NCMLElement(0), _length("0"), _orgName(""), _isUnlimited(""), _isShared(""), _isVariableLength(""), _dim()
47 {
48 }
49 
50 DimensionElement::DimensionElement(const DimensionElement& proto) :
51  RCObjectInterface(), NCMLElement(proto), _length(proto._length), _orgName(proto._orgName), _isUnlimited(
52  proto._isUnlimited), _isShared(proto._isShared), _isVariableLength(proto._isVariableLength), _dim(proto._dim)
53 {
54 }
55 
56 DimensionElement::DimensionElement(const agg_util::Dimension& dim) :
57  NCMLElement(0), _length("0"), _orgName(""), _isUnlimited(""), _isShared(""), _isVariableLength(""), _dim(dim)
58 {
59  // Set string to match the int size
60  ostringstream oss;
61  oss << dim.size;
62  _length = oss.str();
63 }
64 
65 DimensionElement::~DimensionElement()
66 {
67 }
68 
69 const string& DimensionElement::getTypeName() const
70 {
71  return _sTypeName;
72 }
73 
75 DimensionElement::clone() const
76 {
77  return new DimensionElement(*this);
78 }
79 
80 void DimensionElement::setAttributes(const XMLAttributeMap& attrs)
81 {
82  _dim.name = attrs.getValueForLocalNameOrDefault("name");
83  _length = attrs.getValueForLocalNameOrDefault("length");
84  _orgName = attrs.getValueForLocalNameOrDefault("orgName");
85  _isUnlimited = attrs.getValueForLocalNameOrDefault("isUnlimited");
86  _isShared = attrs.getValueForLocalNameOrDefault("isShared");
87  _isVariableLength = attrs.getValueForLocalNameOrDefault("isVariableLength");
88 
89  // First check that we didn't get any typos...
90  validateAttributes(attrs, _sValidAttributes);
91 
92  // Parse the size etc
93  parseValidateAndCacheDimension();
94 }
95 
96 void DimensionElement::handleBegin()
97 {
98  BESDEBUG("ncml", "DimensionElement::handleBegin called..." << endl);
99 
100  // Make sure we're placed at a valid parse location.
101  // Direct child of <netcdf> only now since we dont handle <group>
102  if (!_parser->isScopeNetcdf()) {
103  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
104  "Got dimension element = " + toString()
105  + " at an invalid parse location. Expected it as a direct child of <netcdf> element only." + " scope="
106  + _parser->getScopeString());
107  }
108 
109  // This will be the scope we're to be added...
110  NetcdfElement* dataset = _parser->getCurrentDataset();
111  VALID_PTR(dataset);
112 
113  // Make sure the name is unique at this parse level or exception.
114  const DimensionElement* pExistingDim = dataset->getDimensionInLocalScope(name());
115  if (pExistingDim) {
116  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
117  "Tried to add dimension at " + toString() + " but a dimension with name=" + name()
118  + " already exists in this scope=" + _parser->getScopeString());
119  }
120 
121  // The dataset will maintain a strong reference to us while we're needed.
122  dataset->addDimension(this);
123  if(!_orgName.empty()){
124  processRenameDimension(*_parser);
125  }
126 }
127 
128 void DimensionElement::processRenameDimension(NCMLParser& p)
129 {
130  BESDEBUG("ncml",
131  "DimensionElement::processRenameDimension() called on " + toString() << " at scope=" << p.getTypedScopeString() << endl);
132 
133  BESDEBUG("ncml", "Renaming dimension " << _orgName << " to " << name() << endl);
134  // Loop over variables
135  DDS* cDDS = p.getDDSForCurrentDataset();
136  DDS::Vars_iter varit;
137  for (varit = cDDS->var_begin(); varit != cDDS->var_end(); varit++) {
138  Array* varArray = 0;
139  if ((*varit)->type() == dods_array_c)
140  varArray = dynamic_cast<Array *>(*varit);
141  Array::Dim_iter ait;
142  // Loop over dimensions
143  for (ait = varArray->dim_begin(); ait != varArray->dim_end(); ++ait) {
144  if((*ait).name == name()){
145  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
146  "Renaming dimension failed for element=" + toString() + " since a dimension with name=" + (*ait).name
147  + " already exists at current parser scope=" + p.getScopeString());
148  }
149  if((*ait).name == _orgName){
150  varArray->rename_dim(_orgName, name());
151  }
152  }
153  }
154 }
155 
156 void DimensionElement::handleContent(const string& content)
157 {
158  // BESDEBUG("ncml", "DimensionElement::handleContent called...");
159  if (!NCMLUtil::isAllWhitespace(content)) {
160  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
161  "Got illegal (non-whitespace) content in element " + toString());
162  }
163 }
164 
165 void DimensionElement::handleEnd()
166 {
167  // BESDEBUG("ncml", "DimensionElement::handleEnd called...");
168 }
169 
170 string DimensionElement::toString() const
171 {
172  string ret = "<" + _sTypeName + " ";
173  ret += NCMLElement::printAttributeIfNotEmpty("name", name());
174  ret += NCMLElement::printAttributeIfNotEmpty("length", _length);
175  ret += NCMLElement::printAttributeIfNotEmpty("isShared", _isShared);
176  ret += NCMLElement::printAttributeIfNotEmpty("isVariableLength", _isVariableLength);
177  ret += NCMLElement::printAttributeIfNotEmpty("isUnlimited", _isUnlimited);
178  ret += NCMLElement::printAttributeIfNotEmpty("orgName", _orgName);
179  ret += " >";
180  return ret;
181 }
182 
183 bool DimensionElement::checkDimensionsMatch(const DimensionElement& rhs) const
184 {
185  return ((this->name() == rhs.name()) && (this->getSize() == rhs.getSize()));
186 }
187 
188 const string&
189 DimensionElement::name() const
190 {
191  return _dim.name;
192 }
193 
194 unsigned int DimensionElement::getLengthNumeric() const
195 {
196  return _dim.size;
197 }
198 
199 unsigned int DimensionElement::getSize() const
200 {
201  return getLengthNumeric();
202 }
203 
206 #if 0
207 void DimensionElement::parseAndCacheDimension()
208 {
209  stringstream sis;
210  sis.str(_length);
211  sis >> _dim.size;
212  if (sis.fail()) {
213  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
214  "Element " + toString() + " failed to parse the length attribute into a proper unsigned int!");
215  }
216 
217  // @TODO set the _dim.isSizeConstant from the isVariableLength, etc once we know how to use them for aggs
218  _dim.isSizeConstant = true;
219 
220  if (_isShared == "true") {
221  _dim.isShared = true;
222  }
223  else if (_isShared == "false") {
224  _dim.isShared = false;
225  }
226  else if (!_isShared.empty()) {
227  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), "dimension@isShared did not have value in {true,false}.");
228  }
229 
230 }
231 
232 void DimensionElement::validateOrThrow()
233 {
234  // Perhaps we want to warn in BESDEBUG rather than error, but I'd rather be explicit for now.
235  if (!_isShared.empty() || !_isUnlimited.empty() || !_isVariableLength.empty() || !_orgName.empty()) {
236  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
237  "Dimension element " + toString() + " has unexpected unimplemented attributes. "
238  "This version of the module only handles name, orgName and length.");
239  }else if(!_length.empty() && !_orgName.empty()){
240  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
241  "Dimension element " + toString() + " has unexpected attributes orgName or length.");
242  }
243 }
244 #endif
245 
246 void DimensionElement::parseValidateAndCacheDimension()
247 {
248  // There is no name
249  if (_dim.name.empty()) {
250  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
251  "Dimension element " + toString() + "Can't have an empty name.");
252  }
253  // Perhaps we want to warn in BESDEBUG rather than error, but I'd rather be explicit for now.
254  else if (!_isShared.empty() || !_isUnlimited.empty() || !_isVariableLength.empty()) {
255  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
256  "Dimension element " + toString() + " has unexpected unimplemented attributes. "
257  "This version of the module only handles name, orgName and length.");
258  }
259  // There is only name
260  else if (_length.empty() && _orgName.empty()) {
261  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
262  "Dimension element " + toString() + " has no expected length value for new dimension or orgName value for renaming.");
263  }
264  // There are length and orgName together
265  else if(!_length.empty() && !_orgName.empty()){
266  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
267  "Dimension element " + toString() + " should not has attributes orgName and length together.");
268  }
269 
270  stringstream sis;
271  if(!_length.empty()){
272  sis.str(_length);
273  sis >> _dim.size;
274  if (sis.fail()) {
275  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
276  "Element " + toString() + " failed to parse the length attribute into a proper unsigned int!");
277  }
278  }
279 
280  // @TODO set the _dim.isSizeConstant from the isVariableLength, etc once we know how to use them for aggs
281  _dim.isSizeConstant = true;
282 
283  if (_isShared == "true") {
284  _dim.isShared = true;
285  }
286  else if (_isShared == "false") {
287  _dim.isShared = false;
288  }
289  else if (!_isShared.empty()) {
290  THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), "dimension@isShared did not have value in {true,false}.");
291  }
292 
293 }
294 
295 
296 vector<string> DimensionElement::getValidAttributes()
297 {
298  vector<string> validAttrs;
299  validAttrs.reserve(10);
300  validAttrs.push_back("name");
301  validAttrs.push_back("length");
302  validAttrs.push_back("isUnlimited");
303  validAttrs.push_back("isVariableLength");
304  validAttrs.push_back("isShared");
305  validAttrs.push_back("orgName");
306  return validAttrs;
307 }
308 }
ncml_module::NetcdfElement
Concrete class for NcML <netcdf> element.
Definition: NetcdfElement.h:62
agg_util::Dimension
Definition: Dimension.h:49
ncml_module::NetcdfElement::addDimension
void addDimension(DimensionElement *dim)
Definition: NetcdfElement.cc:340
ncml_module::NCMLParser
Definition: NCMLParser.h:158
ncml_module::XMLAttributeMap
Definition: XMLHelpers.h:93
ncml_module::DimensionElement
Definition: DimensionElement.h:55
ncml_module::NetcdfElement::getDimensionInLocalScope
const DimensionElement * getDimensionInLocalScope(const std::string &name) const
Definition: NetcdfElement.cc:310
ncml_module
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
Definition: AggregationElement.cc:72
ncml_module::XMLAttributeMap::getValueForLocalNameOrDefault
const std::string getValueForLocalNameOrDefault(const std::string &localname, const std::string &defVal="") const
Definition: XMLHelpers.cc:181