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.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 }