bes Updated for version 3.20.13
DimensionElement.cc
1
2// 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 <libdap/Array.h>
36
37using std::string;
38using std::stringstream;
39
40namespace ncml_module {
41// the parse name of the element
42const string DimensionElement::_sTypeName = "dimension";
43const vector<string> DimensionElement::_sValidAttributes = getValidAttributes();
44
45DimensionElement::DimensionElement() :
46 NCMLElement(0), _length("0"), _orgName(""), _isUnlimited(""), _isShared(""), _isVariableLength(""), _dim()
47{
48}
49
50DimensionElement::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
56DimensionElement::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
65DimensionElement::~DimensionElement()
66{
67}
68
69const string& DimensionElement::getTypeName() const
70{
71 return _sTypeName;
72}
73
75DimensionElement::clone() const
76{
77 return new DimensionElement(*this);
78}
79
80void 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
96void 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
128void 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
156void 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
165void DimensionElement::handleEnd()
166{
167 // BESDEBUG("ncml", "DimensionElement::handleEnd called...");
168}
169
170string 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
183bool DimensionElement::checkDimensionsMatch(const DimensionElement& rhs) const
184{
185 return ((this->name() == rhs.name()) && (this->getSize() == rhs.getSize()));
186}
187
188const string&
189DimensionElement::name() const
190{
191 return _dim.name;
192}
193
194unsigned int DimensionElement::getLengthNumeric() const
195{
196 return _dim.size;
197}
198
199unsigned int DimensionElement::getSize() const
200{
201 return getLengthNumeric();
202}
203
206#if 0
207void 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
232void 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
246void 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
296vector<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}
Concrete class for NcML <netcdf> element.
Definition: NetcdfElement.h:64
void addDimension(DimensionElement *dim)
const DimensionElement * getDimensionInLocalScope(const std::string &name) const
const std::string getValueForLocalNameOrDefault(const std::string &localname, const std::string &defVal="") const
Definition: XMLHelpers.cc:181
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...