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