1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.xml;
18
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Set;
22
23 import javax.xml.namespace.QName;
24
25 import org.opensaml.xml.util.DatatypeHelper;
26 import org.opensaml.xml.util.IDIndex;
27 import org.opensaml.xml.util.LazySet;
28 import org.opensaml.xml.util.XMLHelper;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.w3c.dom.Element;
32
33
34
35
36 public abstract class AbstractXMLObject implements XMLObject {
37
38
39 private final Logger log = LoggerFactory.getLogger(AbstractXMLObject.class);
40
41
42 private XMLObject parent;
43
44
45 private QName elementQname;
46
47
48 private String schemaLocation;
49
50
51 private String noNamespaceSchemaLocation;
52
53
54 private QName typeQname;
55
56
57 private Set<Namespace> namespaces;
58
59
60 private Element dom;
61
62
63
64
65
66 private final IDIndex idIndex;
67
68
69
70
71
72
73
74
75 protected AbstractXMLObject(String namespaceURI, String elementLocalName, String namespacePrefix) {
76 idIndex = new IDIndex(this);
77 namespaces = new LazySet<Namespace>();
78 elementQname = XMLHelper.constructQName(namespaceURI, elementLocalName, namespacePrefix);
79 if(namespaceURI != null){
80 addNamespace(new Namespace(namespaceURI, namespacePrefix));
81 setElementNamespacePrefix(namespacePrefix);
82 }
83 }
84
85
86 public void addNamespace(Namespace newNamespace) {
87 if(newNamespace == null){
88 return;
89 }
90
91 if(namespaces.size() == 0){
92 namespaces.add(newNamespace);
93 return;
94 }
95
96 for(Namespace namespace : namespaces){
97 if(DatatypeHelper.safeEquals(namespace.getNamespaceURI(), newNamespace.getNamespaceURI()) &&
98 DatatypeHelper.safeEquals(namespace.getNamespacePrefix(), newNamespace.getNamespacePrefix())){
99 if(newNamespace.alwaysDeclare()){
100 namespace.setAlwaysDeclare(true);
101 return;
102 }
103 }
104 }
105
106 namespaces.add(newNamespace);
107 }
108
109
110 public void detach(){
111 releaseParentDOM(true);
112 parent = null;
113 }
114
115
116 public Element getDOM() {
117 return dom;
118 }
119
120
121 public QName getElementQName() {
122 return new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart(), elementQname.getPrefix());
123 }
124
125
126 public IDIndex getIDIndex() {
127 return idIndex;
128 }
129
130
131 public Set<Namespace> getNamespaces() {
132 return Collections.unmodifiableSet(namespaces);
133 }
134
135
136 public String getNoNamespaceSchemaLocation() {
137 return noNamespaceSchemaLocation;
138 }
139
140
141
142
143
144
145 public XMLObject getParent() {
146 return parent;
147 }
148
149
150 public String getSchemaLocation() {
151 return schemaLocation;
152 }
153
154
155 public QName getSchemaType() {
156 return typeQname;
157 }
158
159
160 public boolean hasChildren() {
161 List<? extends XMLObject> children = getOrderedChildren();
162 return children != null && children.size() > 0;
163 }
164
165
166 public boolean hasParent() {
167 return getParent() != null;
168 }
169
170
171
172
173
174
175
176
177
178
179
180 protected QName prepareForAssignment(QName oldValue, QName newValue) {
181 if (oldValue == null) {
182 if (newValue != null) {
183 Namespace newNamespace = new Namespace(newValue.getNamespaceURI(), newValue.getPrefix());
184 addNamespace(newNamespace);
185 releaseThisandParentDOM();
186 return newValue;
187 } else {
188 return null;
189 }
190 }
191
192 if (!oldValue.equals(newValue)) {
193 if (newValue != null) {
194 Namespace newNamespace = new Namespace(newValue.getNamespaceURI(), newValue.getPrefix());
195 addNamespace(newNamespace);
196 }
197 releaseThisandParentDOM();
198 }
199
200 return newValue;
201 }
202
203
204
205
206
207
208
209
210
211
212
213 protected String prepareForAssignment(String oldValue, String newValue) {
214 String newString = DatatypeHelper.safeTrimOrNullString(newValue);
215
216 if (!DatatypeHelper.safeEquals(oldValue, newString)) {
217 releaseThisandParentDOM();
218 }
219
220 return newString;
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 protected <T extends Object> T prepareForAssignment(T oldValue, T newValue) {
238 if (oldValue == null) {
239 if (newValue != null) {
240 releaseThisandParentDOM();
241 return newValue;
242 } else {
243 return null;
244 }
245 }
246
247 if (!oldValue.equals(newValue)) {
248 releaseThisandParentDOM();
249 }
250
251 return newValue;
252 }
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 protected <T extends XMLObject> T prepareForAssignment(T oldValue, T newValue) {
270
271 if (newValue != null && newValue.hasParent()) {
272 throw new IllegalArgumentException(newValue.getClass().getName()
273 + " cannot be added - it is already the child of another SAML Object");
274 }
275
276 if (oldValue == null) {
277 if (newValue != null) {
278 releaseThisandParentDOM();
279 newValue.setParent(this);
280 idIndex.registerIDMappings(newValue.getIDIndex());
281 return newValue;
282
283 } else {
284 return null;
285 }
286 }
287
288 if (!oldValue.equals(newValue)) {
289 oldValue.setParent(null);
290 releaseThisandParentDOM();
291 idIndex.deregisterIDMappings(oldValue.getIDIndex());
292 if (newValue != null) {
293 newValue.setParent(this);
294 idIndex.registerIDMappings(newValue.getIDIndex());
295 }
296 }
297
298 return newValue;
299 }
300
301
302
303
304
305
306
307
308
309 protected void registerOwnID(String oldID, String newID) {
310 String newString = DatatypeHelper.safeTrimOrNullString(newID);
311
312 if (!DatatypeHelper.safeEquals(oldID, newString)) {
313 if (oldID != null) {
314 idIndex.deregisterIDMapping(oldID);
315 }
316
317 if (newString != null) {
318 idIndex.registerIDMapping(newString, this);
319 }
320 }
321 }
322
323
324 public void releaseChildrenDOM(boolean propagateRelease) {
325 log.trace("Releasing cached DOM reprsentation for children of {} with propagation set to {}",
326 getElementQName(), propagateRelease);
327 if (getOrderedChildren() != null) {
328 for (XMLObject child : getOrderedChildren()) {
329 if (child != null) {
330 child.releaseDOM();
331 if (propagateRelease) {
332 child.releaseChildrenDOM(propagateRelease);
333 }
334 }
335 }
336 }
337 }
338
339
340 public void releaseDOM() {
341 log.trace("Releasing cached DOM reprsentation for {}", getElementQName());
342 setDOM(null);
343 }
344
345
346 public void releaseParentDOM(boolean propagateRelease) {
347 log.trace("Releasing cached DOM reprsentation for parent of {} with propagation set to {}", getElementQName(),
348 propagateRelease);
349 XMLObject parentElement = getParent();
350 if (parentElement != null) {
351 parent.releaseDOM();
352 if (propagateRelease) {
353 parent.releaseParentDOM(propagateRelease);
354 }
355 }
356 }
357
358
359
360
361
362 public void releaseThisAndChildrenDOM() {
363 if (getDOM() != null) {
364 releaseDOM();
365 releaseChildrenDOM(true);
366 }
367 }
368
369
370
371
372
373 public void releaseThisandParentDOM() {
374 if (getDOM() != null) {
375 releaseDOM();
376 releaseParentDOM(true);
377 }
378 }
379
380
381 public void removeNamespace(Namespace namespace) {
382 namespaces.remove(namespace);
383 }
384
385
386 public XMLObject resolveID(String id) {
387 return idIndex.lookup(id);
388 }
389
390
391 public XMLObject resolveIDFromRoot(String id) {
392 XMLObject root = this;
393 while (root.hasParent()) {
394 root = root.getParent();
395 }
396 return root.resolveID(id);
397 }
398
399
400 public void setDOM(Element newDom) {
401 dom = newDom;
402 }
403
404
405
406
407
408
409 public void setElementNamespacePrefix(String prefix) {
410 if (prefix == null) {
411 elementQname = new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart());
412 } else {
413 elementQname = new QName(elementQname.getNamespaceURI(), elementQname.getLocalPart(), prefix);
414 }
415 }
416
417
418
419
420
421
422 protected void setElementQName(QName elementQName) {
423 this.elementQname = XMLHelper.constructQName(elementQName.getNamespaceURI(), elementQName.getLocalPart(),
424 elementQName.getPrefix());
425 addNamespace(new Namespace(elementQName.getNamespaceURI(), elementQName.getLocalPart()));
426 }
427
428
429 public void setNoNamespaceSchemaLocation(String location) {
430 noNamespaceSchemaLocation = DatatypeHelper.safeTrimOrNullString(location);
431 }
432
433
434 public void setParent(XMLObject newParent) {
435 parent = newParent;
436 }
437
438
439 public void setSchemaLocation(String location) {
440 schemaLocation = DatatypeHelper.safeTrimOrNullString(location);
441 }
442
443
444
445
446
447
448
449
450 protected void setSchemaType(QName type) {
451 if (type == null) {
452 typeQname = null;
453 } else {
454 typeQname = type;
455 addNamespace(new Namespace(type.getNamespaceURI(), type.getPrefix()));
456 }
457 }
458
459 }