bes Updated for version 3.20.13
NCMLElement.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
30#include "NCMLDebug.h"
31#include "NCMLElement.h"
32#include "NCMLParser.h"
33
34// Factory Includes for Concrete Subtypes
35#include "AggregationElement.h"
36#include "AttributeElement.h"
37#include "DimensionElement.h"
38#include "ExplicitElement.h"
39#include "NetcdfElement.h"
40#include "ReadMetadataElement.h"
41#include "RemoveElement.h"
42#include "ScanElement.h"
43#include "ValuesElement.h"
44#include "VariableAggElement.h"
45#include "VariableElement.h"
46
47using std::string;
48using std::vector;
49
50namespace ncml_module {
51
53
54NCMLElement::Factory::Factory() :
55 _protos()
56{
57 initialize();
58}
59
60NCMLElement::Factory::~Factory()
61{
62 // Delete all the prototype objects
63 while (!_protos.empty()) {
64 const NCMLElement* proto = _protos.back();
65 delete proto;
66 _protos.pop_back();
67 }
68}
69
70void NCMLElement::Factory::addPrototype(const NCMLElement* proto)
71{
72 VALID_PTR(proto);
73
74 // If a proto already exists, erase and delete it so we can add the new one.
75 const string& typeName = proto->getTypeName();
76 ProtoList::iterator existingIt = findPrototype(typeName);
77 if (existingIt != _protos.end()) {
78 BESDEBUG("ncml",
79 "WARNING: Already got NCMLElement prototype for type=" << typeName << " so replacing with new one." << endl);
80 const NCMLElement* oldOne = *existingIt;
81 _protos.erase(existingIt);
82 delete oldOne;
83 }
84
85 // Now it's safe to add new one
86 _protos.push_back(proto);
87}
88
89NCMLElement::Factory::ProtoList::iterator NCMLElement::Factory::findPrototype(const std::string& elementTypeName)
90{
91 ProtoList::iterator it = _protos.end();
92 ProtoList::iterator endIt = _protos.end();
93 for (it = _protos.begin(); it != endIt; ++it) {
94 if ((*it)->getTypeName() == elementTypeName) {
95 return it;
96 }
97 }
98 return endIt;
99}
100
101void NCMLElement::Factory::initialize()
102{
103 // Enter prototypes for all the concrete subclasses
104 addPrototype(new RemoveElement());
105 addPrototype(new ExplicitElement());
106 addPrototype(new ReadMetadataElement());
107 addPrototype(new NetcdfElement());
108 addPrototype(new AttributeElement());
109 addPrototype(new VariableElement());
110 addPrototype(new ValuesElement());
111 addPrototype(new DimensionElement());
112 addPrototype(new AggregationElement());
113 addPrototype(new VariableAggElement());
114 addPrototype(new ScanElement());
115}
116
117RCPtr<NCMLElement> NCMLElement::Factory::makeElement(const string& eltTypeName, const XMLAttributeMap& attrs,
118 NCMLParser& parser)
119{
120 ProtoList::const_iterator it = findPrototype(eltTypeName);
121 if (it == _protos.end()) // not found
122 {
123 BESDEBUG("ncml", "NCMLElement::Factory cannot find prototype for element type=" << eltTypeName << endl);
124 return RCPtr<NCMLElement>(0);
125 }
126
127 RCPtr<NCMLElement> newElt = RCPtr<NCMLElement>((*it)->clone());
128 VALID_PTR(newElt.get());
129 // set the parser first if given it since exceptions use it
130 newElt->setParser(&parser);
131 newElt->setAttributes(attrs);
132
133 return newElt; //relinquish
134}
135
137
138NCMLElement::NCMLElement(NCMLParser* p) :
139 RCObject(), _parser(p)
140{
141}
142
143NCMLElement::NCMLElement(const NCMLElement& proto) :
144 RCObjectInterface(), RCObject(proto), _parser(proto._parser)
145{
146}
147
148NCMLElement::~NCMLElement()
149{
150 _parser = 0;
151}
152
153void NCMLElement::setParser(NCMLParser* p)
154{
155 // make sure we only call it once when we create it in the parser.
156 NCML_ASSERT_MSG(!_parser, "NCMLElement::setParser() called more than once. Logic bug!");
157 _parser = p;
158}
159
161{
162 return _parser->getParseLineNumber();
163}
164
165void NCMLElement::handleContent(const string& content)
166{
167 if (!NCMLUtil::isAllWhitespace(content)) {
168 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(),
169 "Got non-whitespace for element content and didn't expect it. Element=" + toString() + " content=\""
170 + content + "\"");
171 }
172}
173
174bool NCMLElement::validateAttributes(const XMLAttributeMap& attrs, const vector<string>& validAttrs,
175 vector<string>* pInvalidAttrs /* = 0 */, bool printInvalid /* = true */, bool throwOnError /* = true */)
176{
177 bool ret = true; // optimism in the face of uncertainty!
178
179 // Make sure we always have an array to put results in.
180 vector<string> myInvalidAttrs;
181 if (!pInvalidAttrs) {
182 pInvalidAttrs = &myInvalidAttrs;
183 }
184 VALID_PTR(pInvalidAttrs);
185
186 // Check the lists
187 if (!areAllAttributesValid(attrs, validAttrs, pInvalidAttrs)) {
188 // If any is wrong, cons up the list of errors.
189 ret = false;
190
191 // If we need to print or throw the error cases, then build the list up
192 if (printInvalid || throwOnError) {
193 std::ostringstream oss;
194 oss << "Got invalid attribute for element = " << getTypeName();
195 oss << " The invalid attributes were: {";
196 for (unsigned int i = 0; i < pInvalidAttrs->size(); ++i) {
197 oss << (*pInvalidAttrs)[i];
198 if (i < pInvalidAttrs->size() - 1) oss << ", ";
199 }
200 oss << "}";
201 if (printInvalid) {
202 BESDEBUG("ncml", oss.str() << endl);
203 }
204 if (throwOnError) {
205 THROW_NCML_PARSE_ERROR(_parser->getParseLineNumber(), oss.str());
206 }
207 }
208 }
209 return ret;
210}
211
212std::string NCMLElement::printAttributeIfNotEmpty(const std::string& attrName, const std::string& attrValue)
213{
214 return ((attrValue.empty()) ? ("") : (" " + attrName + "=\"" + attrValue + "\""));
215}
216
217bool NCMLElement::isValidAttribute(const std::vector<string>& validAttrs, const string& attr)
218{
219 bool ret = false;
220 for (unsigned int i = 0; i < validAttrs.size(); ++i) {
221 if (attr == validAttrs[i]) {
222 ret = true;
223 break;
224 }
225 }
226 return ret;
227}
228
229bool NCMLElement::areAllAttributesValid(const XMLAttributeMap& attrMap, const std::vector<string>& validAttrs,
230 std::vector<string>* pInvalidAttributes/*=0*/)
231{
232 if (pInvalidAttributes) {
233 pInvalidAttributes->resize(0);
234 }
235 bool ret = true;
236 XMLAttributeMap::const_iterator it;
237 XMLAttributeMap::const_iterator endIt = attrMap.end();
238 for (it = attrMap.begin(); it != endIt; ++it) {
239 const string& attr = it->localname;
240 if (!isValidAttribute(validAttrs, attr)) {
241 ret = false;
242 if (pInvalidAttributes) {
243 pInvalidAttributes->push_back(attr);
244 }
245 else {
246 // Early exit only if we don't need the full list of bad ones...
247 break;
248 }
249 }
250 }
251 return ret;
252}
253
254} // namespace ncml_module
A base class for a simple reference counted object.
Definition: RCObject.h:165
A reference to an RCObject which automatically ref() and deref() on creation and destruction.
Definition: RCObject.h:284
Base class for NcML element concrete classes.
Definition: NCMLElement.h:61
virtual void handleContent(const std::string &content)
Definition: NCMLElement.cc:165
static bool isValidAttribute(const std::vector< std::string > &validAttrs, const std::string &attr)
Definition: NCMLElement.cc:217
virtual bool validateAttributes(const XMLAttributeMap &attrs, const std::vector< std::string > &validAttrs, std::vector< std::string > *pInvalidAttrs=0, bool printInvalid=true, bool throwOnError=true)
Definition: NCMLElement.cc:174
virtual const std::string & getTypeName() const =0
virtual std::string toString() const =0
static std::string printAttributeIfNotEmpty(const std::string &attrName, const std::string &attrValue)
Definition: NCMLElement.cc:212
static bool areAllAttributesValid(const XMLAttributeMap &attrMap, const std::vector< std::string > &validAttrs, std::vector< std::string > *pInvalidAttributes=0)
Definition: NCMLElement.cc:229
int getParseLineNumber() const
Definition: NCMLParser.cc:200
static bool isAllWhitespace(const std::string &str)
Definition: NCMLUtil.cc:105
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...