Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.collections;
027
028import com.sun.javafx.collections.ListListenerHelper;
029import com.sun.javafx.collections.MapListenerHelper;
030import com.sun.javafx.collections.SetListenerHelper;
031import java.lang.reflect.Array;
032import java.util.AbstractList;
033import java.util.AbstractMap;
034import java.util.AbstractSet;
035import java.util.ArrayList;
036import java.util.Arrays;
037import java.util.Collection;
038import java.util.Collections;
039import java.util.Comparator;
040import java.util.HashMap;
041import java.util.HashSet;
042import java.util.Iterator;
043import java.util.List;
044import java.util.ListIterator;
045import java.util.Map;
046import java.util.NoSuchElementException;
047import java.util.Random;
048import java.util.Set;
049
050import javafx.beans.InvalidationListener;
051
052import com.sun.javafx.collections.ObservableListWrapper;
053import com.sun.javafx.collections.ObservableMapWrapper;
054import com.sun.javafx.collections.ObservableSetWrapper;
055import com.sun.javafx.collections.MapAdapterChange;
056import com.sun.javafx.collections.ObservableFloatArrayImpl;
057import com.sun.javafx.collections.ObservableIntegerArrayImpl;
058import com.sun.javafx.collections.ObservableSequentialListWrapper;
059import com.sun.javafx.collections.SetAdapterChange;
060import com.sun.javafx.collections.SortableList;
061import com.sun.javafx.collections.SourceAdapterChange;
062import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection;
063import java.util.RandomAccess;
064import javafx.beans.Observable;
065import javafx.collections.ListChangeListener.Change;
066import javafx.util.Callback;
067
068/**
069 * Utility class that consists of static methods that are 1:1 copies of java.util.Collections methods.
070 * <br><br>
071 * The wrapper methods (like synchronizedObservableList or emptyObservableList) has exactly the same
072 * functionality as the methods in Collections, with exception that they return ObservableList and are
073 * therefore suitable for methods that require ObservableList on input.
074 * <br><br>
075 * The utility methods are here mainly for performance reasons. All methods are optimized in a way that
076 * they yield only limited number of notifications. On the other hand, java.util.Collections methods
077 * might call "modification methods" on an ObservableList multiple times, resulting in a number of notifications.
078 *
079 */
080public class FXCollections {
081    /** Not to be instantiated. */
082    private FXCollections() { }
083
084    /**
085     * Constructs an ObservableList that is backed by the specified list.
086     * Mutation operations on the ObservableList instance will be reported
087     * to observers that have registered on that instance.<br>
088     * Note that mutation operations made directly to the underlying list are
089     * <em>not</em> reported to observers of any ObservableList that
090     * wraps it.
091     *
092     * @param list a concrete List that backs this ObservableList
093     * @return a newly created ObservableList
094     */
095    public static <E> ObservableList<E> observableList(List<E> list) {
096        if (list == null) {
097            throw new NullPointerException();
098        }
099        return list instanceof RandomAccess ? new ObservableListWrapper<E>(list) :
100                new ObservableSequentialListWrapper<E>(list);
101    }
102    
103    /**
104     * Constructs an ObservableList that is backed by the specified list.
105     * Mutation operations on the ObservableList instance will be reported
106     * to observers that have registered on that instance.<br>
107     * Note that mutation operations made directly to the underlying list are
108     * <em>not</em> reported to observers of any ObservableList that
109     * wraps it.
110     * <br>
111     * This list also reports mutations of the elements in it by using <code>extractor</code>.
112     * Observable objects returned by extractor (applied to each list element) are listened for changes
113     * and transformed into "update" change of ListChangeListener.
114     *
115     * @param list a concrete List that backs this ObservableList
116     * @param extractor element to Observable[] convertor
117     * @since 2.1
118     * @return a newly created ObservableList
119     */
120    public static <E> ObservableList<E> observableList(List<E> list, Callback<E, Observable[]> extractor) {
121        if (list == null || extractor == null) {
122            throw new NullPointerException();
123        }
124        return list instanceof RandomAccess ? new ObservableListWrapper<E>(list, extractor) : 
125            new ObservableSequentialListWrapper<E>(list, extractor);
126    }
127    
128    /**
129     * Constructs an ObservableMap that is backed by the specified map.
130     * Mutation operations on the ObservableMap instance will be reported
131     * to observers that have registered on that instance.<br>
132     * Note that mutation operations made directly to the underlying map are <em>not</em>
133     * reported to observers of any ObservableMap that wraps it.
134     * @param map a Map that backs this ObservableMap
135     * @return a newly created ObservableMap
136     */
137    public static <K, V> ObservableMap<K, V> observableMap(Map<K, V> map) {
138        if (map == null) {
139            throw new NullPointerException();
140        }
141        return new ObservableMapWrapper<K, V>(map);
142    }
143
144    /**
145     * Constructs an ObservableSet that is backed by the specified set.
146     * Mutation operations on the ObservableSet instance will be reported
147     * to observers that have registered on that instance.<br>
148     * Note that mutation operations made directly to the underlying set are <em>not</em>
149     * reported to observers of any ObservableSet that wraps it.
150     * @param set a Set that backs this ObservableSet
151     * @return a newly created ObservableSet
152     */
153    public static <E> ObservableSet<E> observableSet(Set<E> set) {
154        if (set == null) {
155            throw new NullPointerException();
156        }
157        return new ObservableSetWrapper<E>(set);
158    }
159
160    /**
161     * Constructs an ObservableSet that contains all the specified elements.
162     * @param elements elements that will be added into returned ObservableSet
163     * @return a newly created ObservableSet
164     */
165    public static <E> ObservableSet<E> observableSet(E... elements) {
166        if (elements == null) {
167            throw new NullPointerException();
168        }
169        Set<E> set = new HashSet<E>(elements.length);
170        Collections.addAll(set, elements);
171        return new ObservableSetWrapper<E>(set);
172    }
173
174    /**
175     * Constructs a read-only interface to the specified ObservableMap. Only
176     * mutation operations made to the underlying ObservableMap will be reported
177     * to observers that have registered on the unmodifiable instance. This allows
178     * clients to track changes in a Map but disallows the ability to modify it.
179     * @param map an ObservableMap that is to be monitored by this interface
180     * @return a newly created UnmodifiableObservableMap
181     */
182    @ReturnsUnmodifiableCollection
183    public static <K, V> ObservableMap<K, V> unmodifiableObservableMap(ObservableMap<K, V> map) {
184        if (map == null) {
185            throw new NullPointerException();
186        }
187        return new com.sun.javafx.collections.UnmodifiableObservableMap<K, V>(map);
188    }
189
190    /**
191     * Creates and returns a typesafe wrapper on top of provided observable map.
192     * @param map an Observable map to be wrapped
193     * @param keyType the type of key that {@code map} is permitted to hold
194     * @param valueType the type of value that {@code map} is permitted to hold
195     * @return a dynamically typesafe view of the specified map
196     * @see Collections#checkedMap(java.util.Map, java.lang.Class)
197     */
198    public static <K, V> ObservableMap<K, V> checkedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) {
199        if (map == null || keyType == null || valueType == null) {
200            throw new NullPointerException();
201        }
202        return new CheckedObservableMap<K, V>(map, keyType, valueType);
203    }
204
205    /**
206     * Creates and returns a synchronized wrapper on top of provided observable map.
207     * @param  map the map to be "wrapped" in a synchronized map.
208     * @return A synchronized version of the observable map
209     * @see Collections#synchronizedMap(java.util.Map)
210     */
211    public static <K, V> ObservableMap<K, V> synchronizedObservableMap(ObservableMap<K, V> map) {
212        if (map == null) {
213            throw new NullPointerException();
214        }
215        return new SynchronizedObservableMap<K, V>(map);
216    }
217
218    private static ObservableMap EMPTY_OBSERVABLE_MAP = new EmptyObservableMap();
219
220    /**
221     * Creates and empty unmodifiable observable map.
222     * @return An empty unmodifiable observable map
223     * @see Collections#emptyMap()
224     */
225    @SuppressWarnings("unchecked")
226    @ReturnsUnmodifiableCollection
227    public static <K, V> ObservableMap<K, V> emptyObservableMap() {
228        return EMPTY_OBSERVABLE_MAP;
229    }
230
231    /**
232     * Creates a new empty observable integer array.
233     * @return a newly created ObservableIntegerArray
234     */
235    public static ObservableIntegerArray observableIntegerArray() {
236        return new ObservableIntegerArrayImpl();
237    }
238
239    /**
240     * Creates a new observable integer array with {@code values} set to it.
241     * @param values the values that will be in the new observable integer array
242     * @return a newly created ObservableIntegerArray
243     */
244    public static ObservableIntegerArray observableIntegerArray(int... values) {
245        return new ObservableIntegerArrayImpl(values);
246    }
247
248    /**
249     * Creates a new observable integer array with copy of elements in given
250     * {@code array}.
251     * @param array observable integer array to copy
252     * @return a newly created ObservableIntegerArray
253     */
254    public static ObservableIntegerArray observableIntegerArray(ObservableIntegerArray array) {
255        return new ObservableIntegerArrayImpl(array);
256    }
257
258    /**
259     * Creates a new empty observable float array.
260     * @return a newly created ObservableFloatArray
261     */
262    public static ObservableFloatArray observableFloatArray() {
263        return new ObservableFloatArrayImpl();
264    }
265
266    /**
267     * Creates a new observable float array with {@code values} set to it.
268     * @param values the values that will be in the new observable float array
269     * @return a newly created ObservableFloatArray
270     */
271    public static ObservableFloatArray observableFloatArray(float... values) {
272        return new ObservableFloatArrayImpl(values);
273    }
274
275    /**
276     * Creates a new observable float array with copy of elements in given
277     * {@code array}.
278     * @param array observable float array to copy
279     * @return a newly created ObservableFloatArray
280     */
281    public static ObservableFloatArray observableFloatArray(ObservableFloatArray array) {
282        return new ObservableFloatArrayImpl(array);
283    }
284
285    /**
286     * Creates a new empty observable list that is backed by an arraylist.
287     * @see #observableList(java.util.List) 
288     * @return a newly created ObservableList
289     */
290    @SuppressWarnings("unchecked")
291    public static <E> ObservableList<E> observableArrayList() {
292        return observableList(new ArrayList());
293    }
294    
295    /**
296     * Creates a new empty observable list backed by an arraylist.
297     * 
298     * This list reports element updates.
299     * @param extractor element to Observable[] convertor. Observable objects are listened for changes on the element.
300     * @see #observableList(java.util.List, javafx.util.Callback) 
301     * @since 2.1
302     * @return a newly created ObservableList
303     */
304    public static <E> ObservableList<E> observableArrayList(Callback<E, Observable[]> extractor) {
305        return observableList(new ArrayList(), extractor);
306    }
307
308    /**
309     * Creates a new observable array list with {@code items} added to it.
310     * @return a newly created observableArrayList
311     * @param items the items that will be in the new observable ArrayList
312     * @see #observableArrayList()
313     */
314    public static <E> ObservableList<E> observableArrayList(E... items) {
315        ObservableList<E> list = observableArrayList();
316        list.addAll(items);
317        return list;
318    }
319
320    /**
321     * Creates a new observable array list and adds a content of collection {@code col}
322     * to it.
323     * @param col a collection which content should be added to the observableArrayList
324     * @return a newly created observableArrayList
325     */
326    public static <E> ObservableList<E> observableArrayList(Collection<? extends E> col) {
327        ObservableList<E> list = observableArrayList();
328        list.addAll(col);
329        return list;
330    }
331    
332    /**
333     * Creates a new empty observable map that is backed by a HashMap.
334     * @param <K> the type of keys
335     * @param <V> the type of values
336     * @return a newly created observable HashMap
337     */
338    public static <K,V> ObservableMap<K,V> observableHashMap() {
339        return observableMap(new HashMap<K, V>());
340    }
341    
342    /**
343     * Concatenates more observable lists into one. The resulting list
344     * would be backed by an arraylist.
345     * @param lists lists to concatenate
346     * @return new observable array list concatenated from the arguments
347     */
348    public static <E> ObservableList<E> concat(ObservableList<E>... lists) {
349        if (lists.length == 0 ) {
350            return observableArrayList();
351        }
352        if (lists.length == 1) {
353            return observableArrayList(lists[0]);
354        }
355        ArrayList<E> backingList = new ArrayList<E>();
356        for (ObservableList<E> s : lists) {
357            backingList.addAll(s);
358        }
359
360        return observableList(backingList);
361    }
362
363    /**
364     * Creates and returns unmodifiable wrapper list on top of provided observable list.
365     * @param list  an ObservableList that is to be wrapped
366     * @return an ObserableList wrapper that is unmodifiable
367     * @see Collections#unmodifiableList(java.util.List) 
368     */
369    @ReturnsUnmodifiableCollection
370    public static<E> ObservableList<E> unmodifiableObservableList(ObservableList<E> list) {
371        if (list == null) {
372            throw new NullPointerException();
373        }
374        return new UnmodifiableObservableListImpl<E>(list);
375    }
376
377    /**
378     * Creates and returns a typesafe wrapper on top of provided observable list.
379     * @param list  an Observable list to be wrapped
380     * @param type   the type of element that <tt>list</tt> is permitted to hold
381     * @return a dynamically typesafe view of the specified list
382     * @see Collections#checkedList(java.util.List, java.lang.Class) 
383     */
384    public static<E> ObservableList<E> checkedObservableList(ObservableList<E> list, Class<E> type) {
385        if (list == null) {
386            throw new NullPointerException();
387        }
388        return new CheckedObservableList<E>(list, type);
389    }
390
391    /**
392     * Creates and returns a synchronized wrapper on top of provided observable list.
393     * @param  list the list to be "wrapped" in a synchronized list.
394     * @return A synchronized version of the observable list
395     * @see Collections#synchronizedList(java.util.List) 
396     */
397    public static<E> ObservableList<E> synchronizedObservableList(ObservableList<E> list) {
398        if (list == null) {
399            throw new NullPointerException();
400        }
401        return new SynchronizedObservableList<E>(list);
402    }
403
404    private static ObservableList EMPTY_OBSERVABLE_LIST = new EmptyObservableList();
405
406
407    /**
408     * Creates and empty unmodifiable observable list.
409     * @return An empty unmodifiable observable list
410     * @see Collections#emptyList() 
411     */
412    @SuppressWarnings("unchecked")
413    @ReturnsUnmodifiableCollection
414    public static<E> ObservableList<E> emptyObservableList() {
415        return EMPTY_OBSERVABLE_LIST;
416    }
417
418    /**
419     * Creates an unmodifiable observable list with single element.
420     * @param e the only elements that will be contained in this singleton observable list
421     * @return a singleton observable list
422     * @see Collections#singletonList(java.lang.Object) 
423     */
424    @ReturnsUnmodifiableCollection
425    public static<E> ObservableList<E> singletonObservableList(E e) {
426        return new SingletonObservableList<E>(e);
427    }
428
429    /**
430     * Creates and returns unmodifiable wrapper on top of provided observable set.
431     * @param set an ObservableSet that is to be wrapped
432     * @return an ObserableSet wrapper that is unmodifiable
433     * @see Collections#unmodifiableSet(java.util.Set)
434     */
435    @ReturnsUnmodifiableCollection
436    public static<E> ObservableSet<E> unmodifiableObservableSet(ObservableSet<E> set) {
437        if (set == null) {
438            throw new NullPointerException();
439        }
440        return new UnmodifiableObservableSet<E>(set);
441    }
442
443    /**
444     * Creates and returns a typesafe wrapper on top of provided observable set.
445     * @param set an Observable set to be wrapped
446     * @param type  the type of element that <tt>set</tt> is permitted to hold
447     * @return a dynamically typesafe view of the specified set
448     * @see Collections#checkedSet(java.util.Set, java.lang.Class)
449     */
450    public static<E> ObservableSet<E> checkedObservableSet(ObservableSet<E> set, Class<E> type) {
451        if (set == null) {
452            throw new NullPointerException();
453        }
454        return new CheckedObservableSet<E>(set, type);
455    }
456
457    /**
458     * Creates and returns a synchronized wrapper on top of provided observable set.
459     * @param  set the set to be "wrapped" in a synchronized set.
460     * @return A synchronized version of the observable set
461     * @see Collections#synchronizedSet(java.util.Set)
462     */
463    public static<E> ObservableSet<E> synchronizedObservableSet(ObservableSet<E> set) {
464        if (set == null) {
465            throw new NullPointerException();
466        }
467        return new SynchronizedObservableSet<E>(set);
468    }
469
470    private static ObservableSet EMPTY_OBSERVABLE_SET = new EmptyObservableSet();
471
472    /**
473     * Creates and empty unmodifiable observable set.
474     * @return An empty unmodifiable observable set
475     * @see Collections#emptySet()
476     */
477    @SuppressWarnings("unchecked")
478    @ReturnsUnmodifiableCollection
479    public static<E> ObservableSet<E> emptyObservableSet() {
480        return EMPTY_OBSERVABLE_SET;
481    }
482
483    /**
484     * Copies elements from src to dest. Fires only <b>one</b> change notification on dest.
485     * @param dest the destination observable list
486     * @param src the source list
487     * @see Collections#copy(java.util.List, java.util.List) 
488     */
489    @SuppressWarnings("unchecked")
490    public static <T> void copy(ObservableList<? super T> dest, List<? extends T> src) {
491        final int srcSize = src.size();
492        if (srcSize > dest.size()) {
493            throw new IndexOutOfBoundsException("Source does not fit in dest");
494        }
495        T[] destArray = (T[]) dest.toArray();
496        System.arraycopy(src.toArray(), 0, destArray, 0, srcSize);
497        dest.setAll(destArray);
498    }
499
500    /**
501     * Fills the provided list with obj. Fires only <b>one</b> change notification on the list.
502     * @param list the list to fill
503     * @param obj the object to fill the list with
504     * @see Collections#fill(java.util.List, java.lang.Object) 
505     */
506    @SuppressWarnings("unchecked")
507    public static <T> void fill(ObservableList<? super T> list, T obj) {
508        T[] newContent = (T[]) new Object[list.size()];
509        Arrays.fill(newContent, obj);
510        list.setAll(newContent);
511    }
512
513    /**
514     * Replace all oldVal elements in the list with newVal element.
515     * Fires only <b>one</b> change notification on the list.
516     * @param list the list which will have it's elements replaced
517     * @param oldVal the element that is going to be replace
518     * @param newVal the replacement
519     * @return true if the list was modified
520     * @see Collections#replaceAll(java.util.List, java.lang.Object, java.lang.Object) 
521     */
522    @SuppressWarnings("unchecked")
523    public static <T> boolean replaceAll(ObservableList<T> list, T oldVal, T newVal) {
524        T[] newContent = (T[]) list.toArray();
525        boolean modified = false;
526        for (int i = 0 ; i < newContent.length; ++i) {
527            if (newContent[i].equals(oldVal)) {
528                newContent[i] = newVal;
529                modified = true;
530            }
531        }
532        if (modified) {
533            list.setAll(newContent);
534        }
535        return modified;
536    }
537
538    /**
539     * Reverse the order in the list
540     * Fires only <b>one</b> change notification on the list.
541     * @param list the list to be reversed
542     * @see Collections#reverse(java.util.List) 
543     */
544    @SuppressWarnings("unchecked")
545    public static void reverse(ObservableList list) {
546        Object[] newContent = list.toArray();
547        for (int i = 0; i < newContent.length / 2; ++i) {
548            Object tmp = newContent[i];
549            newContent[i] = newContent[newContent.length - i - 1];
550            newContent[newContent.length -i - 1] = tmp;
551        }
552        list.setAll(newContent);
553    }
554
555    /**
556     * Rotates the list by distance.
557     * Fires only <b>one</b> change notification on the list.
558     * @param list the list to be rotated
559     * @param distance the distance of rotation
560     * @see Collections#rotate(java.util.List, int) 
561     */
562    @SuppressWarnings("unchecked")
563    public static void rotate(ObservableList list, int distance) {
564        Object[] newContent = list.toArray();
565
566        int size = list.size();
567        distance = distance % size;
568        if (distance < 0)
569            distance += size;
570        if (distance == 0)
571            return;
572
573        for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
574            Object displaced = newContent[cycleStart];
575            Object tmp;
576            int i = cycleStart;
577            do {
578                i += distance;
579                if (i >= size)
580                    i -= size;
581                tmp = newContent[i];
582                newContent[i] = displaced;
583                displaced = tmp;
584                nMoved ++;
585            } while(i != cycleStart);
586        }
587        list.setAll(newContent);
588    }
589
590    /**
591     * Shuffles all elements in the observable list.
592     * Fires only <b>one</b> change notification on the list.
593     * @param list the list to shuffle
594     * @see Collections#shuffle(java.util.List)
595     */
596    public static void shuffle(ObservableList<?> list) {
597        if (r == null) {
598            r = new Random();
599        }
600        shuffle(list, r);
601    }
602    private static Random r;
603
604    /**
605     * Shuffles all elements in the observable list.
606     * Fires only <b>one</b> change notification on the list.
607     * @param list the list to be shuffled
608     * @param rnd the random generator used for shuffling 
609     * @see Collections#shuffle(java.util.List, java.util.Random) 
610     */
611    @SuppressWarnings("unchecked")
612    public static void shuffle(ObservableList list, Random rnd) {
613        Object newContent[] = list.toArray();
614
615        for (int i = list.size(); i > 1; i--) {
616            swap(newContent, i - 1, rnd.nextInt(i));
617        }
618
619        list.setAll(newContent);
620    }
621
622    private static void swap(Object[] arr, int i, int j) {
623        Object tmp = arr[i];
624        arr[i] = arr[j];
625        arr[j] = tmp;
626    }
627
628    /**
629     * Sorts the provided observable list.
630     * Fires only <b>one</b> change notification on the list.
631     * @see Collections#sort(java.util.List)
632     */
633    @SuppressWarnings("unchecked")
634    public static <T extends Comparable<? super T>> void sort(ObservableList<T> list) {
635        if (list instanceof SortableList) {
636            ((SortableList<? extends T>)list).sort();
637        } else {
638            List<T> newContent = new ArrayList<T>(list);
639            Collections.sort(newContent);
640            list.setAll((Collection<T>)newContent);
641        }
642    }
643
644    /**
645     * Sorts the provided observable list using the c comparator.
646     * Fires only <b>one</b> change notification on the list.
647     * @param list the list to sort
648     * @param c comparator used for sorting. Null if natural ordering is required.
649     * @see Collections#sort(java.util.List, java.util.Comparator) 
650     */
651    @SuppressWarnings("unchecked")
652    public static <T> void sort(ObservableList<T> list, Comparator<? super T> c) {
653        if (list instanceof SortableList) {
654            ((SortableList<? extends T>)list).sort(c);
655        } else {
656            List<T> newContent = new ArrayList<T>(list);
657            Collections.sort(newContent, c);
658            list.setAll((Collection<T>)newContent);
659        }
660    }
661
662    private static class EmptyObservableList<E> extends AbstractList<E> implements ObservableList<E> {
663
664        private static final ListIterator iterator = new ListIterator() {
665
666            @Override
667            public boolean hasNext() {
668                return false;
669            }
670
671            @Override
672            public Object next() {
673                throw new NoSuchElementException();
674            }
675
676            @Override
677            public void remove() {
678                throw new UnsupportedOperationException();
679            }
680
681            @Override
682            public boolean hasPrevious() {
683                return false;
684            }
685
686            @Override
687            public Object previous() {
688                throw new NoSuchElementException();
689            }
690
691            @Override
692            public int nextIndex() {
693                return 0;
694            }
695
696            @Override
697            public int previousIndex() {
698                return -1;
699            }
700
701            @Override
702            public void set(Object e) {
703                throw new UnsupportedOperationException();
704            }
705
706            @Override
707            public void add(Object e) {
708                throw new UnsupportedOperationException();
709            }
710        };
711
712        public EmptyObservableList() {
713        }
714
715        @Override
716        public final void addListener(InvalidationListener listener) {
717        }
718        
719        @Override
720        public final void removeListener(InvalidationListener listener) {
721        }
722        
723
724        @Override
725        public void addListener(ListChangeListener<? super E> o) {
726        }
727
728        @Override
729        public void removeListener(ListChangeListener<? super E> o) {
730        }
731
732        @Override
733        public int size() {
734            return 0;
735        }
736
737        @Override
738        public boolean contains(Object o) {
739            return false;
740        }
741
742        @Override
743        @SuppressWarnings("unchecked")
744        public Iterator<E> iterator() {
745            return iterator;
746        }
747
748        @Override
749        public boolean containsAll(Collection<?> c) {
750            return c.isEmpty();
751        }
752
753        @Override
754        public E get(int index) {
755            throw new IndexOutOfBoundsException();
756        }
757
758        @Override
759        public int indexOf(Object o) {
760            return -1;
761        }
762
763        @Override
764        public int lastIndexOf(Object o) {
765            return -1;
766        }
767
768        @Override
769        @SuppressWarnings("unchecked")
770        public ListIterator<E> listIterator() {
771            return iterator;
772        }
773
774        @Override
775        @SuppressWarnings("unchecked")
776        public ListIterator<E> listIterator(int index) {
777            if (index != 0) {
778                throw new IndexOutOfBoundsException();
779            }
780            return iterator;
781        }
782
783        @Override
784        public List<E> subList(int fromIndex, int toIndex) {
785            if (fromIndex != 0 || toIndex != 0) {
786                throw new IndexOutOfBoundsException();
787            }
788            return this;
789        }
790
791        @Override
792        public boolean addAll(E... elements) {
793            throw new UnsupportedOperationException();
794        }
795
796        @Override
797        public boolean setAll(E... elements) {
798            throw new UnsupportedOperationException();
799        }
800
801        @Override
802        public boolean setAll(Collection<? extends E> col) {
803            throw new UnsupportedOperationException();
804        }
805
806        @Override
807        public boolean removeAll(E... elements) {
808            throw new UnsupportedOperationException();
809        }
810
811        @Override
812        public boolean retainAll(E... elements) {
813            throw new UnsupportedOperationException();
814        }
815        
816        @Override
817        public void remove(int from, int to) {
818            throw new UnsupportedOperationException();
819        }
820    }
821
822    private static class SingletonObservableList<E> extends AbstractList<E> implements ObservableList<E> {
823
824        private final E element;
825
826        public SingletonObservableList(E element) {
827            if (element == null) {
828                throw new NullPointerException();
829            }
830            this.element = element;
831        }
832
833        @Override
834        public boolean addAll(E... elements) {
835            throw new UnsupportedOperationException();
836        }
837
838        @Override
839        public boolean setAll(E... elements) {
840            throw new UnsupportedOperationException();
841        }
842
843        @Override
844        public boolean setAll(Collection<? extends E> col) {
845            throw new UnsupportedOperationException();
846        }
847
848        @Override
849        public boolean removeAll(E... elements) {
850            throw new UnsupportedOperationException();
851        }
852
853        @Override
854        public boolean retainAll(E... elements) {
855            throw new UnsupportedOperationException();
856        }
857
858        @Override
859        public void remove(int from, int to) {
860            throw new UnsupportedOperationException();
861        }
862
863        @Override
864        public void addListener(InvalidationListener listener) {
865        }
866        
867        @Override
868        public void removeListener(InvalidationListener listener) {
869        }
870        
871        @Override
872        public void addListener(ListChangeListener<? super E> o) {
873        }
874        
875        @Override
876        public void removeListener(ListChangeListener<? super E> o) {
877        }
878
879        @Override
880        public int size() {
881            return 1;
882        }
883
884        @Override
885        public boolean isEmpty() {
886            return false;
887        }
888
889        @Override
890        public boolean contains(Object o) {
891            return element.equals(o);
892        }
893
894        @Override
895        public E get(int index) {
896            if (index != 0) {
897                throw new IndexOutOfBoundsException();
898            }
899            return element;
900        }
901
902    }
903
904    private static class UnmodifiableObservableListImpl<T> extends ObservableListBase<T> implements ObservableList<T> {
905
906        private final ObservableList<T> backingList;
907        private final ListChangeListener<T> listener;
908
909        public UnmodifiableObservableListImpl(ObservableList<T> backingList) {
910            this.backingList = backingList;
911            listener = new ListChangeListener<T>() {
912
913                @Override
914                public void onChanged(Change<? extends T> c) {
915                    fireChange(new SourceAdapterChange<T>(UnmodifiableObservableListImpl.this, c));
916                }
917            };
918            this.backingList.addListener(new WeakListChangeListener<T>(listener));
919        }
920
921        @Override
922        public T get(int index) {
923            return backingList.get(index);
924        }
925
926        @Override
927        public int size() {
928            return backingList.size();
929        }
930
931        @Override
932        public boolean addAll(T... elements) {
933            throw new UnsupportedOperationException();
934        }
935
936        @Override
937        public boolean setAll(T... elements) {
938            throw new UnsupportedOperationException();
939        }
940
941        @Override
942        public boolean setAll(Collection<? extends T> col) {
943            throw new UnsupportedOperationException();
944        }
945
946        @Override
947        public boolean removeAll(T... elements) {
948            throw new UnsupportedOperationException();
949        }
950
951        @Override
952        public boolean retainAll(T... elements) {
953            throw new UnsupportedOperationException();
954        }
955
956        @Override
957        public void remove(int from, int to) {
958            throw new UnsupportedOperationException();
959        }
960
961    }
962
963    private static class SynchronizedList<T> implements List<T> {
964        final Object mutex;
965        private final List<T> backingList;
966
967        SynchronizedList(List<T> list, Object mutex) {
968            this.backingList = list;
969            this.mutex = mutex;
970        }
971
972        SynchronizedList(List<T> seq) {
973            this (seq, new Object());
974        }
975
976
977        @Override
978        public int size() {
979            synchronized(mutex) {
980                return backingList.size();
981            }
982        }
983
984        @Override
985        public boolean isEmpty() {
986            synchronized(mutex) {
987                return backingList.isEmpty();
988            }
989        }
990
991        @Override
992        public boolean contains(Object o) {
993            synchronized(mutex) {
994                return backingList.contains(o);
995            }
996        }
997
998        @Override
999        public Iterator<T> iterator() {
1000            return backingList.iterator();
1001        }
1002
1003        @Override
1004        public Object[] toArray() {
1005            synchronized(mutex)  {
1006                return backingList.toArray();
1007            }
1008        }
1009
1010        @Override
1011        public <T> T[] toArray(T[] a) {
1012            synchronized(mutex) {
1013                return backingList.toArray(a);
1014            }
1015        }
1016
1017        @Override
1018        public boolean add(T e) {
1019            synchronized(mutex) {
1020                return backingList.add(e);
1021            }
1022        }
1023
1024        @Override
1025        public boolean remove(Object o) {
1026            synchronized(mutex) {
1027                return backingList.remove(o);
1028            }
1029        }
1030
1031        @Override
1032        public boolean containsAll(Collection<?> c) {
1033            synchronized(mutex) {
1034                return backingList.containsAll(c);
1035            }
1036        }
1037
1038        @Override
1039        public boolean addAll(Collection<? extends T> c) {
1040            synchronized(mutex) {
1041                return backingList.addAll(c);
1042            }
1043        }
1044
1045        @Override
1046        public boolean addAll(int index, Collection<? extends T> c) {
1047            synchronized(mutex) {
1048                return backingList.addAll(index, c);
1049
1050            }
1051        }
1052
1053        @Override
1054        public boolean removeAll(Collection<?> c) {
1055            synchronized(mutex) {
1056                return backingList.removeAll(c);
1057            }
1058        }
1059
1060        @Override
1061        public boolean retainAll(Collection<?> c) {
1062            synchronized(mutex) {
1063                return backingList.retainAll(c);
1064            }
1065        }
1066
1067        @Override
1068        public void clear() {
1069            synchronized(mutex) {
1070                backingList.clear();
1071            }
1072        }
1073
1074        @Override
1075        public T get(int index) {
1076            synchronized(mutex) {
1077                return backingList.get(index);
1078            }
1079        }
1080
1081        @Override
1082        public T set(int index, T element) {
1083            synchronized(mutex) {
1084                return backingList.set(index, element);
1085            }
1086        }
1087
1088        @Override
1089        public void add(int index, T element) {
1090            synchronized(mutex) {
1091                backingList.add(index, element);
1092            }
1093        }
1094
1095        @Override
1096        public T remove(int index) {
1097            synchronized(mutex) {
1098                return backingList.remove(index);
1099            }
1100        }
1101
1102        @Override
1103        public int indexOf(Object o) {
1104            synchronized(mutex) {
1105                return backingList.indexOf(o);
1106            }
1107        }
1108
1109        @Override
1110        public int lastIndexOf(Object o) {
1111            synchronized(mutex) {
1112                return backingList.lastIndexOf(o);
1113            }
1114        }
1115
1116        @Override
1117        public ListIterator<T> listIterator() {
1118            return backingList.listIterator();
1119        }
1120
1121        @Override
1122        public ListIterator<T> listIterator(int index) {
1123            synchronized(mutex) {
1124                return backingList.listIterator(index);
1125            }
1126        }
1127
1128        @Override
1129        public List<T> subList(int fromIndex, int toIndex) {
1130            synchronized(mutex) {
1131                return new SynchronizedList<T>(backingList.subList(fromIndex, toIndex),
1132                        mutex);
1133            }
1134        }
1135
1136        @Override
1137        public String toString() {
1138            synchronized(mutex) {
1139                return backingList.toString();
1140            }
1141        }
1142
1143        @Override
1144        public int hashCode() {
1145            synchronized(mutex) {
1146                return backingList.hashCode();
1147            }
1148        }
1149
1150        @Override
1151        public boolean equals(Object o) {
1152            synchronized(mutex) {
1153                return backingList.equals(o);
1154            }
1155        }
1156
1157    }
1158
1159    private static class SynchronizedObservableList<T> extends SynchronizedList<T> implements ObservableList<T> {
1160
1161        private ListListenerHelper helper;
1162
1163        private final ObservableList<T> backingList;
1164        private final ListChangeListener<T> listener;
1165
1166        SynchronizedObservableList(ObservableList<T> seq, Object mutex) {
1167            super(seq, mutex);
1168            this.backingList = seq;
1169            listener = new ListChangeListener<T>() {
1170
1171                @Override
1172                public void onChanged(Change<? extends T> c) {
1173                    ListListenerHelper.fireValueChangedEvent(helper, new SourceAdapterChange<T>(SynchronizedObservableList.this, c));
1174                }
1175            };
1176            backingList.addListener(new WeakListChangeListener<T>(listener));
1177        }
1178
1179        SynchronizedObservableList(ObservableList<T> seq) {
1180            this(seq, new Object());
1181        }
1182
1183        @Override
1184        public boolean addAll(T... elements) {
1185            synchronized(mutex) {
1186                return backingList.addAll(elements);
1187            }
1188        }
1189
1190        @Override
1191        public boolean setAll(T... elements) {
1192            synchronized(mutex) {
1193                return backingList.setAll(elements);
1194            }
1195        }
1196
1197        @Override
1198        public boolean removeAll(T... elements) {
1199            synchronized(mutex) {
1200                return backingList.removeAll(elements);
1201            }
1202        }
1203
1204        @Override
1205        public boolean retainAll(T... elements) {
1206            synchronized(mutex) {
1207                return backingList.retainAll(elements);
1208            }
1209        }
1210
1211        @Override
1212        public void remove(int from, int to) {
1213            synchronized(mutex) {
1214                backingList.remove(from, to);
1215            }
1216        }
1217
1218        @Override
1219        public boolean setAll(Collection<? extends T> col) {
1220            synchronized(mutex) {
1221                return backingList.setAll(col);
1222            }
1223        }
1224
1225        @Override
1226        public final void addListener(InvalidationListener listener) {
1227            helper = ListListenerHelper.addListener(helper, listener);
1228        }
1229        
1230        @Override
1231        public final void removeListener(InvalidationListener listener) {
1232            helper = ListListenerHelper.removeListener(helper, listener);
1233        }
1234        
1235        @Override
1236        public void addListener(ListChangeListener<? super T> listener) {
1237            helper = ListListenerHelper.addListener(helper, listener);
1238        }
1239
1240        @Override
1241        public void removeListener(ListChangeListener<? super T> listener) {
1242            helper = ListListenerHelper.removeListener(helper, listener);
1243        }
1244
1245
1246    }
1247
1248    private static class CheckedObservableList<T> extends ObservableListBase<T> implements ObservableList<T> {
1249
1250        private final ObservableList<T> list;
1251        private final Class<T> type;
1252        private final ListChangeListener<T> listener;
1253
1254        CheckedObservableList(ObservableList<T> list, Class<T> type) {
1255            if (list == null || type == null) {
1256                throw new NullPointerException();
1257            }
1258            this.list = list;
1259            this.type = type;
1260            listener = new ListChangeListener<T>() {
1261
1262                @Override
1263                public void onChanged(Change<? extends T> c) {
1264                    fireChange(new SourceAdapterChange<T>(CheckedObservableList.this, c));
1265                }
1266            };
1267            list.addListener(new WeakListChangeListener<T>(listener));
1268        }
1269
1270        void typeCheck(Object o) {
1271            if (o != null && !type.isInstance(o)) {
1272                throw new ClassCastException("Attempt to insert "
1273                        + o.getClass() + " element into collection with element type "
1274                        + type);
1275            }
1276        }
1277
1278        @Override
1279        public int size() {
1280            return list.size();
1281        }
1282
1283        @Override
1284        public boolean isEmpty() {
1285            return list.isEmpty();
1286        }
1287
1288        @Override
1289        public boolean contains(Object o) {
1290            return list.contains(o);
1291        }
1292
1293        @Override
1294        public Object[] toArray() {
1295            return list.toArray();
1296        }
1297
1298        @Override
1299        public <T> T[] toArray(T[] a) {
1300            return list.toArray(a);
1301        }
1302
1303        @Override
1304        public String toString() {
1305            return list.toString();
1306        }
1307
1308        @Override
1309        public boolean remove(Object o) {
1310            return list.remove(o);
1311        }
1312
1313        @Override
1314        public boolean containsAll(Collection<?> coll) {
1315            return list.containsAll(coll);
1316        }
1317
1318        @Override
1319        public boolean removeAll(Collection<?> coll) {
1320            return list.removeAll(coll);
1321        }
1322
1323        @Override
1324        public boolean retainAll(Collection<?> coll) {
1325            return list.retainAll(coll);
1326        }
1327
1328        @Override
1329        public boolean removeAll(T... elements) {
1330            return list.removeAll(elements);
1331        }
1332
1333        @Override
1334        public boolean retainAll(T... elements) {
1335            return list.retainAll(elements);
1336        }
1337
1338        @Override
1339        public void remove(int from, int to) {
1340            list.remove(from, to);
1341        }
1342
1343        @Override
1344        public void clear() {
1345            list.clear();
1346        }
1347
1348        @Override
1349        public boolean equals(Object o) {
1350            return o == this || list.equals(o);
1351        }
1352
1353        @Override
1354        public int hashCode() {
1355            return list.hashCode();
1356        }
1357
1358        @Override
1359        public T get(int index) {
1360            return list.get(index);
1361        }
1362
1363        @Override
1364        public T remove(int index) {
1365            return list.remove(index);
1366        }
1367
1368        @Override
1369        public int indexOf(Object o) {
1370            return list.indexOf(o);
1371        }
1372
1373        @Override
1374        public int lastIndexOf(Object o) {
1375            return list.lastIndexOf(o);
1376        }
1377
1378        @Override
1379        public T set(int index, T element) {
1380            typeCheck(element);
1381            return list.set(index, element);
1382        }
1383
1384        @Override
1385        public void add(int index, T element) {
1386            typeCheck(element);
1387            list.add(index, element);
1388        }
1389
1390        @Override
1391        @SuppressWarnings("unchecked")
1392        public boolean addAll(int index, Collection<? extends T> c) {
1393            T[] a = null;
1394            try {
1395                a = c.toArray((T[]) Array.newInstance(type, 0));
1396            } catch (ArrayStoreException e) {
1397                throw new ClassCastException();
1398            }
1399
1400            return this.list.addAll(index, Arrays.asList(a));
1401        }
1402
1403        @Override
1404        @SuppressWarnings("unchecked")
1405        public boolean addAll(Collection<? extends T> coll) {
1406            T[] a = null;
1407            try {
1408                a = coll.toArray((T[]) Array.newInstance(type, 0));
1409            } catch (ArrayStoreException e) {
1410                throw new ClassCastException();
1411            }
1412
1413            return this.list.addAll(Arrays.asList(a));
1414        }
1415
1416        @Override
1417        public ListIterator<T> listIterator() {
1418            return listIterator(0);
1419        }
1420
1421        @Override
1422        public ListIterator<T> listIterator(final int index) {
1423            return new ListIterator<T>() {
1424
1425                ListIterator<T> i = list.listIterator(index);
1426
1427                @Override
1428                public boolean hasNext() {
1429                    return i.hasNext();
1430                }
1431
1432                @Override
1433                public T next() {
1434                    return i.next();
1435                }
1436
1437                @Override
1438                public boolean hasPrevious() {
1439                    return i.hasPrevious();
1440                }
1441
1442                @Override
1443                public T previous() {
1444                    return i.previous();
1445                }
1446
1447                @Override
1448                public int nextIndex() {
1449                    return i.nextIndex();
1450                }
1451
1452                @Override
1453                public int previousIndex() {
1454                    return i.previousIndex();
1455                }
1456
1457                @Override
1458                public void remove() {
1459                    i.remove();
1460                }
1461
1462                @Override
1463                public void set(T e) {
1464                    typeCheck(e);
1465                    i.set(e);
1466                }
1467
1468                @Override
1469                public void add(T e) {
1470                    typeCheck(e);
1471                    i.add(e);
1472                }
1473            };
1474        }
1475
1476        @Override
1477        public Iterator<T> iterator() {
1478            return new Iterator<T>() {
1479
1480                private final Iterator<T> it = list.iterator();
1481
1482                @Override
1483                public boolean hasNext() {
1484                    return it.hasNext();
1485                }
1486
1487                @Override
1488                public T next() {
1489                    return it.next();
1490                }
1491
1492                @Override
1493                public void remove() {
1494                    it.remove();
1495                }
1496            };
1497        }
1498
1499        @Override
1500        public boolean add(T e) {
1501            typeCheck(e);
1502            return list.add(e);
1503        }
1504
1505        @Override
1506        public List<T> subList(int fromIndex, int toIndex) {
1507            return Collections.checkedList(list.subList(fromIndex, toIndex), type);
1508        }
1509
1510        @Override
1511        @SuppressWarnings("unchecked")
1512        public boolean addAll(T... elements) {
1513            try {
1514                T[] array = (T[]) Array.newInstance(type, elements.length);
1515                System.arraycopy(elements, 0, array, 0, elements.length);
1516                return list.addAll(array);
1517            } catch (ArrayStoreException e) {
1518                throw new ClassCastException();
1519            }
1520        }
1521
1522        @Override
1523        @SuppressWarnings("unchecked")
1524        public boolean setAll(T... elements) {
1525            try {
1526                T[] array = (T[]) Array.newInstance(type, elements.length);
1527                System.arraycopy(elements, 0, array, 0, elements.length);
1528                return list.setAll(array);
1529            } catch (ArrayStoreException e) {
1530                throw new ClassCastException();
1531            }
1532        }
1533
1534        @Override
1535        @SuppressWarnings("unchecked")
1536        public boolean setAll(Collection<? extends T> col) {
1537            T[] a = null;
1538            try {
1539                a = col.toArray((T[]) Array.newInstance(type, 0));
1540            } catch (ArrayStoreException e) {
1541                throw new ClassCastException();
1542            }
1543
1544            return list.setAll(Arrays.asList(a));
1545        }
1546    }
1547
1548    private static class EmptyObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> {
1549
1550        public EmptyObservableSet() {
1551        }
1552
1553        @Override
1554        public void addListener(InvalidationListener listener) {
1555        }
1556
1557        @Override
1558        public void removeListener(InvalidationListener listener) {
1559        }
1560
1561        @Override
1562        public void addListener(SetChangeListener<? super E> listener) {
1563        }
1564
1565        @Override
1566        public void removeListener(SetChangeListener<? super E> listener) {
1567        }
1568
1569        @Override
1570        public int size() {
1571            return 0;
1572        }
1573
1574        @Override
1575        public boolean isEmpty() {
1576            return true;
1577        }
1578
1579        @Override
1580        public boolean contains(Object obj) {
1581            return false;
1582        }
1583
1584        @Override
1585        public boolean containsAll(Collection<?> c) {
1586            return c.isEmpty();
1587        }
1588
1589        @Override
1590        public Object[] toArray() {
1591            return new Object[0];
1592        }
1593
1594        @Override
1595        public <E> E[] toArray(E[] a) {
1596            if (a.length > 0)
1597                a[0] = null;
1598            return a;
1599        }
1600
1601        @Override
1602        public Iterator<E> iterator() {
1603            return new Iterator() {
1604
1605                @Override
1606                public boolean hasNext() {
1607                    return false;
1608                }
1609
1610                @Override
1611                public Object next() {
1612                    throw new NoSuchElementException();
1613                }
1614
1615                @Override
1616                public void remove() {
1617                    throw new UnsupportedOperationException();
1618                }
1619            };
1620        }
1621
1622    }
1623
1624    private static class UnmodifiableObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> {
1625
1626        private final ObservableSet<E> backingSet;
1627        private SetListenerHelper<E> listenerHelper;
1628        private final SetChangeListener<E> listener;
1629
1630        public UnmodifiableObservableSet(ObservableSet<E> backingSet) {
1631            this.backingSet = backingSet;
1632            listener = new SetChangeListener<E>() {
1633                @Override
1634                public void onChanged(Change<? extends E> c) {
1635                    callObservers(new SetAdapterChange<E>(UnmodifiableObservableSet.this, c));
1636                }
1637            };
1638            this.backingSet.addListener(new WeakSetChangeListener<E>(listener));
1639        }
1640
1641        private void callObservers(SetChangeListener.Change<? extends E> change) {
1642            SetListenerHelper.fireValueChangedEvent(listenerHelper, change);
1643        }
1644
1645        @Override
1646        public Iterator<E> iterator() {
1647            return new Iterator<E>() {
1648                private final Iterator<? extends E> i = backingSet.iterator();
1649
1650                @Override
1651                public boolean hasNext() {
1652                    return i.hasNext();
1653                }
1654
1655                @Override
1656                public E next() {
1657                    return i.next();
1658                }
1659
1660                @Override
1661                public void remove() {
1662                    throw new UnsupportedOperationException();
1663                }
1664            };
1665        }
1666
1667        @Override
1668        public int size() {
1669            return backingSet.size();
1670        }
1671
1672        @Override
1673        public void addListener(InvalidationListener listener) {
1674            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1675        }
1676
1677        @Override
1678        public void removeListener(InvalidationListener listener) {
1679            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1680        }
1681
1682        @Override
1683        public void addListener(SetChangeListener<? super E> listener) {
1684            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1685        }
1686
1687        @Override
1688        public void removeListener(SetChangeListener<? super E> listener) {
1689            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1690        }
1691
1692        @Override
1693        public boolean add(E e) {
1694            throw new UnsupportedOperationException();
1695        }
1696
1697        @Override
1698        public boolean remove(Object o) {
1699            throw new UnsupportedOperationException();
1700        }
1701
1702        @Override
1703        public boolean addAll(Collection<? extends E> c) {
1704            throw new UnsupportedOperationException();
1705        }
1706
1707        @Override
1708        public boolean retainAll(Collection<?> c) {
1709            throw new UnsupportedOperationException();
1710        }
1711
1712        @Override
1713        public boolean removeAll(Collection<?> c) {
1714            throw new UnsupportedOperationException();
1715        }
1716
1717        @Override
1718        public void clear() {
1719            throw new UnsupportedOperationException();
1720        }
1721    }
1722
1723    private static class SynchronizedSet<E> implements Set<E> {
1724        final Object mutex;
1725        private final Set<E> backingSet;
1726
1727        SynchronizedSet(Set<E> set, Object mutex) {
1728            this.backingSet = set;
1729            this.mutex = mutex;
1730        }
1731
1732        SynchronizedSet(Set<E> set) {
1733            this(set, new Object());
1734        }
1735
1736        @Override
1737        public int size() {
1738            synchronized(mutex) {
1739                return backingSet.size();
1740            }
1741        }
1742
1743        @Override
1744        public boolean isEmpty() {
1745            synchronized(mutex) {
1746                return backingSet.isEmpty();
1747            }
1748        }
1749
1750        @Override
1751        public boolean contains(Object o) {
1752            synchronized(mutex) {
1753                return backingSet.contains(o);
1754            }
1755        }
1756
1757        @Override
1758        public Iterator<E> iterator() {
1759            return backingSet.iterator();
1760        }
1761
1762        @Override
1763        public Object[] toArray() {
1764            synchronized(mutex) {
1765                return backingSet.toArray();
1766            }
1767        }
1768
1769        @Override
1770        public <E> E[] toArray(E[] a) {
1771            synchronized(mutex) {
1772                return backingSet.toArray(a);
1773            }
1774        }
1775
1776        @Override
1777        public boolean add(E e) {
1778            synchronized(mutex) {
1779                return backingSet.add(e);
1780            }
1781        }
1782
1783        @Override
1784        public boolean remove(Object o) {
1785            synchronized(mutex) {
1786                return backingSet.remove(o);
1787            }
1788        }
1789
1790        @Override
1791        public boolean containsAll(Collection<?> c) {
1792            synchronized(mutex) {
1793                return backingSet.containsAll(c);
1794            }
1795        }
1796
1797        @Override
1798        public boolean addAll(Collection<? extends E> c) {
1799            synchronized(mutex) {
1800                return backingSet.addAll(c);
1801            }
1802        }
1803
1804        @Override
1805        public boolean retainAll(Collection<?> c) {
1806            synchronized(mutex) {
1807                return backingSet.retainAll(c);
1808            }
1809        }
1810
1811        @Override
1812        public boolean removeAll(Collection<?> c) {
1813            synchronized(mutex) {
1814                return backingSet.removeAll(c);
1815            }
1816        }
1817
1818        @Override
1819        public void clear() {
1820            synchronized(mutex) {
1821                backingSet.clear();
1822            }
1823        }
1824        
1825        @Override
1826        public boolean equals(Object o) {
1827            if (o == this) {
1828                return true;
1829            }
1830            synchronized(mutex) {
1831                return backingSet.equals(o);
1832            }
1833        }
1834
1835        @Override
1836        public int hashCode() {
1837            synchronized (mutex) {
1838                return backingSet.hashCode();
1839            }
1840        }
1841    }
1842
1843    private static class SynchronizedObservableSet<E> extends SynchronizedSet<E> implements ObservableSet<E> {
1844
1845        private final ObservableSet<E> backingSet;
1846        private SetListenerHelper listenerHelper;
1847        private final SetChangeListener<E> listener;
1848
1849        SynchronizedObservableSet(ObservableSet<E> set, Object mutex) {
1850            super(set, mutex);
1851            backingSet = set;
1852            listener = new SetChangeListener<E>() {
1853                @Override
1854                public void onChanged(Change<? extends E> c) {
1855                    SetListenerHelper.fireValueChangedEvent(listenerHelper, new SetAdapterChange<E>(SynchronizedObservableSet.this, c));
1856                }
1857            };
1858            backingSet.addListener(new WeakSetChangeListener<E>(listener));
1859        }
1860
1861        SynchronizedObservableSet(ObservableSet<E> set) {
1862            this(set, new Object());
1863        }
1864
1865        @Override
1866        public void addListener(InvalidationListener listener) {
1867            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1868        }
1869
1870        @Override
1871        public void removeListener(InvalidationListener listener) {
1872            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1873        }
1874        @Override
1875        public void addListener(SetChangeListener<? super E> listener) {
1876            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1877        }
1878
1879        @Override
1880        public void removeListener(SetChangeListener<? super E> listener) {
1881            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1882        }
1883    }
1884
1885    private static class CheckedObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> {
1886
1887        private final ObservableSet<E> backingSet;
1888        private final Class<E> type;
1889        private SetListenerHelper listenerHelper;
1890        private final SetChangeListener<E> listener;
1891
1892        CheckedObservableSet(ObservableSet<E> set, Class<E> type) {
1893            if (set == null || type == null) {
1894                throw new NullPointerException();
1895            }
1896            backingSet = set;
1897            this.type = type;
1898            listener = new SetChangeListener<E>() {
1899                @Override
1900                public void onChanged(SetChangeListener.Change<? extends E> c) {
1901                    callObservers(new SetAdapterChange<E>(CheckedObservableSet.this, c));
1902                }
1903            };
1904            backingSet.addListener(new WeakSetChangeListener<E>(listener));
1905        }
1906
1907        private void callObservers(SetChangeListener.Change<? extends E> c) {
1908            SetListenerHelper.fireValueChangedEvent(listenerHelper, c);
1909        }
1910
1911        void typeCheck(Object o) {
1912            if (o != null && !type.isInstance(o)) {
1913                throw new ClassCastException("Attempt to insert "
1914                        + o.getClass() + " element into collection with element type "
1915                        + type);
1916            }
1917        }
1918
1919        @Override
1920        public void addListener(InvalidationListener listener) {
1921            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1922        }
1923
1924        @Override
1925        public void removeListener(InvalidationListener listener) {
1926            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1927        }
1928
1929        @Override
1930        public void addListener(SetChangeListener<? super E> listener) {
1931            listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1932        }
1933
1934        @Override
1935        public void removeListener(SetChangeListener<? super E> listener) {
1936            listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1937        }
1938
1939        @Override
1940        public int size() {
1941            return backingSet.size();
1942        }
1943
1944        @Override
1945        public boolean isEmpty() {
1946            return backingSet.isEmpty();
1947        }
1948
1949        @Override
1950        public boolean contains(Object o) {
1951            return backingSet.contains(o);
1952        }
1953
1954        @Override
1955        public Object[] toArray() {
1956            return backingSet.toArray();
1957        }
1958
1959        @Override
1960        public <T> T[] toArray(T[] a) {
1961            return backingSet.toArray(a);
1962        }
1963
1964        @Override
1965        public boolean add(E e) {
1966            typeCheck(e);
1967            return backingSet.add(e);
1968        }
1969
1970        @Override
1971        public boolean remove(Object o) {
1972            return backingSet.remove(o);
1973        }
1974
1975        @Override
1976        public boolean containsAll(Collection<?> c) {
1977            return backingSet.containsAll(c);
1978        }
1979
1980        @Override
1981        @SuppressWarnings("unchecked")
1982        public boolean addAll(Collection<? extends E> c) {
1983            E[] a = null;
1984            try {
1985                a = c.toArray((E[]) Array.newInstance(type, 0));
1986            } catch (ArrayStoreException e) {
1987                throw new ClassCastException();
1988            }
1989
1990            return backingSet.addAll(Arrays.asList(a));
1991        }
1992
1993        @Override
1994        public boolean retainAll(Collection<?> c) {
1995            return backingSet.retainAll(c);
1996        }
1997
1998        @Override
1999        public boolean removeAll(Collection<?> c) {
2000            return backingSet.removeAll(c);
2001        }
2002
2003        @Override
2004        public void clear() {
2005            backingSet.clear();
2006        }
2007
2008        @Override
2009        public boolean equals(Object o) {
2010            return o == this || backingSet.equals(o);
2011        }
2012
2013        @Override
2014        public int hashCode() {
2015            return backingSet.hashCode();
2016        }
2017
2018        @Override
2019        public Iterator<E> iterator() {
2020            final Iterator<E> it = backingSet.iterator();
2021
2022            return new Iterator<E>() {
2023                @Override
2024                public boolean hasNext() {
2025                    return it.hasNext();
2026                }
2027
2028                @Override
2029                public E next() {
2030                    return it.next();
2031                }
2032
2033                @Override
2034                public void remove() {
2035                    it.remove();
2036                }
2037            };
2038        }
2039
2040    }
2041
2042    private static class EmptyObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> {
2043
2044        public EmptyObservableMap() {
2045        }
2046
2047        @Override
2048        public void addListener(InvalidationListener listener) {
2049        }
2050
2051        @Override
2052        public void removeListener(InvalidationListener listener) {
2053        }
2054
2055        @Override
2056        public void addListener(MapChangeListener<? super K, ? super V> listener) {
2057        }
2058
2059        @Override
2060        public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2061        }
2062
2063        @Override
2064        public int size() {
2065            return 0;
2066        }
2067
2068        @Override
2069        public boolean isEmpty() {
2070            return true;
2071        }
2072
2073        @Override
2074        public boolean containsKey(Object key) {
2075            return false;
2076        }
2077
2078        @Override
2079        public boolean containsValue(Object value) {
2080            return false;
2081        }
2082
2083        @Override
2084        public V get(Object key) {
2085            return null;
2086        }
2087
2088        @Override
2089        public Set<K> keySet() {
2090            return emptyObservableSet();
2091        }
2092
2093        @Override
2094        public Collection<V> values() {
2095            return emptyObservableSet();
2096        }
2097
2098        @Override
2099        public Set<Map.Entry<K,V>> entrySet() {
2100            return emptyObservableSet();
2101        }
2102
2103        @Override
2104        public boolean equals(Object o) {
2105            return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
2106        }
2107
2108        @Override
2109        public int hashCode() {
2110            return 0;
2111        }
2112    }
2113
2114    private static class CheckedObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> {
2115
2116        private final ObservableMap<K, V> backingMap;
2117        private final Class<K> keyType;
2118        private final Class<V> valueType;
2119        private MapListenerHelper listenerHelper;
2120        private final MapChangeListener<K, V> listener;
2121
2122        CheckedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) {
2123            backingMap = map;
2124            this.keyType = keyType;
2125            this.valueType = valueType;
2126            listener = new MapChangeListener<K, V>() {
2127                @Override
2128                public void onChanged(MapChangeListener.Change<? extends K, ? extends V> c) {
2129                    callObservers(new MapAdapterChange<K, V>(CheckedObservableMap.this, c));
2130                }
2131            };
2132            backingMap.addListener(new WeakMapChangeListener<K, V>(listener));
2133        }
2134
2135        private void callObservers(MapChangeListener.Change<? extends K, ? extends V> c) {
2136            MapListenerHelper.fireValueChangedEvent(listenerHelper, c);
2137        }
2138
2139        void typeCheck(Object key, Object value) {
2140            if (key != null && !keyType.isInstance(key)) {
2141                throw new ClassCastException("Attempt to insert "
2142                        + key.getClass() + " key into map with key type "
2143                        + keyType);
2144            }
2145
2146            if (value != null && !valueType.isInstance(value)) {
2147                throw new ClassCastException("Attempt to insert "
2148                        + value.getClass() + " value into map with value type "
2149                        + valueType);
2150            }
2151        }
2152
2153        @Override
2154        public void addListener(InvalidationListener listener) {
2155            listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2156        }
2157
2158        @Override
2159        public void removeListener(InvalidationListener listener) {
2160            listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2161        }
2162
2163        @Override
2164        public void addListener(MapChangeListener<? super K, ? super V> listener) {
2165            listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2166        }
2167
2168        @Override
2169        public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2170            listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2171        }
2172
2173        @Override
2174        public int size() {
2175            return backingMap.size();
2176        }
2177
2178        @Override
2179        public boolean isEmpty() {
2180            return backingMap.isEmpty();
2181        }
2182
2183        @Override
2184        public boolean containsKey(Object key) {
2185            return backingMap.containsKey(key);
2186        }
2187
2188        @Override
2189        public boolean containsValue(Object value) {
2190            return backingMap.containsValue(value);
2191        }
2192
2193        @Override
2194        public V get(Object key) {
2195            return backingMap.get(key);
2196        }
2197
2198        @Override
2199        public V put(K key, V value) {
2200            typeCheck(key, value);
2201            return backingMap.put(key, value);
2202        }
2203
2204        @Override
2205        public V remove(Object key) {
2206            return backingMap.remove(key);
2207        }
2208
2209        @Override
2210        @SuppressWarnings("unchecked")
2211        public void putAll(Map t) {
2212            // Satisfy the following goals:
2213            // - good diagnostics in case of type mismatch
2214            // - all-or-nothing semantics
2215            // - protection from malicious t
2216            // - correct behavior if t is a concurrent map
2217            Object[] entries = t.entrySet().toArray();
2218            List<Map.Entry<K,V>> checked =
2219                new ArrayList<Map.Entry<K,V>>(entries.length);
2220            for (Object o : entries) {
2221                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
2222                Object k = e.getKey();
2223                Object v = e.getValue();
2224                typeCheck(k, v);
2225                checked.add(
2226                    new AbstractMap.SimpleImmutableEntry<K,V>((K) k, (V) v));
2227            }
2228            for (Map.Entry<K,V> e : checked)
2229                backingMap.put(e.getKey(), e.getValue());
2230        }
2231
2232        @Override
2233        public void clear() {
2234            backingMap.clear();
2235        }
2236
2237        @Override
2238        public Set<K> keySet() {
2239            return backingMap.keySet();
2240        }
2241
2242        @Override
2243        public Collection<V> values() {
2244            return backingMap.values();
2245        }
2246
2247        private transient Set<Map.Entry<K,V>> entrySet = null;
2248
2249        @Override
2250        public Set entrySet() {
2251            if (entrySet==null)
2252                entrySet = new CheckedEntrySet<K,V>(backingMap.entrySet(), valueType);
2253            return entrySet;
2254        }
2255
2256        @Override
2257        public boolean equals(Object o) {
2258            return o == this || backingMap.equals(o);
2259        }
2260
2261        @Override
2262        public int hashCode() {
2263            return backingMap.hashCode();
2264        }
2265
2266        static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> {
2267            private final Set<Map.Entry<K,V>> s;
2268            private final Class<V> valueType;
2269
2270            CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) {
2271                this.s = s;
2272                this.valueType = valueType;
2273            }
2274
2275            @Override
2276            public int size() {
2277                return s.size();
2278            }
2279
2280            @Override
2281            public boolean isEmpty() {
2282                return s.isEmpty();
2283            }
2284
2285            @Override
2286            public String toString() {
2287                return s.toString();
2288            }
2289
2290            @Override
2291            public int hashCode() {
2292                return s.hashCode();
2293            }
2294
2295            @Override
2296            public void clear() {
2297                s.clear();
2298            }
2299
2300            @Override
2301            public boolean add(Map.Entry<K, V> e) {
2302                throw new UnsupportedOperationException();
2303            }
2304
2305            @Override
2306            public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
2307                throw new UnsupportedOperationException();
2308            }
2309
2310            @Override
2311            public Iterator<Map.Entry<K,V>> iterator() {
2312                final Iterator<Map.Entry<K, V>> i = s.iterator();
2313                final Class<V> valueType = this.valueType;
2314
2315                return new Iterator<Map.Entry<K,V>>() {
2316                    @Override
2317                    public boolean hasNext() {
2318                        return i.hasNext();
2319                    }
2320
2321                    @Override
2322                    public void remove() {
2323                        i.remove();
2324                    }
2325
2326                    @Override
2327                    public Map.Entry<K,V> next() {
2328                        return checkedEntry(i.next(), valueType);
2329                    }
2330                };
2331            }
2332
2333            @Override
2334            @SuppressWarnings("unchecked")
2335            public Object[] toArray() {
2336                Object[] source = s.toArray();
2337
2338                /*
2339                 * Ensure that we don't get an ArrayStoreException even if
2340                 * s.toArray returns an array of something other than Object
2341                 */
2342                Object[] dest = (CheckedEntry.class.isInstance(
2343                    source.getClass().getComponentType()) ? source :
2344                                 new Object[source.length]);
2345
2346                for (int i = 0; i < source.length; i++)
2347                    dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
2348                                           valueType);
2349                return dest;
2350            }
2351
2352            @Override
2353            @SuppressWarnings("unchecked")
2354            public <T> T[] toArray(T[] a) {
2355                // We don't pass a to s.toArray, to avoid window of
2356                // vulnerability wherein an unscrupulous multithreaded client
2357                // could get his hands on raw (unwrapped) Entries from s.
2358                T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
2359
2360                for (int i=0; i<arr.length; i++)
2361                    arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i],
2362                                              valueType);
2363                if (arr.length > a.length)
2364                    return arr;
2365
2366                System.arraycopy(arr, 0, a, 0, arr.length);
2367                if (a.length > arr.length)
2368                    a[arr.length] = null;
2369                return a;
2370            }
2371
2372            /**
2373             * This method is overridden to protect the backing set against
2374             * an object with a nefarious equals function that senses
2375             * that the equality-candidate is Map.Entry and calls its
2376             * setValue method.
2377             */
2378            @Override
2379            public boolean contains(Object o) {
2380                if (!(o instanceof Map.Entry))
2381                    return false;
2382                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
2383                return s.contains(
2384                    (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
2385            }
2386
2387            /**
2388             * The bulk collection methods are overridden to protect
2389             * against an unscrupulous collection whose contains(Object o)
2390             * method senses when o is a Map.Entry, and calls o.setValue.
2391             */
2392            @Override
2393            public boolean containsAll(Collection<?> c) {
2394                for (Object o : c)
2395                    if (!contains(o)) // Invokes safe contains() above
2396                        return false;
2397                return true;
2398            }
2399
2400            @Override
2401            public boolean remove(Object o) {
2402                if (!(o instanceof Map.Entry))
2403                    return false;
2404                return s.remove(new AbstractMap.SimpleImmutableEntry
2405                                <Object, Object>((Map.Entry<?,?>)o));
2406            }
2407
2408            @Override
2409            public boolean removeAll(Collection<?> c) {
2410                return batchRemove(c, false);
2411            }
2412
2413            @Override
2414            public boolean retainAll(Collection<?> c) {
2415                return batchRemove(c, true);
2416            }
2417
2418            private boolean batchRemove(Collection<?> c, boolean complement) {
2419                boolean modified = false;
2420                Iterator<Map.Entry<K,V>> it = iterator();
2421                while (it.hasNext()) {
2422                    if (c.contains(it.next()) != complement) {
2423                        it.remove();
2424                        modified = true;
2425                    }
2426                }
2427                return modified;
2428            }
2429
2430            @Override
2431            public boolean equals(Object o) {
2432                if (o == this)
2433                    return true;
2434                if (!(o instanceof Set))
2435                    return false;
2436                Set<?> that = (Set<?>) o;
2437                return that.size() == s.size()
2438                    && containsAll(that); // Invokes safe containsAll() above
2439            }
2440
2441            static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e,
2442                                                            Class<T> valueType) {
2443                return new CheckedEntry<K,V,T>(e, valueType);
2444            }
2445
2446            /**
2447             * This "wrapper class" serves two purposes: it prevents
2448             * the client from modifying the backing Map, by short-circuiting
2449             * the setValue method, and it protects the backing Map against
2450             * an ill-behaved Map.Entry that attempts to modify another
2451             * Map.Entry when asked to perform an equality check.
2452             */
2453            private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> {
2454                private final Map.Entry<K, V> e;
2455                private final Class<T> valueType;
2456
2457                CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) {
2458                    this.e = e;
2459                    this.valueType = valueType;
2460                }
2461
2462                @Override
2463                public K getKey() {
2464                    return e.getKey();
2465                }
2466
2467                @Override
2468                public V getValue() {
2469                    return e.getValue();
2470                }
2471
2472                @Override
2473                public int hashCode() {
2474                    return e.hashCode();
2475                }
2476
2477                @Override
2478                public String toString() {
2479                    return e.toString();
2480                }
2481
2482                @Override
2483                public V setValue(V value) {
2484                    if (value != null && !valueType.isInstance(value))
2485                        throw new ClassCastException(badValueMsg(value));
2486                    return e.setValue(value);
2487                }
2488
2489                private String badValueMsg(Object value) {
2490                    return "Attempt to insert " + value.getClass() +
2491                        " value into map with value type " + valueType;
2492                }
2493
2494                @Override
2495                public boolean equals(Object o) {
2496                    if (o == this)
2497                        return true;
2498                    if (!(o instanceof Map.Entry))
2499                        return false;
2500                    return e.equals(new AbstractMap.SimpleImmutableEntry
2501                                    <Object, Object>((Map.Entry<?,?>)o));
2502                }
2503            }
2504        }
2505
2506    }
2507
2508    private static class SynchronizedMap<K, V> implements Map<K, V> {
2509        final Object mutex;
2510        private final Map<K, V> backingMap;
2511
2512        SynchronizedMap(Map<K, V> map, Object mutex) {
2513            backingMap = map;
2514            this.mutex = mutex;
2515        }
2516
2517        SynchronizedMap(Map<K, V> map) {
2518            this(map, new Object());
2519        }
2520
2521        @Override
2522        public int size() {
2523            synchronized (mutex) {
2524                return backingMap.size();
2525            }
2526        }
2527
2528        @Override
2529        public boolean isEmpty() {
2530            synchronized (mutex) {
2531                return backingMap.isEmpty();
2532            }
2533        }
2534
2535        @Override
2536        public boolean containsKey(Object key) {
2537            synchronized (mutex) {
2538                return backingMap.containsKey(key);
2539            }
2540        }
2541
2542        @Override
2543        public boolean containsValue(Object value) {
2544            synchronized (mutex) {
2545                return backingMap.containsValue(value);
2546            }
2547        }
2548
2549        @Override
2550        public V get(Object key) {
2551            synchronized (mutex) {
2552                return backingMap.get(key);
2553            }
2554        }
2555
2556        @Override
2557        public V put(K key, V value) {
2558            synchronized (mutex) {
2559                return backingMap.put(key, value);
2560            }
2561        }
2562
2563        @Override
2564        public V remove(Object key) {
2565            synchronized (mutex) {
2566                return backingMap.remove(key);
2567            }
2568        }
2569
2570        @Override
2571        public void putAll(Map<? extends K, ? extends V> m) {
2572            synchronized (mutex) {
2573                backingMap.putAll(m);
2574            }
2575        }
2576
2577        @Override
2578        public void clear() {
2579            synchronized (mutex) {
2580                backingMap.clear();
2581            }
2582        }
2583
2584        private transient Set<K> keySet = null;
2585        private transient Set<Map.Entry<K,V>> entrySet = null;
2586        private transient Collection<V> values = null;
2587
2588        @Override
2589        public Set<K> keySet() {
2590            synchronized(mutex) {
2591                if (keySet==null)
2592                    keySet = new SynchronizedSet<K>(backingMap.keySet(), mutex);
2593                return keySet;
2594            }
2595        }
2596
2597        @Override
2598        public Collection<V> values() {
2599            synchronized(mutex) {
2600                if (values==null)
2601                    values = new SynchronizedCollection<V>(backingMap.values(), mutex);
2602                return values;
2603            }
2604        }
2605
2606        @Override
2607        public Set<Entry<K, V>> entrySet() {
2608            synchronized(mutex) {
2609                if (entrySet==null)
2610                    entrySet = new SynchronizedSet<Map.Entry<K,V>>(backingMap.entrySet(), mutex);
2611                return entrySet;
2612            }
2613        }
2614        
2615        @Override
2616        public boolean equals(Object o) {
2617            if (o == this) {
2618                return true;
2619            }
2620            synchronized(mutex) {
2621                return backingMap.equals(o);
2622            }
2623        }
2624
2625        @Override
2626        public int hashCode() {
2627            synchronized(mutex) {
2628                return backingMap.hashCode();
2629            }
2630        }
2631
2632    }
2633
2634    private static class SynchronizedCollection<E> implements Collection<E> {
2635
2636        private final Collection<E> backingCollection;
2637        final Object mutex;
2638
2639        SynchronizedCollection(Collection<E> c, Object mutex) {
2640            backingCollection = c;
2641            this.mutex = mutex;
2642        }
2643
2644        SynchronizedCollection(Collection<E> c) {
2645            this(c, new Object());
2646        }
2647
2648        @Override
2649        public int size() {
2650            synchronized (mutex) {
2651                return backingCollection.size();
2652            }
2653        }
2654
2655        @Override
2656        public boolean isEmpty() {
2657            synchronized (mutex) {
2658                return backingCollection.isEmpty();
2659            }
2660        }
2661
2662        @Override
2663        public boolean contains(Object o) {
2664            synchronized (mutex) {
2665                return backingCollection.contains(o);
2666            }
2667        }
2668
2669        @Override
2670        public Iterator<E> iterator() {
2671            return backingCollection.iterator();
2672        }
2673
2674        @Override
2675        public Object[] toArray() {
2676            synchronized (mutex) {
2677                return backingCollection.toArray();
2678            }
2679        }
2680
2681        @Override
2682        public <T> T[] toArray(T[] a) {
2683            synchronized (mutex) {
2684                return backingCollection.toArray(a);
2685            }
2686        }
2687
2688        @Override
2689        public boolean add(E e) {
2690            synchronized (mutex) {
2691                return backingCollection.add(e);
2692            }
2693        }
2694
2695        @Override
2696        public boolean remove(Object o) {
2697            synchronized (mutex) {
2698                return backingCollection.remove(o);
2699            }
2700        }
2701
2702        @Override
2703        public boolean containsAll(Collection<?> c) {
2704            synchronized (mutex) {
2705                return backingCollection.containsAll(c);
2706            }
2707        }
2708
2709        @Override
2710        public boolean addAll(Collection<? extends E> c) {
2711            synchronized (mutex) {
2712                return backingCollection.addAll(c);
2713            }
2714        }
2715
2716        @Override
2717        public boolean removeAll(Collection<?> c) {
2718            synchronized (mutex) {
2719                return backingCollection.removeAll(c);
2720            }
2721        }
2722
2723        @Override
2724        public boolean retainAll(Collection<?> c) {
2725            synchronized (mutex) {
2726                return backingCollection.retainAll(c);
2727            }
2728        }
2729
2730        @Override
2731        public void clear() {
2732            synchronized (mutex) {
2733                backingCollection.clear();
2734            }
2735        }
2736    }
2737
2738    private static class SynchronizedObservableMap<K, V> extends SynchronizedMap<K, V> implements ObservableMap<K, V> {
2739
2740        private final ObservableMap<K, V> backingMap;
2741        private MapListenerHelper listenerHelper;
2742        private final MapChangeListener<K, V> listener;
2743
2744        SynchronizedObservableMap(ObservableMap<K, V> map, Object mutex) {
2745            super(map, mutex);
2746            backingMap = map;
2747            listener = new MapChangeListener<K, V>() {
2748                @Override
2749                public void onChanged(Change<? extends K, ? extends V> c) {
2750                    MapListenerHelper.fireValueChangedEvent(listenerHelper, new MapAdapterChange<K, V>(SynchronizedObservableMap.this, c));
2751                }
2752            };
2753            backingMap.addListener(new WeakMapChangeListener<K, V>(listener));
2754        }
2755
2756        SynchronizedObservableMap(ObservableMap<K, V> map) {
2757            this(map, new Object());
2758        }
2759
2760        @Override
2761        public void addListener(InvalidationListener listener) {
2762            listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2763
2764        }
2765
2766        @Override
2767        public void removeListener(InvalidationListener listener) {
2768            listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2769        }
2770
2771        @Override
2772        public void addListener(MapChangeListener<? super K, ? super V> listener) {
2773            listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2774        }
2775
2776        @Override
2777        public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2778            listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2779        }
2780
2781    }
2782
2783}