View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package org.kuali.rice.krad.uif.util;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Iterator;
23  import java.util.List;
24  import java.util.ListIterator;
25  
26  import org.kuali.rice.krad.datadictionary.Copyable;
27  
28  /**
29   * List implementation for internal use by a lifecycle element.
30   *
31   * <p>Mutability of the list will follow the semantics for the lifecycle element.</p>
32   *
33   * @author Kuali Rice Team (rice.collab@kuali.org)
34   */
35  public class LifecycleAwareList<E> implements List<E>, Copyable, UifCloneable, Serializable {
36  
37      private static final long serialVersionUID = -8971217230511446882L;
38  
39      /**
40       * Delegating list iterator proxy.
41       *
42       * @author Kuali Rice Team (rice.collab@kuali.org)
43       */
44      private class ListIter implements ListIterator<E> {
45  
46          private final ListIterator<E> delegate;
47  
48          /**
49           * @see LifecycleAwareList#listIterator()
50           */
51          private ListIter() {
52              this.delegate = LifecycleAwareList.this.delegate.listIterator();
53          }
54  
55          /**
56           * @see LifecycleAwareList#listIterator(int)
57           */
58          private ListIter(int index) {
59              this.delegate = LifecycleAwareList.this.delegate.listIterator(index);
60          }
61  
62          @Override
63          public boolean hasNext() {
64              return this.delegate.hasNext();
65          }
66  
67          @Override
68          public E next() {
69              return this.delegate.next();
70          }
71  
72          @Override
73          public boolean hasPrevious() {
74              return this.delegate.hasPrevious();
75          }
76  
77          @Override
78          public E previous() {
79              return this.delegate.previous();
80          }
81  
82          @Override
83          public int nextIndex() {
84              return this.delegate.nextIndex();
85          }
86  
87          @Override
88          public int previousIndex() {
89              return this.delegate.previousIndex();
90          }
91  
92          @Override
93          public void remove() {
94              lifecycleElement.checkMutable(true);
95              this.delegate.remove();
96          }
97  
98          @Override
99          public void set(E e) {
100             lifecycleElement.checkMutable(true);
101             this.delegate.set(e);
102         }
103 
104         @Override
105         public void add(E e) {
106             lifecycleElement.checkMutable(true);
107             this.delegate.add(e);
108         }
109 
110     }
111 
112     /**
113      * Delegating iterator proxy.
114      *
115      * @author Kuali Rice Team (rice.collab@kuali.org)
116      */
117     private class Iter implements Iterator<E> {
118 
119         private final Iterator<E> delegate;
120 
121         /**
122          * @see LifecycleAwareList#iterator()
123          */
124         private Iter() {
125             this.delegate = LifecycleAwareList.this.delegate.iterator();
126         }
127 
128         @Override
129         public boolean hasNext() {
130             return this.delegate.hasNext();
131         }
132 
133         @Override
134         public E next() {
135             return this.delegate.next();
136         }
137 
138         @Override
139         public void remove() {
140             lifecycleElement.checkMutable(true);
141             this.delegate.remove();
142         }
143     }
144 
145     /**
146      * The component this list is related to.
147      */
148     private final LifecycleElement lifecycleElement;
149 
150     /**
151      * Delegating list implementation.
152      */
153     private List<E> delegate;
154 
155     /**
156      * Create a new list instance.
157      *
158      * @param lifecycleElement The lifecycle element to use for mutability checks.
159      */
160     public LifecycleAwareList(LifecycleElement lifecycleElement) {
161         this.lifecycleElement = lifecycleElement;
162         this.delegate = Collections.emptyList();
163     }
164 
165     /**
166      * Create a new list instance, based on another list.
167      *
168      * @param lifecycleElement The lifecycle element to use for mutability checks.
169      * @param delegate The list to wrap.
170      */
171     public LifecycleAwareList(LifecycleElement lifecycleElement, List<E> delegate) {
172         this.lifecycleElement = lifecycleElement;
173         
174         List<E> wrapped = delegate;
175         while (wrapped instanceof LifecycleAwareList) {
176             wrapped = ((LifecycleAwareList<E>) wrapped).delegate;
177         }
178         
179         this.delegate = delegate;
180     }
181 
182     /**
183      * Ensure that the delegate list can be modified.
184      */
185     private void ensureMutable() {
186         lifecycleElement.checkMutable(true);
187 
188         if (delegate == Collections.EMPTY_LIST) {
189             delegate = new ArrayList<E>();
190         }
191     }
192 
193     @Override
194     public int size() {
195         return this.delegate.size();
196     }
197 
198     @Override
199     public boolean isEmpty() {
200         return this.delegate.isEmpty();
201     }
202 
203     @Override
204     public boolean contains(Object o) {
205         return this.delegate.contains(o);
206     }
207 
208     @Override
209     public Iterator<E> iterator() {
210         return new Iter();
211     }
212 
213     @Override
214     public Object[] toArray() {
215         return this.delegate.toArray();
216     }
217 
218     @Override
219     public <T> T[] toArray(T[] a) {
220         return this.delegate.toArray(a);
221     }
222 
223     @Override
224     public boolean add(E e) {
225         ensureMutable();
226         return this.delegate.add(e);
227     }
228 
229     @Override
230     public boolean remove(Object o) {
231         lifecycleElement.checkMutable(true);
232         return delegate != Collections.EMPTY_LIST && delegate.remove(o);
233     }
234 
235     @Override
236     public boolean containsAll(Collection<?> c) {
237         return this.delegate.containsAll(c);
238     }
239 
240     @Override
241     public boolean addAll(Collection<? extends E> c) {
242         ensureMutable();
243         return this.delegate.addAll(c);
244     }
245 
246     @Override
247     public boolean addAll(int index, Collection<? extends E> c) {
248         ensureMutable();
249         return this.delegate.addAll(index, c);
250     }
251 
252     @Override
253     public boolean removeAll(Collection<?> c) {
254         lifecycleElement.checkMutable(true);
255         return delegate != Collections.EMPTY_LIST && this.delegate.removeAll(c);
256     }
257 
258     @Override
259     public boolean retainAll(Collection<?> c) {
260         lifecycleElement.checkMutable(true);
261         return delegate != Collections.EMPTY_LIST && this.delegate.retainAll(c);
262     }
263 
264     @Override
265     public void clear() {
266         if (this.delegate != Collections.EMPTY_LIST) {
267             this.delegate.clear();
268         }
269     }
270 
271     @Override
272     public boolean equals(Object o) {
273         return this.delegate.equals(o);
274     }
275 
276     @Override
277     public int hashCode() {
278         return this.delegate.hashCode();
279     }
280 
281     @Override
282     public E get(int index) {
283         return this.delegate.get(index);
284     }
285 
286     @Override
287     public E set(int index, E element) {
288         lifecycleElement.checkMutable(true);
289         return this.delegate.set(index, element);
290     }
291 
292     @Override
293     public void add(int index, E element) {
294         ensureMutable();
295         this.delegate.add(index, element);
296     }
297 
298     @Override
299     public E remove(int index) {
300         lifecycleElement.checkMutable(true);
301         return this.delegate.remove(index);
302     }
303 
304     @Override
305     public int indexOf(Object o) {
306         return this.delegate.indexOf(o);
307     }
308 
309     @Override
310     public int lastIndexOf(Object o) {
311         return this.delegate.lastIndexOf(o);
312     }
313 
314     @Override
315     public ListIterator<E> listIterator() {
316         ensureMutable();
317         return new ListIter();
318     }
319 
320     @Override
321     public ListIterator<E> listIterator(int index) {
322         ensureMutable();
323         return new ListIter(index);
324     }
325 
326     @Override
327     public List<E> subList(int fromIndex, int toIndex) {
328         return new LifecycleAwareList<E>(lifecycleElement, this.delegate.subList(fromIndex, toIndex));
329     }
330 
331     /**
332      * @see org.kuali.rice.krad.datadictionary.Copyable#copy()
333      */
334     @SuppressWarnings("unchecked")
335     @Override
336     public <T> T copy() {
337         try {
338             return (T) clone();
339         } catch (CloneNotSupportedException e) {
340             throw new IllegalStateException("Unexpected error in clone()", e);
341         }
342     }
343 
344     /**
345      * Modification is not controlled at this level.
346      * 
347      * @see Copyable#preventModification()
348      */
349     @Override
350     public void preventModification() {}
351 
352     /**
353      * @see java.lang.Object#clone()
354      */
355     @Override
356     public Object clone() throws CloneNotSupportedException {
357         return super.clone();
358     }
359 
360 }