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