001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.util; 017 018import java.io.Serializable; 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.Iterator; 023import java.util.List; 024import java.util.ListIterator; 025 026import org.kuali.rice.krad.datadictionary.Copyable; 027import org.kuali.rice.krad.uif.component.DelayedCopy; 028 029/** 030 * List implementation for internal use by a lifecycle element. 031 * 032 * <p>Mutability of the list will follow the semantics for the lifecycle element.</p> 033 * 034 * @author Kuali Rice Team (rice.collab@kuali.org) 035 * @param <T> list item type 036 */ 037public class LifecycleAwareList<T> implements List<T>, Copyable, Serializable { 038 039 private static final long serialVersionUID = -8971217230511446882L; 040 041 /** 042 * Delegating list iterator proxy. 043 * 044 * @author Kuali Rice Team (rice.collab@kuali.org) 045 */ 046 private class ListIter implements ListIterator<T> { 047 048 private final ListIterator<T> delegate; 049 050 /** 051 * @see LifecycleAwareList#listIterator() 052 */ 053 private ListIter() { 054 this.delegate = LifecycleAwareList.this.delegate.listIterator(); 055 } 056 057 /** 058 * @see LifecycleAwareList#listIterator(int) 059 */ 060 private ListIter(int index) { 061 this.delegate = LifecycleAwareList.this.delegate.listIterator(index); 062 } 063 064 @Override 065 public boolean hasNext() { 066 return this.delegate.hasNext(); 067 } 068 069 @Override 070 public T next() { 071 return this.delegate.next(); 072 } 073 074 @Override 075 public boolean hasPrevious() { 076 return this.delegate.hasPrevious(); 077 } 078 079 @Override 080 public T previous() { 081 return this.delegate.previous(); 082 } 083 084 @Override 085 public int nextIndex() { 086 return this.delegate.nextIndex(); 087 } 088 089 @Override 090 public int previousIndex() { 091 return this.delegate.previousIndex(); 092 } 093 094 @Override 095 public void remove() { 096 lifecycleElement.checkMutable(true); 097 this.delegate.remove(); 098 } 099 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}