View Javadoc

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