32#include <libdap/BaseType.h>
33#include <BESDapResponse.h>
35#include "AggMemberDataset.h"
36#include "AggMemberDatasetDDSWrapper.h"
37#include "AggMemberDatasetSharedDDSWrapper.h"
38#include "AggMemberDatasetUsingLocationRef.h"
39#include "AggregationElement.h"
40#include "DimensionElement.h"
41#include "NetcdfElement.h"
43#include "NCMLParser.h"
45#include "VariableElement.h"
56const string NetcdfElement::_sTypeName =
"netcdf";
57const vector<string> NetcdfElement::_sValidAttributes = getValidAttributes();
59NetcdfElement::NetcdfElement() :
60 NCMLElement(0), _location(
""), _id(
""), _title(
""), _ncoords(
""), _enhance(
""), _addRecords(
""), _coordValue(
""), _fmrcDefinition(
61 ""), _gotMetadataDirective(false), _weOwnResponse(false), _loaded(false), _response(0), _aggregation(0), _parentAgg(
62 0), _dimensions(), _variableValidator(this)
66NetcdfElement::NetcdfElement(
const NetcdfElement& proto) :
68 proto._id), _title(proto._title), _ncoords(proto._ncoords), _enhance(proto._enhance), _addRecords(
69 proto._addRecords), _coordValue(proto._coordValue), _fmrcDefinition(proto._fmrcDefinition), _gotMetadataDirective(
70 false), _weOwnResponse(false), _loaded(false), _response(0), _aggregation(0), _parentAgg(0)
71 , _dimensions(), _variableValidator(this)
76 if (proto._response) {
77 THROW_NCML_INTERNAL_ERROR(
"Can't clone() a NetcdfElement that contains a response!");
81 if (proto._aggregation.get()) {
82 setChildAggregation(proto._aggregation.get()->clone());
86 vector<DimensionElement*>::const_iterator endIt = proto._dimensions.end();
87 vector<DimensionElement*>::const_iterator it;
88 for (it = proto._dimensions.begin(); it != endIt; ++it) {
89 DimensionElement* elt = *it;
90 addDimension(elt->clone());
94NetcdfElement::~NetcdfElement()
96 BESDEBUG(
"ncml:memory",
"~NetcdfElement called...");
99 SAFE_DELETE(_response);
109NetcdfElement::getTypeName()
const
115NetcdfElement::clone()
const
123 validateAttributes(attrs, _sValidAttributes);
136 throwOnUnsupportedAttributes();
139void NetcdfElement::handleBegin()
141 BESDEBUG(
"ncml",
"NetcdfElement::handleBegin on " << toString() << endl);
145 if (p.getRootDataset() && !p.isScopeAggregation()) {
146 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
147 "Got a nested <netcdf> element which was NOT a direct child of an <aggregation>!");
152 p.pushCurrentDataset(
this);
156 validateAttributeContextOrThrow();
159void NetcdfElement::handleContent(
const string& content)
161 if (!NCMLUtil::isAllWhitespace(content)) {
162 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
163 "Got non-whitespace for element content and didn't expect it. Element=" + toString() +
" content=\""
168void NetcdfElement::handleEnd()
170 BESDEBUG(
"ncml",
"NetcdfElement::handleEnd called!" << endl);
172 if (!_parser->isScopeNetcdf()) {
173 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
"Got close of <netcdf> node while not within one!");
179 if (_aggregation.get()) {
180 _aggregation->processParentDatasetComplete();
186 _variableValidator.validate();
190 _parser->popCurrentDataset(
this);
196string NetcdfElement::toString()
const
198 return "<" + _sTypeName +
" " +
"location=\"" + _location +
"\""
200 printAttributeIfNotEmpty(
"id", _id) + printAttributeIfNotEmpty(
"title", _title)
201 + printAttributeIfNotEmpty(
"enhance", _enhance) + printAttributeIfNotEmpty(
"addRecords", _addRecords)
202 + printAttributeIfNotEmpty(
"ncoords", _ncoords) + printAttributeIfNotEmpty(
"coordValue", _coordValue)
203 + printAttributeIfNotEmpty(
"fmrcDefinition", _fmrcDefinition) +
">";
207NetcdfElement::getDDS()
const
213NetcdfElement::getDDS()
217 BESDEBUG(
"ncml",
"Lazy loading DDX for location=" << location() << endl);
222 return NCMLUtil::getDDSFromEitherResponse(_response);
229bool NetcdfElement::isValid()
const
234 return _response && _parser;
237unsigned int NetcdfElement::getNcoordsAsUnsignedInt()
const
239 NCML_ASSERT_MSG(hasNcoords(),
240 "NetcdfElement::getNCoords(): called illegally when no ncoords attribute was specified!");
241 unsigned int num = 0;
242 if (!NCMLUtil::toUnsignedInt(_ncoords, num)) {
243 THROW_NCML_PARSE_ERROR(line(),
"A <netcdf> element has an invalid ncoords attribute set. Bad value was:"
244 "\"" + _ncoords +
"\"");
251 NCML_ASSERT_MSG(!_response,
"_response object should be NULL for proper logic of borrowResponseObject call!");
252 _response = pResponse;
253 _weOwnResponse =
false;
258 NCML_ASSERT_MSG(pResponse == _response,
259 "NetcdfElement::unborrowResponseObject() called with a response we are not borrowing.");
266 THROW_NCML_INTERNAL_ERROR(
267 "NetcdfElement::createResponseObject(): Called when we already had a _response! Logic error!");
273 std::unique_ptr<BESDapResponse> newResponse = _parser->getDDSLoader().makeResponseForType(type);
274 VALID_PTR(newResponse.get());
275 _response = newResponse.release();
276 _weOwnResponse =
true;
285 if (_pDatasetWrapper.empty()) {
286 if (_location.empty()) {
298 VALID_PTR(pAGM.get());
305 NCML_ASSERT(!_pDatasetWrapper.empty());
306 return _pDatasetWrapper.lock();
310NetcdfElement::getDimensionInLocalScope(
const string& name)
const
313 vector<DimensionElement*>::const_iterator endIt = _dimensions.end();
314 for (vector<DimensionElement*>::const_iterator it = _dimensions.begin(); it != endIt; ++it) {
317 if (pElt->name() == name) {
326NetcdfElement::getDimensionInFullScope(
const string& name)
const
330 elt = getDimensionInLocalScope(name);
343 if (getDimensionInLocalScope(dim->name())) {
344 THROW_NCML_INTERNAL_ERROR(
345 "NCMLParser::addDimension(): already found dimension with name while adding " + dim->
toString());
348 _dimensions.push_back(dim);
351 BESDEBUG(
"ncml",
"Added dimension to dataset. Dimension Table is now: " << printDimensions() << endl);
354string NetcdfElement::printDimensions()
const
356 string ret =
"Dimensions = {\n";
357 vector<DimensionElement*>::const_iterator endIt = _dimensions.end();
358 vector<DimensionElement*>::const_iterator it;
359 for (it = _dimensions.begin(); it != endIt; ++it) {
360 ret += (*it)->toString() +
"\n";
366void NetcdfElement::clearDimensions()
368 while (!_dimensions.empty()) {
371 _dimensions.pop_back();
373 _dimensions.resize(0);
376const std::vector<DimensionElement*>&
377NetcdfElement::getDimensionElements()
const
384 if (_aggregation.get() && throwIfExists) {
385 THROW_NCML_INTERNAL_ERROR(
386 "NetcdfElement::setAggregation: We were called but we already contain a non-NULL aggregation! Previous="
387 + _aggregation->toString() +
" and the new one is: " + agg->
toString());
398NetcdfElement::getParentDataset()
const
401 if (_parentAgg && _parentAgg->getParentDataset()) {
408NetcdfElement::getParentAggregation()
const
419NetcdfElement::getChildAggregation()
const
421 return _aggregation.get();
427NetcdfElement::getCoordValueVector(vector<T>& values)
const
433 vector<string> tokens;
434 int numToks = NCMLUtil::tokenize(_coordValue, tokens, NCMLUtil::WHITESPACE);
435 values.reserve(numToks);
437 for (
int i=0; i<numToks; ++i)
439 stringstream iss(tokens[i]);
444 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
445 "NetcdfElement::getCoordValueVector(): "
446 "Could not parse the token \"" + tokens[i] +
"\""
447 " into the required data type.");
451 values.push_back(val);
457bool NetcdfElement::getCoordValueAsDouble(
double& val)
const
459 if (_coordValue.empty()) {
463 std::istringstream iss(_coordValue);
467 if (iss.fail() || !iss.eof()) {
476void NetcdfElement::addVariableToValidateOnClose(libdap::BaseType* pNewVar,
VariableElement* pVE)
478 _variableValidator.addVariableToValidate(pNewVar, pVE);
481void NetcdfElement::setVariableGotValues(libdap::BaseType* pVarToValidate,
bool removeEntry)
483 _variableValidator.setVariableGotValues(pVarToValidate);
485 _variableValidator.removeVariableToValidate(pVarToValidate);
498 return (pLHS->location().compare(pRHS->location()) < 0);
508 return (pLHS->coordValue().compare(pRHS->coordValue()) < 0);
514void NetcdfElement::loadLocation()
516 if (_location.empty()) {
523 NCML_ASSERT_MSG(_response,
524 "NetcdfElement::loadLocation(): Requires a valid _response via borrowResponseObject() or createResponseObject() prior to call!");
529 _parser->loadLocation(_location, _parser->_responseType, _response);
534void NetcdfElement::throwOnUnsupportedAttributes()
536 const string msgStart =
"NetcdfElement: unsupported attribute: ";
537 const string msgEnd =
" was declared.";
538 if (!_enhance.empty()) {
539 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msgStart +
"enhance" + msgEnd);
541 if (!_addRecords.empty()) {
542 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msgStart +
"addRecords" + msgEnd);
546 if (!_fmrcDefinition.empty()) {
547 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), msgStart +
"fmrcDefinition" + msgEnd);
551bool NetcdfElement::validateAttributeContextOrThrow()
const
554 AggregationElement* pParentAgg = getParentAggregation();
555 if (!pParentAgg || !(pParentAgg->isJoinExistingAggregation())) {
556 THROW_NCML_PARSE_ERROR(line(),
"Cannot specify netcdf@ncoords attribute while not within a "
557 "joinExisting aggregation!");
563vector<string> NetcdfElement::getValidAttributes()
565 vector<string> validAttrs;
566 validAttrs.push_back(
"schemaLocation");
567 validAttrs.push_back(
"location");
568 validAttrs.push_back(
"id");
569 validAttrs.push_back(
"title");
570 validAttrs.push_back(
"enhance");
571 validAttrs.push_back(
"addRecords");
573 validAttrs.push_back(
"ncoords");
574 validAttrs.push_back(
"coordValue");
575 validAttrs.push_back(
"fmrcDefinition");
582typedef vector<NetcdfElement::VariableValueValidator::VVVEntry> VVVEntries;
584NetcdfElement::VariableValueValidator::VariableValueValidator(NetcdfElement* pParent) :
585 _entries(), _pParent(pParent)
592 VVVEntries::iterator it;
593 VVVEntries::iterator endIt = _entries.end();
594 for (it = _entries.begin(); it != endIt; ++it) {
596 entry._pVarElt->
unref();
607 VVVEntry* pExisting = findEntryByLibdapVar(pNewVar);
608 NCML_ASSERT_MSG(!pExisting,
609 "NetcdfElement::VariableValueValidator::addVariableToValidate: var was already added!");
614 _entries.push_back(
VVVEntry(pNewVar, pVE));
619 for (
unsigned int i = 0; i < _entries.size(); ++i) {
620 if (_entries[i]._pNewVar == pVarToRemove) {
621 _entries[i]._pVarElt->unref();
622 _entries[i] = _entries[_entries.size() - 1];
631 VALID_PTR(pVarToValidate);
632 VVVEntry* pEntry = findEntryByLibdapVar(pVarToValidate);
633 NCML_ASSERT_MSG(pEntry,
634 "NetcdfElement::VariableValueValidator::setVariableGotValues: expected to find the var name="
635 + pVarToValidate->name() +
" but we did not!");
647 VVVEntries::iterator it;
648 VVVEntries::iterator endIt = _entries.end();
649 for (it = _entries.begin(); it != endIt; ++it) {
653 THROW_NCML_PARSE_ERROR(_pParent->line(),
654 "On closing the <netcdf> element, we found a new variable name=" + entry._pNewVar->name()
656 " to the dataset but which never had values set on it. This is illegal!"
657 " Please make sure all variables in this dataset have values set on them"
658 " or that they are new coordinate variables for a joinNew aggregation.");
665NetcdfElement::VariableValueValidator::findEntryByLibdapVar(libdap::BaseType* pVarToFind)
667 VALID_PTR(pVarToFind);
668 VVVEntry* pRetVal = 0;
669 VVVEntries::iterator it;
670 VVVEntries::iterator endIt = _entries.end();
671 for (it = _entries.begin(); it != endIt; ++it) {
672 VVVEntry& entry = *it;
673 if (entry._pNewVar == pVarToFind) {
684 VALID_PTR(pVarToFind);
685 VVVEntry* pRetVal = findEntryByLibdapVar(pVarToFind);
687 return pRetVal->_pVarElt;
Represents an OPeNDAP DAP response object within the BES.
virtual int unref() const
A reference to an RCObject which automatically ref() and deref() on creation and destruction.
virtual string toString() const
NetcdfElement * setParentDataset(NetcdfElement *parent)
Private Impl.
virtual std::string toString() const
void removeVariableToValidate(libdap::BaseType *pVarToRemove)
void setVariableGotValues(libdap::BaseType *pVarToValidate)
void addVariableToValidate(libdap::BaseType *pNewVar, VariableElement *pVE)
~VariableValueValidator()
VariableElement * findVariableElementForLibdapVar(libdap::BaseType *pNewVar)
Concrete class for NcML <netcdf> element.
const DimensionElement * getDimensionInFullScope(const std::string &name) const
VariableElement * findVariableElementForLibdapVar(libdap::BaseType *pNewVar)
NetcdfElement * getParentDataset() const
Concrete class for NcML <variable> element.
bool checkGotValues() const
const std::string getValueForLocalNameOrDefault(const std::string &localname, const std::string &defVal="") const
Helper class for temporarily hijacking an existing dhi to load a DDX response for one particular file...
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...