1 /*
2 * Copyright [2005] [University Corporation for Advanced Internet Development, Inc.]
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 package org.opensaml.xml.util;
18
19 import java.util.AbstractList;
20 import java.util.Collection;
21 import java.util.List;
22
23 import org.opensaml.xml.XMLObject;
24
25 /**
26 * Resizable list for the children of XMLObjects. This list implements all optional List operations and does not all for
27 * null elements. XMLObjects added to, or removed from, this list will have their parent object appropriately set and,
28 * the underlying DOM will be released during mutation opertions.
29 *
30 * @param <ElementType> type of elements added to the list
31 */
32 public class XMLObjectChildrenList<ElementType extends XMLObject> extends AbstractList<ElementType> {
33
34 /** Parent to the elements in this list. */
35 private XMLObject parent;
36
37 /** List of elements. */
38 private List<ElementType> elements;
39
40 /**
41 * Constructs an empty list with all added XMLObjects being assigned the given parent XMLObject.
42 *
43 * @param newParent the parent for all the added XMLObjects
44 *
45 * @throws NullPointerException thrown if the parent is null
46 */
47 public XMLObjectChildrenList(XMLObject newParent) throws NullPointerException {
48 if (newParent == null) {
49 throw new NullPointerException("Parent may not be null");
50 }
51
52 parent = newParent;
53 elements = new LazyList<ElementType>();
54 }
55
56 /**
57 * Constructs a list containing the elements in the specified collection, in the order they are returned by the
58 * collection's iterator, with each added XMLObject assigned the given parent XMLObject.
59 *
60 * @param newParent the parent for all the added XMLObjects
61 * @param newElements the elements to be added
62 *
63 * @throws NullPointerException thrown if the parent is null
64 * @throws IllegalArgumentException thrown if any of the XMLObjects in the given collection already have a parent
65 * that is different from the given parent
66 */
67 public XMLObjectChildrenList(XMLObject newParent, Collection<ElementType> newElements) throws NullPointerException {
68 if (newParent == null) {
69 throw new NullPointerException("Parent may not be null");
70 }
71
72 parent = newParent;
73 elements = new LazyList<ElementType>();
74
75 addAll(newElements);
76 }
77
78 /** {@inheritDoc} */
79 public int size() {
80 return elements.size();
81 }
82
83 /**
84 * Checks to see if the given element is contained in this list.
85 *
86 * @param element the element to check for
87 *
88 * @return true if the element is in this list, false if not
89 */
90 public boolean contains(ElementType element) {
91 return elements.contains(element);
92 }
93
94 /** {@inheritDoc} */
95 public ElementType get(int index) {
96 return elements.get(index);
97 }
98
99 /**
100 * Replaces the XMLObject at the specified index with the given element.
101 *
102 * @param index index of the XMLObject to be replaced
103 * @param element element to be stored at the given index
104 *
105 * @return the replaced XMLObject
106 *
107 * @throws IllegalArgumentException thrown if the given XMLObject already has a parent that is different from the
108 * XMLObject given at list construction time
109 */
110 public ElementType set(int index, ElementType element) throws IllegalArgumentException {
111 if (element == null) {
112 return null;
113 }
114
115 setParent(element);
116
117 ElementType removedElement = elements.set(index, element);
118 if (removedElement != null) {
119 removedElement.setParent(null);
120 parent.getIDIndex().deregisterIDMappings(removedElement.getIDIndex());
121 }
122
123 // Note: to avoid ordering problems, this needs to be called after
124 // the deregistration, in case the added element has a same ID string
125 // value as the removed one, else you will lose it.
126 parent.getIDIndex().registerIDMappings(element.getIDIndex());
127
128 modCount++;
129 return removedElement;
130 }
131
132 /**
133 * Adds the given XMLObject to this list.
134 *
135 * @param index index at which to add the given XMLObject
136 * @param element element to be stored at the given index
137 *
138 * @throws IllegalArgumentException thrown if the given XMLObject already has a parent that is different from the
139 * XMLObject given at list construction time
140 */
141 public void add(int index, ElementType element) throws IllegalArgumentException {
142 if (element == null || elements.contains(element)) {
143 return;
144 }
145
146 setParent(element);
147 parent.getIDIndex().registerIDMappings(element.getIDIndex());
148
149 modCount++;
150 elements.add(index, element);
151 }
152
153 /** {@inheritDoc} */
154 public ElementType remove(int index) {
155 ElementType element = elements.remove(index);
156
157 if (element != null) {
158 element.releaseParentDOM(true);
159 element.setParent(null);
160 parent.getIDIndex().deregisterIDMappings(element.getIDIndex());
161 }
162
163 modCount++;
164 return element;
165 }
166
167 /**
168 * Removes the element from the list.
169 *
170 * @param element the element to be removed
171 *
172 * @return true if the element was in the list and removed, false if not
173 */
174 public boolean remove(ElementType element) {
175 boolean elementRemoved = false;
176
177 elementRemoved = elements.remove(element);
178 if (elementRemoved) {
179 if (element != null) {
180 element.releaseParentDOM(true);
181 element.setParent(null);
182 parent.getIDIndex().deregisterIDMappings(element.getIDIndex());
183 }
184 }
185
186 return elementRemoved;
187 }
188
189 /**
190 * Assigned the parent, given at list construction, to the given element if the element does not have a parent or
191 * its parent matches the one given at list construction time.
192 *
193 * @param element the element to set the parent on
194 *
195 * @throws IllegalArgumentException thrown if the given element already has a parent and it is different than the
196 * parent given at list construction time
197 */
198 protected void setParent(ElementType element) throws IllegalArgumentException {
199 XMLObject elemParent = element.getParent();
200 if (elemParent != null && elemParent != parent) {
201 throw new IllegalArgumentException(element.getElementQName()
202 + " is already the child of another XMLObject and may not be inserted in to this list");
203 }
204
205 element.setParent(parent);
206 element.releaseParentDOM(true);
207 }
208 }