bes  Updated for version 3.20.6
NCMLElement.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 
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 
47 using std::string;
48 using std::vector;
49 
50 namespace ncml_module {
51 
53 
54 NCMLElement::Factory::Factory() :
55  _protos()
56 {
57  initialize();
58 }
59 
60 NCMLElement::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 
70 void 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 
89 NCMLElement::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 
101 void 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 
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 
138 NCMLElement::NCMLElement(NCMLParser* p) :
139  RCObject(), _parser(p)
140 {
141 }
142 
143 NCMLElement::NCMLElement(const NCMLElement& proto) :
144  RCObjectInterface(), RCObject(proto), _parser(proto._parser)
145 {
146 }
147 
148 NCMLElement::~NCMLElement()
149 {
150  _parser = 0;
151 }
152 
153 void 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 
160 int NCMLElement::line() const
161 {
162  return _parser->getParseLineNumber();
163 }
164 
165 void 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 
174 bool 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 
212 std::string NCMLElement::printAttributeIfNotEmpty(const std::string& attrName, const std::string& attrValue)
213 {
214  return ((attrValue.empty()) ? ("") : (" " + attrName + "=\"" + attrValue + "\""));
215 }
216 
217 bool 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 
229 bool 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
ncml_module::NCMLElement::Factory::makeElement
RCPtr< NCMLElement > makeElement(const std::string &eltTypeName, const XMLAttributeMap &attrs, NCMLParser &parser)
Definition: NCMLElement.cc:117
ncml_module::NCMLElement::printAttributeIfNotEmpty
static std::string printAttributeIfNotEmpty(const std::string &attrName, const std::string &attrValue)
Definition: NCMLElement.cc:212
ncml_module::NCMLElement::handleContent
virtual void handleContent(const std::string &content)
Definition: NCMLElement.cc:165
ncml_module::NCMLElement::line
int line() const
Definition: NCMLElement.cc:160
ncml_module::NCMLParser
Definition: NCMLParser.h:158
ncml_module::XMLAttributeMap
Definition: XMLHelpers.h:93
agg_util::RCObject
A base class for a simple reference counted object.
Definition: RCObject.h:164
ncml_module::NCMLElement::areAllAttributesValid
static bool areAllAttributesValid(const XMLAttributeMap &attrMap, const std::vector< std::string > &validAttrs, std::vector< std::string > *pInvalidAttributes=0)
Definition: NCMLElement.cc:229
ncml_module::NCMLElement
Base class for NcML element concrete classes.
Definition: NCMLElement.h:61
ncml_module::NCMLElement::toString
virtual std::string toString() const =0
ncml_module::NCMLUtil::isAllWhitespace
static bool isAllWhitespace(const std::string &str)
Definition: NCMLUtil.cc:103
ncml_module
NcML Parser for adding/modifying/removing metadata (attributes) to existing local datasets using NcML...
Definition: AggregationElement.cc:72
agg_util::RCPtr
A reference to an RCObject which automatically ref() and deref() on creation and destruction.
Definition: RCObject.h:284
ncml_module::NCMLElement::getTypeName
virtual const std::string & getTypeName() const =0
ncml_module::NCMLParser::getParseLineNumber
int getParseLineNumber() const
Definition: NCMLParser.cc:200
ncml_module::NCMLElement::isValidAttribute
static bool isValidAttribute(const std::vector< std::string > &validAttrs, const std::string &attr)
Definition: NCMLElement.cc:217
ncml_module::NCMLElement::validateAttributes
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