Reducing header overuse, non-inlining selected methods (CPPOST-35).
[shibboleth/cpp-xmltooling.git] / xmltooling / AbstractXMLObject.cpp
1 /*
2 *  Copyright 2001-2009 Internet2
3  *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * AbstractXMLObject.cpp
19  *
20  * An abstract implementation of XMLObject.
21  */
22
23 #include "internal.h"
24 #include "exceptions.h"
25 #include "AbstractXMLObject.h"
26 #include "util/DateTime.h"
27
28 #include <algorithm>
29
30 using namespace xmltooling;
31 using std::set;
32
33 using xercesc::XMLString;
34
35 XMLObject::XMLObject()
36 {
37 }
38
39 XMLObject::~XMLObject()
40 {
41 }
42
43 void XMLObject::releaseThisandParentDOM() const
44 {
45     if (getDOM()) {
46         releaseDOM();
47         releaseParentDOM(true);
48     }
49 }
50
51 void XMLObject::releaseThisAndChildrenDOM() const
52 {
53     if (getDOM()) {
54         releaseChildrenDOM(true);
55         releaseDOM();
56     }
57 }
58
59 AbstractXMLObject::AbstractXMLObject(const XMLCh* nsURI, const XMLCh* localName, const XMLCh* prefix, const QName* schemaType)
60     : m_log(logging::Category::getInstance(XMLTOOLING_LOGCAT".XMLObject")),
61         m_schemaLocation(NULL), m_noNamespaceSchemaLocation(NULL), m_nil(xmlconstants::XML_BOOL_NULL),
62         m_parent(NULL), m_elementQname(nsURI, localName, prefix), m_typeQname(NULL)
63 {
64     addNamespace(Namespace(nsURI, prefix));
65     if (schemaType) {
66         m_typeQname = new QName(*schemaType);
67         addNamespace(Namespace(m_typeQname->getNamespaceURI(), m_typeQname->getPrefix()));
68     }
69 }
70
71 AbstractXMLObject::AbstractXMLObject(const AbstractXMLObject& src)
72     : m_namespaces(src.m_namespaces), m_log(src.m_log), m_schemaLocation(XMLString::replicate(src.m_schemaLocation)),
73         m_noNamespaceSchemaLocation(XMLString::replicate(src.m_noNamespaceSchemaLocation)), m_nil(src.m_nil),
74         m_parent(NULL), m_elementQname(src.m_elementQname), m_typeQname(NULL)
75 {
76     if (src.m_typeQname)
77         m_typeQname=new QName(*src.m_typeQname);
78 }
79
80 AbstractXMLObject::~AbstractXMLObject()
81 {
82     delete m_typeQname;
83     xercesc::XMLString::release(&m_schemaLocation);
84     xercesc::XMLString::release(&m_noNamespaceSchemaLocation);
85 }
86
87 void AbstractXMLObject::detach()
88 {
89     if (!getParent())
90         return;
91     else if (getParent()->hasParent())
92         throw XMLObjectException("Cannot detach an object whose parent is itself a child.");
93
94     // Pull ourselves out of the parent and then blast him.
95     getParent()->removeChild(this);
96     delete m_parent;
97     m_parent = NULL;
98 }
99
100 const QName& AbstractXMLObject::getElementQName() const
101 {
102     return m_elementQname;
103 }
104
105 const set<Namespace>& AbstractXMLObject::getNamespaces() const
106 {
107     return m_namespaces;
108 }
109
110 void XMLObject::setNil(const XMLCh* value)
111 {
112     if (value) {
113         switch (*value) {
114             case xercesc::chLatin_t:
115                 nil(xmlconstants::XML_BOOL_TRUE);
116                 break;
117             case xercesc::chLatin_f:
118                 nil(xmlconstants::XML_BOOL_FALSE);
119                 break;
120             case xercesc::chDigit_1:
121                 nil(xmlconstants::XML_BOOL_ONE);
122                 break;
123             case xercesc::chDigit_0:
124                 nil(xmlconstants::XML_BOOL_ZERO);
125                 break;
126             default:
127                 nil(xmlconstants::XML_BOOL_NULL);
128         }
129     }
130     else {
131         nil(xmlconstants::XML_BOOL_NULL);
132     }
133 }
134
135 void AbstractXMLObject::addNamespace(const Namespace& ns) const
136 {
137     std::set<Namespace>::iterator i = m_namespaces.find(ns);
138     if (i == m_namespaces.end())
139         m_namespaces.insert(ns);
140     else if (ns.alwaysDeclare())
141         const_cast<Namespace&>(*i).setAlwaysDeclare(true);
142 }
143
144 void AbstractXMLObject::removeNamespace(const Namespace& ns)
145 {
146     m_namespaces.erase(ns);
147 }
148
149 const QName* AbstractXMLObject::getSchemaType() const
150 {
151     return m_typeQname;
152 }
153
154 const XMLCh* AbstractXMLObject::getXMLID() const
155 {
156     return NULL;
157 }
158
159 xmlconstants::xmltooling_bool_t AbstractXMLObject::getNil() const
160 {
161     return m_nil;
162 }
163
164 void AbstractXMLObject::nil(xmlconstants::xmltooling_bool_t value)
165 {
166     if (m_nil != value) {
167         releaseThisandParentDOM();
168         m_nil = value;
169     }
170 }
171
172 bool AbstractXMLObject::hasParent() const
173 {
174     return m_parent != NULL;
175 }
176
177 XMLObject* AbstractXMLObject::getParent() const
178 {
179     return m_parent;
180 }
181
182 void AbstractXMLObject::setParent(XMLObject* parent)
183 {
184     m_parent = parent;
185 }
186
187 XMLCh* AbstractXMLObject::prepareForAssignment(XMLCh* oldValue, const XMLCh* newValue)
188 {
189     if (!XMLString::equals(oldValue,newValue)) {
190         releaseThisandParentDOM();
191         XMLCh* newString = XMLString::replicate(newValue);
192         XMLString::release(&oldValue);
193         return newString;
194     }
195     return oldValue;
196 }
197
198 QName* AbstractXMLObject::prepareForAssignment(QName* oldValue, const QName* newValue)
199 {
200     if (!oldValue) {
201         if (newValue) {
202             releaseThisandParentDOM();
203             Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());
204             addNamespace(newNamespace);
205             return new QName(*newValue);
206         }
207         return NULL;
208     }
209
210     delete oldValue;
211     releaseThisandParentDOM();
212     if (newValue) {
213         Namespace newNamespace(newValue->getNamespaceURI(), newValue->getPrefix());
214         addNamespace(newNamespace);
215         return new QName(*newValue);
216     }
217     return NULL;
218 }
219
220 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const DateTime* newValue)
221 {
222     if (!oldValue) {
223         if (newValue) {
224             releaseThisandParentDOM();
225             return new DateTime(*newValue);
226         }
227         return NULL;
228     }
229
230     delete oldValue;
231     releaseThisandParentDOM();
232     return newValue ? new DateTime(*newValue) : NULL;
233 }
234
235 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, time_t newValue, bool duration)
236 {
237     delete oldValue;
238     releaseThisandParentDOM();
239     DateTime* ret = new DateTime(newValue, duration);
240     if (duration)
241         ret->parseDuration();
242     else
243         ret->parseDateTime();
244     return ret;
245 }
246
247 DateTime* AbstractXMLObject::prepareForAssignment(DateTime* oldValue, const XMLCh* newValue, bool duration)
248 {
249     delete oldValue;
250     releaseThisandParentDOM();
251     DateTime* ret = new DateTime(newValue);
252     if (duration)
253         ret->parseDuration();
254     else
255         ret->parseDateTime();
256     return ret;
257 }
258
259 XMLObject* AbstractXMLObject::prepareForAssignment(XMLObject* oldValue, XMLObject* newValue)
260 {
261     if (newValue && newValue->hasParent())
262         throw XMLObjectException("child XMLObject cannot be added - it is already the child of another XMLObject");
263
264     if (!oldValue) {
265         if (newValue) {
266             releaseThisandParentDOM();
267             newValue->setParent(this);
268         }
269         return newValue;
270     }
271
272     if (oldValue != newValue) {
273         delete oldValue;
274         releaseThisandParentDOM();
275         if (newValue)
276             newValue->setParent(this);
277     }
278
279     return newValue;
280 }