View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.launcher.util;
8   
9   import java.beans.PropertyChangeListener;
10  import java.beans.PropertyChangeSupport;
11  import java.util.ArrayList;
12  import java.util.Collection;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.ListIterator;
16  
17  /**
18   * Adapted version of a groovy.util.ObservableList.
19   * List decorator that will trigger PropertyChangeEvents when a value changes.<br>
20   * <p/>
21   * The current implementation will trigger specialized events in the following scenarios, you need
22   * not register a different listener as those events extend from PropertyChangeEvent
23   * <ul>
24   * <li>ObservableList.ElementAddedEvent - a new element is added to the list</li>
25   * <li>ObservableList.ElementRemovedEvent - a element is removed from the list</li>
26   * <li>ObservableList.ElementUpdatedEvent - a element changes value (same as regular
27   * PropertyChangeEvent)</li>
28   * <li>ObservableList.ElementClearedEvent - all elements have been removed from the list</li>
29   * <li>ObservableList.MultiElementAddedEvent - triggered by calling list.addAll()</li>
30   * <li>ObservableList.MultiElementRemovedEvent - triggered by calling
31   * list.removeAll()/list.retainAll()</li>
32   * </ul>
33   * </p>
34   */
35  public class ObservableList<E> implements List<E> {
36  
37      private List<E> delegate;
38      private PropertyChangeSupport pcs;
39  
40      public ObservableList() {
41          this(new ArrayList<E>());
42      }
43  
44      public ObservableList(List<E> delegate) {
45          this.delegate = delegate;
46          pcs = new PropertyChangeSupport(this);
47      }
48  
49      public void add(int index, E element) {
50          delegate.add(index, element);
51          pcs.firePropertyChange(new ElementAddedEvent(this, element, index));
52      }
53  
54  
55      public boolean addAll(Collection<? extends E> c) {
56          int index = size() - 1;
57          index = index < 0 ? 0 : index;
58  
59          boolean success = delegate.addAll(c);
60          if (success && c != null) {
61              List<E> values = new ArrayList<E>();
62              for (E element : values) {
63                  values.add(element);
64              }
65  
66              if (values.size() > 0) {
67                  pcs.firePropertyChange(new MultiElementAddedEvent(this, index, values));
68              }
69          }
70  
71          return success;
72      }
73  
74      public boolean addAll(int index, Collection<? extends E> c) {
75          boolean success = delegate.addAll(index, c);
76  
77          if (success && c != null) {
78              List<E> values = new ArrayList<E>();
79              for (E element : c) {
80                  values.add(element);
81              }
82              if (values.size() > 0) {
83                  pcs.firePropertyChange(new MultiElementAddedEvent(this, index, values));
84              }
85          }
86  
87          return success;
88      }
89  
90      public void clear() {
91          List values = new ArrayList();
92          values.addAll(delegate);
93          delegate.clear();
94          if (!values.isEmpty()) {
95              pcs.firePropertyChange(new ElementsClearedEvent(this, values));
96          }
97      }
98  
99      public boolean contains(Object o) {
100         return delegate.contains(o);
101     }
102 
103     public boolean containsAll(Collection<?> c) {
104         return delegate.containsAll(c);
105     }
106 
107     public boolean equals(Object o) {
108         return delegate.equals(o);
109     }
110 
111     public E get(int index) {
112         return delegate.get(index);
113     }
114 
115     public int hashCode() {
116         return delegate.hashCode();
117     }
118 
119     public int indexOf(Object o) {
120         return delegate.indexOf(o);
121     }
122 
123     public boolean isEmpty() {
124         return delegate.isEmpty();
125     }
126 
127     public Iterator<E> iterator() {
128         return new ObservableIterator(delegate.iterator());
129     }
130 
131     public int lastIndexOf(Object o) {
132         return delegate.lastIndexOf(o);
133     }
134 
135     public ListIterator<E> listIterator() {
136         return new ObservableListIterator(delegate.listIterator(), 0);
137     }
138 
139     public ListIterator<E> listIterator(int index) {
140         return new ObservableListIterator(delegate.listIterator(index), index);
141     }
142 
143     public E remove(int index) {
144         E element = delegate.remove(index);
145         pcs.firePropertyChange(new ElementRemovedEvent(this, element, index));
146         return element;
147     }
148 
149     public boolean remove(Object o) {
150         int index = delegate.indexOf(o);
151         boolean success = delegate.remove(o);
152         if (success) {
153             pcs.firePropertyChange(new ElementRemovedEvent(this, o, index));
154         }
155         return success;
156     }
157 
158     public boolean removeAll(Collection<?> c) {
159         if (c == null) {
160             return false;
161         }
162 
163         List<Object> values = new ArrayList();
164         for (Object element : c) {
165             if (delegate.contains(element)) {
166                 values.add(element);
167             }
168         }
169 
170         boolean success = delegate.removeAll(c);
171         if (success && !values.isEmpty()) {
172             pcs.firePropertyChange(new MultiElementRemovedEvent(this, values));
173         }
174 
175         return success;
176     }
177 
178     public boolean retainAll(Collection<?> c) {
179         if (c == null) {
180             return false;
181         }
182 
183         List<E> values = new ArrayList<E>();
184         if (c != null) {
185             for (E element : delegate) {
186                 if (!c.contains(element)) {
187                     values.add(element);
188                 }
189             }
190         }
191 
192         boolean success = delegate.retainAll(c);
193         if (success && !values.isEmpty()) {
194             pcs.firePropertyChange(new MultiElementRemovedEvent(this, values));
195         }
196 
197         return success;
198     }
199 
200     public E set(int index, E element) {
201         E oldValue = delegate.set(index, element);
202         pcs.firePropertyChange(new ElementUpdatedEvent(this, oldValue, element, index));
203         return oldValue;
204     }
205 
206     public int size() {
207         return delegate.size();
208     }
209 
210     public List subList(int fromIndex, int toIndex) {
211         return delegate.subList(fromIndex, toIndex);
212     }
213 
214     public Object[] toArray() {
215         return delegate.toArray();
216     }
217 
218     public boolean add(E o) {
219         boolean success = delegate.add(o);
220         if (success) {
221             pcs.firePropertyChange(new ElementAddedEvent(this, o, size() - 1));
222         }
223         return success;
224     }
225 
226 
227     public Object[] toArray(Object[] a) {
228         return delegate.toArray(a);
229     }
230 
231     private class ObservableIterator implements Iterator<E> {
232 
233         private Iterator<E> iterDelegate;
234         protected int cursor = 0;
235 
236         public ObservableIterator(Iterator<E> iterDelegate) {
237             this.iterDelegate = iterDelegate;
238         }
239 
240         public Iterator<E> getDelegate() {
241             return iterDelegate;
242         }
243 
244         public boolean hasNext() {
245             return iterDelegate.hasNext();
246         }
247 
248         public E next() {
249             cursor++;
250             return iterDelegate.next();
251         }
252 
253         public void remove() {
254             ObservableList.this.remove(cursor--);
255         }
256     }
257 
258     protected class ObservableListIterator extends ObservableIterator implements ListIterator<E> {
259 
260         public ObservableListIterator(ListIterator<E> iterDelegate, int index) {
261             super(iterDelegate);
262             cursor = index;
263         }
264 
265         public ListIterator<E> getListIterator() {
266             return (ListIterator<E>) getDelegate();
267         }
268 
269         public void add(E o) {
270             ObservableList.this.add(o);
271             cursor++;
272         }
273 
274         public boolean hasPrevious() {
275             return getListIterator().hasPrevious();
276         }
277 
278         public int nextIndex() {
279             return getListIterator().nextIndex();
280         }
281 
282         public E previous() {
283             return getListIterator().previous();
284         }
285 
286         public int previousIndex() {
287             return getListIterator().previousIndex();
288         }
289 
290         public void set(E e) {
291             ObservableList.this.set(cursor, e);
292         }
293 
294     }
295 
296     // observable interface
297 
298     public void addPropertyChangeListener(PropertyChangeListener listener) {
299         pcs.addPropertyChangeListener(listener);
300     }
301 
302     public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
303         pcs.addPropertyChangeListener(propertyName, listener);
304     }
305 
306     public PropertyChangeListener[] getPropertyChangeListeners() {
307         return pcs.getPropertyChangeListeners();
308     }
309 
310     public PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
311         return pcs.getPropertyChangeListeners(propertyName);
312     }
313 
314     public void removePropertyChangeListener(PropertyChangeListener listener) {
315         pcs.removePropertyChangeListener(listener);
316     }
317 
318     public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
319         pcs.removePropertyChangeListener(propertyName, listener);
320     }
321 
322     public boolean hasListeners(String propertyName) {
323         return pcs.hasListeners(propertyName);
324     }
325 
326 }