1 /**
2 * Licensed to the University Corporation for Advanced Internet
3 * Development, Inc. (UCAID) under one or more contributor license
4 * agreements. See the NOTICE file distributed with this work for
5 * additional information regarding copyright ownership.
6 *
7 * UCAID licenses this file to you under the Apache License,
8 * Version 2.0 (the "License"); you may not use this file except
9 * in compliance with the License. You may obtain a copy of the
10 * License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17 * either express or implied. See the License for the specific
18 * language governing permissions and limitations under the License.
19 */
20
21 /**
22 * AbstractXMLObject.cpp
23 *
24 * An abstract implementation of XMLObject.
25 */
26
27 #include "internal.h"
28 #include "exceptions.h"
29 #include "AbstractXMLObject.h"
30
31 #include <algorithm>
32
33 using namespace xmltooling;
34 using std::set;
35
36 using xercesc::XMLString;
37 using xercesc::XMLDateTime;
38 using xercesc::XMLException;
39
XMLObject()40 XMLObject::XMLObject()
41 {
42 }
43
~XMLObject()44 XMLObject::~XMLObject()
45 {
46 }
47
releaseThisandParentDOM() const48 void XMLObject::releaseThisandParentDOM() const
49 {
50 releaseDOM();
51 releaseParentDOM(true);
52 }
53
releaseThisAndChildrenDOM() const54 void XMLObject::releaseThisAndChildrenDOM() const
55 {
56 releaseChildrenDOM(true);
57 releaseDOM();
58 }
59
getLang() const60 const XMLCh* XMLObject::getLang() const
61 {
62 return nullptr;
63 }
64
setNil(const XMLCh * value)65 void XMLObject::setNil(const XMLCh* value)
66 {
67 if (value) {
68 switch (*value) {
69 case xercesc::chLatin_t:
70 nil(xmlconstants::XML_BOOL_TRUE);
71 break;
72 case xercesc::chLatin_f:
73 nil(xmlconstants::XML_BOOL_FALSE);
74 break;
75 case xercesc::chDigit_1:
76 nil(xmlconstants::XML_BOOL_ONE);
77 break;
78 case xercesc::chDigit_0:
79 nil(xmlconstants::XML_BOOL_ZERO);
80 break;
81 default:
82 nil(xmlconstants::XML_BOOL_NULL);
83 }
84 }
85 else {
86 nil(xmlconstants::XML_BOOL_NULL);
87 }
88 }
89
AbstractXMLObject(const XMLCh * nsURI,const XMLCh * localName,const XMLCh * prefix,const QName * schemaType)90 AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType)
91 : m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT ".XMLObject")),
92 m_schemaLocation(nullptr), m_noNamespaceSchemaLocation(nullptr), m_nil(xmlconstants::XML_BOOL_NULL),
93 m_parent(nullptr), m_elementQname(nsURI, localName, prefix)
94 {
95 addNamespace(Namespace(nsURI, prefix, false, Namespace::VisiblyUsed));
96 if (schemaType) {
97 m_typeQname.reset(new QName(*schemaType));
98 addNamespace(Namespace(m_typeQname->getNamespaceURI(), m_typeQname->getPrefix(), false, Namespace::NonVisiblyUsed));
99 }
100 }
101
AbstractXMLObject(const AbstractXMLObject & src)102 AbstractXMLObject::AbstractXMLObject(const AbstractXMLObject& src)
103 : m_namespaces(src.m_namespaces), m_log(src.m_log), m_schemaLocation(XMLString::replicate(src.m_schemaLocation)),
104 m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)), m_nil(src.m_nil),
105 m_parent(nullptr), m_elementQname(src.m_elementQname),
106 m_typeQname(src.m_typeQname.get() ? new QName(*src.m_typeQname) : nullptr)
107 {
108 }
109
~AbstractXMLObject()110 AbstractXMLObject::~AbstractXMLObject()
111 {
112 xercesc::XMLString::release(&m_schemaLocation);
113 xercesc::XMLString::release(&m_noNamespaceSchemaLocation);
114 }
115
detach()116 void AbstractXMLObject::detach()
117 {
118 if (!getParent())
119 return;
120 else if (getParent()->hasParent())
121 throw XMLObjectException("Cannot detach an object whose parent is itself a child.");
122
123 // Pull ourselves out of the parent and then blast him.
124 getParent()->removeChild(this);
125 delete m_parent;
126 m_parent = nullptr;
127 }
128
getElementQName() const129 const QName& AbstractXMLObject::getElementQName() const
130 {
131 return m_elementQname;
132 }
133
getNamespaces() const134 const set<Namespace>& AbstractXMLObject::getNamespaces() const
135 {
136 return m_namespaces;
137 }
138
addNamespace(const Namespace & ns) const139 void AbstractXMLObject::addNamespace(const Namespace& ns) const
140 {
141 for (set<Namespace>::const_iterator n = m_namespaces.begin(); n != m_namespaces.end(); ++n) {
142 // Look for the prefix in the existing set.
143 if (XMLString::equals(ns.getNamespacePrefix(), n->getNamespacePrefix())) {
144 // See if it's the same declaration, and overlay various properties if so.
145 if (XMLString::equals(ns.getNamespaceURI(), n->getNamespaceURI())) {
146 if (ns.alwaysDeclare())
147 const_cast<Namespace&>(*n).setAlwaysDeclare(true);
148 switch (ns.usage()) {
149 case Namespace::Indeterminate:
150 break;
151 case Namespace::VisiblyUsed:
152 const_cast<Namespace&>(*n).setUsage(Namespace::VisiblyUsed);
153 break;
154 case Namespace::NonVisiblyUsed:
155 if (n->usage() == Namespace::Indeterminate)
156 const_cast<Namespace&>(*n).setUsage(Namespace::NonVisiblyUsed);
157 break;
158 }
159 }
160 return;
161 }
162 }
163
164 // If the prefix is now, go ahead and add it.
165 m_namespaces.insert(ns);
166 }
167
removeNamespace(const Namespace & ns)168 void AbstractXMLObject::removeNamespace(const Namespace& ns)
169 {
170 m_namespaces.erase(ns);
171 }
172
getSchemaType() const173 const QName* AbstractXMLObject::getSchemaType() const
174 {
175 return m_typeQname.get();
176 }
177
getXMLID() const178 const XMLCh* AbstractXMLObject::getXMLID() const
179 {
180 return nullptr;
181 }
182
getNil() const183 xmlconstants::xmltooling_bool_t AbstractXMLObject::getNil() const
184 {
185 return m_nil;
186 }
187
nil(xmlconstants::xmltooling_bool_t value)188 void AbstractXMLObject::nil(xmlconstants::xmltooling_bool_t value)
189 {
190 if (m_nil != value) {
191 releaseThisandParentDOM();
192 m_nil = value;
193 }
194 }
195
hasParent() const196 bool AbstractXMLObject::hasParent() const
197 {
198 return m_parent != nullptr;
199 }
200
getParent() const201 XMLObject* AbstractXMLObject::getParent() const
202 {
203 return m_parent;
204 }
205
setParent(XMLObject * parent)206 void AbstractXMLObject::setParent(XMLObject* parent)
207 {
208 m_parent = parent;
209 }
210
prepareForAssignment(XMLCh * oldValue,const XMLCh * newValue)211 XMLCh* AbstractXMLObject::prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue)
212 {
213 if (!XMLString::equals(oldValue,newValue)) {
214 releaseThisandParentDOM();
215 XMLCh* newString = XMLString::replicate(newValue);
216 XMLString::release(&oldValue);
217 return newString;
218 }
219 return oldValue;
220 }
221
prepareForAssignment(QName * oldValue,const QName * newValue)222 QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* newValue)
223 {
224 if (!oldValue) {
225 if (newValue) {
226 releaseThisandParentDOM();
227 addNamespace(Namespace(newValue->getNamespaceURI(), newValue->getPrefix(), false, Namespace::NonVisiblyUsed));
228 return new QName(*newValue);
229 }
230 return nullptr;
231 }
232
233 delete oldValue;
234 releaseThisandParentDOM();
235 if (newValue) {
236 // Attach a non-visibly used namespace.
237 addNamespace(Namespace(newValue->getNamespaceURI(), newValue->getPrefix(), false, Namespace::NonVisiblyUsed));
238 return new QName(*newValue);
239 }
240 return nullptr;
241 }
242
prepareForAssignment(XMLDateTime * oldValue,const XMLDateTime * newValue)243 XMLDateTime* AbstractXMLObject::prepareForAssignment(XMLDateTime* oldValue, const XMLDateTime* newValue)
244 {
245 if (!oldValue) {
246 if (newValue) {
247 releaseThisandParentDOM();
248 try {
249 return new XMLDateTime(*newValue);
250 }
251 catch (const XMLException& e) {
252 auto_ptr_char temp(e.getMessage());
253 throw XMLObjectException(temp.get() ? temp.get() : "XMLException duplicating XMLDateTime object");
254 }
255 }
256 return nullptr;
257 }
258
259 releaseThisandParentDOM();
260
261 // Avoid deleting existing object until new one is safely created.
262 XMLDateTime* ret = nullptr;
263 try {
264 if (newValue)
265 ret = new XMLDateTime(*newValue);
266 }
267 catch (const XMLException& e) {
268 auto_ptr_char temp(e.getMessage());
269 throw XMLObjectException(temp.get() ? temp.get() : "XMLException duplicating XMLDateTime object");
270 }
271
272 delete oldValue;
273 return ret;
274 }
275
prepareForAssignment(XMLDateTime * oldValue,time_t newValue,bool duration)276 XMLDateTime* AbstractXMLObject::prepareForAssignment(XMLDateTime* oldValue, time_t newValue, bool duration)
277 {
278 // Avoid deleting existing object until new one is safely created.
279 XMLDateTime* ret = nullptr;
280 try {
281 ret = new XMLDateTime(newValue, duration);
282 if (duration)
283 ret->parseDuration();
284 else
285 ret->parseDateTime();
286 }
287 catch (const XMLException& e) {
288 auto_ptr_char temp(e.getMessage());
289 throw XMLObjectException(temp.get() ? temp.get() : "XMLException creating XMLDateTime object");
290 }
291
292 delete oldValue;
293 releaseThisandParentDOM();
294 return ret;
295 }
296
prepareForAssignment(XMLDateTime * oldValue,const XMLCh * newValue,bool duration)297 XMLDateTime* AbstractXMLObject::prepareForAssignment(XMLDateTime* oldValue, const XMLCh* newValue, bool duration)
298 {
299 if (!newValue || !*newValue) {
300 delete oldValue;
301 releaseThisandParentDOM();
302 return nullptr;
303 }
304
305 // Avoid deleting existing object until new one is safely created.
306 XMLDateTime* ret = nullptr;
307 try {
308 ret = new XMLDateTime(newValue);
309 if (duration)
310 ret->parseDuration();
311 else
312 ret->parseDateTime();
313 }
314 catch (const XMLException& e) {
315 auto_ptr_char temp(e.getMessage());
316 throw XMLObjectException(temp.get() ? temp.get() : "XMLException creating XMLDateTime object");
317 }
318
319 delete oldValue;
320 releaseThisandParentDOM();
321 return ret;
322 }
323
prepareForAssignment(XMLObject * oldValue,XMLObject * newValue)324 XMLObject* AbstractXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObject* newValue)
325 {
326 if (newValue && newValue->hasParent())
327 throw XMLObjectException("child XMLObject cannot be added - it is already the child of another XMLObject");
328
329 if (!oldValue) {
330 if (newValue) {
331 releaseThisandParentDOM();
332 newValue->setParent(this);
333 }
334 return newValue;
335 }
336
337 if (oldValue != newValue) {
338 delete oldValue;
339 releaseThisandParentDOM();
340 if (newValue)
341 newValue->setParent(this);
342 }
343
344 return newValue;
345 }
346