1 /*
   2  * Copyright (c) 2010, 2016, 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         }
1672 
1673         @Override
1674         public int size() {
1675             return backingSet.size();
1676         }
1677 
1678         @Override
1679         public boolean isEmpty() {
1680             return backingSet.isEmpty();
1681         }
1682 
1683         @Override
1684         public boolean contains(Object o) {
1685             return backingSet.contains(o);
1686         }
1687 
1688         @Override
1689         public void addListener(InvalidationListener listener) {
1690             initListener();
1691             listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1692         }
1693 
1694         @Override
1695         public void removeListener(InvalidationListener listener) {
1696             listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1697         }
1698 
1699         @Override
1700         public void addListener(SetChangeListener<? super E> listener) {
1701             initListener();
1702             listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1703         }
1704 
1705         @Override
1706         public void removeListener(SetChangeListener<? super E> listener) {
1707             listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1708         }
1709 
1710         @Override
1711         public boolean add(E e) {
1712             throw new UnsupportedOperationException();
1713         }
1714 
1715         @Override
1716         public boolean remove(Object o) {
1717             throw new UnsupportedOperationException();
1718         }
1719 
1720         @Override
1721         public boolean addAll(Collection<? extends E> c) {
1722             throw new UnsupportedOperationException();
1723         }
1724 
1725         @Override
1726         public boolean retainAll(Collection<?> c) {
1727             throw new UnsupportedOperationException();
1728         }
1729 
1730         @Override
1731         public boolean removeAll(Collection<?> c) {
1732             throw new UnsupportedOperationException();
1733         }
1734 
1735         @Override
1736         public void clear() {
1737             throw new UnsupportedOperationException();
1738         }
1739     }
1740 
1741     private static class SynchronizedSet<E> implements Set<E> {
1742         final Object mutex;
1743         private final Set<E> backingSet;
1744 
1745         SynchronizedSet(Set<E> set, Object mutex) {
1746             this.backingSet = set;
1747             this.mutex = mutex;
1748         }
1749 
1750         SynchronizedSet(Set<E> set) {
1751             this(set, new Object());
1752         }
1753 
1754         @Override
1755         public int size() {
1756             synchronized(mutex) {
1757                 return backingSet.size();
1758             }
1759         }
1760 
1761         @Override
1762         public boolean isEmpty() {
1763             synchronized(mutex) {
1764                 return backingSet.isEmpty();
1765             }
1766         }
1767 
1768         @Override
1769         public boolean contains(Object o) {
1770             synchronized(mutex) {
1771                 return backingSet.contains(o);
1772             }
1773         }
1774 
1775         @Override
1776         public Iterator<E> iterator() {
1777             return backingSet.iterator();
1778         }
1779 
1780         @Override
1781         public Object[] toArray() {
1782             synchronized(mutex) {
1783                 return backingSet.toArray();
1784             }
1785         }
1786 
1787         @Override
1788         public <E> E[] toArray(E[] a) {
1789             synchronized(mutex) {
1790                 return backingSet.toArray(a);
1791             }
1792         }
1793 
1794         @Override
1795         public boolean add(E e) {
1796             synchronized(mutex) {
1797                 return backingSet.add(e);
1798             }
1799         }
1800 
1801         @Override
1802         public boolean remove(Object o) {
1803             synchronized(mutex) {
1804                 return backingSet.remove(o);
1805             }
1806         }
1807 
1808         @Override
1809         public boolean containsAll(Collection<?> c) {
1810             synchronized(mutex) {
1811                 return backingSet.containsAll(c);
1812             }
1813         }
1814 
1815         @Override
1816         public boolean addAll(Collection<? extends E> c) {
1817             synchronized(mutex) {
1818                 return backingSet.addAll(c);
1819             }
1820         }
1821 
1822         @Override
1823         public boolean retainAll(Collection<?> c) {
1824             synchronized(mutex) {
1825                 return backingSet.retainAll(c);
1826             }
1827         }
1828 
1829         @Override
1830         public boolean removeAll(Collection<?> c) {
1831             synchronized(mutex) {
1832                 return backingSet.removeAll(c);
1833             }
1834         }
1835 
1836         @Override
1837         public void clear() {
1838             synchronized(mutex) {
1839                 backingSet.clear();
1840             }
1841         }
1842 
1843         @Override
1844         public boolean equals(Object o) {
1845             if (o == this) {
1846                 return true;
1847             }
1848             synchronized(mutex) {
1849                 return backingSet.equals(o);
1850             }
1851         }
1852 
1853         @Override
1854         public int hashCode() {
1855             synchronized (mutex) {
1856                 return backingSet.hashCode();
1857             }
1858         }
1859     }
1860 
1861     private static class SynchronizedObservableSet<E> extends SynchronizedSet<E> implements ObservableSet<E> {
1862 
1863         private final ObservableSet<E> backingSet;
1864         private SetListenerHelper listenerHelper;
1865         private final SetChangeListener<E> listener;
1866 
1867         SynchronizedObservableSet(ObservableSet<E> set, Object mutex) {
1868             super(set, mutex);
1869             backingSet = set;
1870             listener = c -> {
1871                 SetListenerHelper.fireValueChangedEvent(listenerHelper, new SetAdapterChange<E>(SynchronizedObservableSet.this, c));
1872             };
1873             backingSet.addListener(new WeakSetChangeListener<E>(listener));
1874         }
1875 
1876         SynchronizedObservableSet(ObservableSet<E> set) {
1877             this(set, new Object());
1878         }
1879 
1880         @Override
1881         public void addListener(InvalidationListener listener) {
1882             synchronized (mutex) {
1883                 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1884             }
1885         }
1886 
1887         @Override
1888         public void removeListener(InvalidationListener listener) {
1889             synchronized (mutex) {
1890                 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1891             }
1892         }
1893         @Override
1894         public void addListener(SetChangeListener<? super E> listener) {
1895             synchronized (mutex) {
1896                 listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1897             }
1898         }
1899 
1900         @Override
1901         public void removeListener(SetChangeListener<? super E> listener) {
1902             synchronized (mutex) {
1903                 listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1904             }
1905         }
1906     }
1907 
1908     private static class CheckedObservableSet<E> extends AbstractSet<E> implements ObservableSet<E> {
1909 
1910         private final ObservableSet<E> backingSet;
1911         private final Class<E> type;
1912         private SetListenerHelper listenerHelper;
1913         private final SetChangeListener<E> listener;
1914 
1915         CheckedObservableSet(ObservableSet<E> set, Class<E> type) {
1916             if (set == null || type == null) {
1917                 throw new NullPointerException();
1918             }
1919             backingSet = set;
1920             this.type = type;
1921             listener = c -> {
1922                 callObservers(new SetAdapterChange<E>(CheckedObservableSet.this, c));
1923             };
1924             backingSet.addListener(new WeakSetChangeListener<E>(listener));
1925         }
1926 
1927         private void callObservers(SetChangeListener.Change<? extends E> c) {
1928             SetListenerHelper.fireValueChangedEvent(listenerHelper, c);
1929         }
1930 
1931         void typeCheck(Object o) {
1932             if (o != null && !type.isInstance(o)) {
1933                 throw new ClassCastException("Attempt to insert "
1934                         + o.getClass() + " element into collection with element type "
1935                         + type);
1936             }
1937         }
1938 
1939         @Override
1940         public void addListener(InvalidationListener listener) {
1941             listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1942         }
1943 
1944         @Override
1945         public void removeListener(InvalidationListener listener) {
1946             listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1947         }
1948 
1949         @Override
1950         public void addListener(SetChangeListener<? super E> listener) {
1951             listenerHelper = SetListenerHelper.addListener(listenerHelper, listener);
1952         }
1953 
1954         @Override
1955         public void removeListener(SetChangeListener<? super E> listener) {
1956             listenerHelper = SetListenerHelper.removeListener(listenerHelper, listener);
1957         }
1958 
1959         @Override
1960         public int size() {
1961             return backingSet.size();
1962         }
1963 
1964         @Override
1965         public boolean isEmpty() {
1966             return backingSet.isEmpty();
1967         }
1968 
1969         @Override
1970         public boolean contains(Object o) {
1971             return backingSet.contains(o);
1972         }
1973 
1974         @Override
1975         public Object[] toArray() {
1976             return backingSet.toArray();
1977         }
1978 
1979         @Override
1980         public <T> T[] toArray(T[] a) {
1981             return backingSet.toArray(a);
1982         }
1983 
1984         @Override
1985         public boolean add(E e) {
1986             typeCheck(e);
1987             return backingSet.add(e);
1988         }
1989 
1990         @Override
1991         public boolean remove(Object o) {
1992             return backingSet.remove(o);
1993         }
1994 
1995         @Override
1996         public boolean containsAll(Collection<?> c) {
1997             return backingSet.containsAll(c);
1998         }
1999 
2000         @Override
2001         @SuppressWarnings("unchecked")
2002         public boolean addAll(Collection<? extends E> c) {
2003             E[] a = null;
2004             try {
2005                 a = c.toArray((E[]) Array.newInstance(type, 0));
2006             } catch (ArrayStoreException e) {
2007                 throw new ClassCastException();
2008             }
2009 
2010             return backingSet.addAll(Arrays.asList(a));
2011         }
2012 
2013         @Override
2014         public boolean retainAll(Collection<?> c) {
2015             return backingSet.retainAll(c);
2016         }
2017 
2018         @Override
2019         public boolean removeAll(Collection<?> c) {
2020             return backingSet.removeAll(c);
2021         }
2022 
2023         @Override
2024         public void clear() {
2025             backingSet.clear();
2026         }
2027 
2028         @Override
2029         public boolean equals(Object o) {
2030             return o == this || backingSet.equals(o);
2031         }
2032 
2033         @Override
2034         public int hashCode() {
2035             return backingSet.hashCode();
2036         }
2037 
2038         @Override
2039         public Iterator<E> iterator() {
2040             final Iterator<E> it = backingSet.iterator();
2041 
2042             return new Iterator<E>() {
2043                 @Override
2044                 public boolean hasNext() {
2045                     return it.hasNext();
2046                 }
2047 
2048                 @Override
2049                 public E next() {
2050                     return it.next();
2051                 }
2052 
2053                 @Override
2054                 public void remove() {
2055                     it.remove();
2056                 }
2057             };
2058         }
2059 
2060     }
2061 
2062     private static class EmptyObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> {
2063 
2064         public EmptyObservableMap() {
2065         }
2066 
2067         @Override
2068         public void addListener(InvalidationListener listener) {
2069         }
2070 
2071         @Override
2072         public void removeListener(InvalidationListener listener) {
2073         }
2074 
2075         @Override
2076         public void addListener(MapChangeListener<? super K, ? super V> listener) {
2077         }
2078 
2079         @Override
2080         public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2081         }
2082 
2083         @Override
2084         public int size() {
2085             return 0;
2086         }
2087 
2088         @Override
2089         public boolean isEmpty() {
2090             return true;
2091         }
2092 
2093         @Override
2094         public boolean containsKey(Object key) {
2095             return false;
2096         }
2097 
2098         @Override
2099         public boolean containsValue(Object value) {
2100             return false;
2101         }
2102 
2103         @Override
2104         public V get(Object key) {
2105             return null;
2106         }
2107 
2108         @Override
2109         public Set<K> keySet() {
2110             return emptyObservableSet();
2111         }
2112 
2113         @Override
2114         public Collection<V> values() {
2115             return emptyObservableSet();
2116         }
2117 
2118         @Override
2119         public Set<Map.Entry<K,V>> entrySet() {
2120             return emptyObservableSet();
2121         }
2122 
2123         @Override
2124         public boolean equals(Object o) {
2125             return (o instanceof Map) && ((Map<?,?>)o).isEmpty();
2126         }
2127 
2128         @Override
2129         public int hashCode() {
2130             return 0;
2131         }
2132     }
2133 
2134     private static class CheckedObservableMap<K, V> extends AbstractMap<K, V> implements ObservableMap<K, V> {
2135 
2136         private final ObservableMap<K, V> backingMap;
2137         private final Class<K> keyType;
2138         private final Class<V> valueType;
2139         private MapListenerHelper listenerHelper;
2140         private final MapChangeListener<K, V> listener;
2141 
2142         CheckedObservableMap(ObservableMap<K, V> map, Class<K> keyType, Class<V> valueType) {
2143             backingMap = map;
2144             this.keyType = keyType;
2145             this.valueType = valueType;
2146             listener = c -> {
2147                 callObservers(new MapAdapterChange<K, V>(CheckedObservableMap.this, c));
2148             };
2149             backingMap.addListener(new WeakMapChangeListener<K, V>(listener));
2150         }
2151 
2152         private void callObservers(MapChangeListener.Change<? extends K, ? extends V> c) {
2153             MapListenerHelper.fireValueChangedEvent(listenerHelper, c);
2154         }
2155 
2156         void typeCheck(Object key, Object value) {
2157             if (key != null && !keyType.isInstance(key)) {
2158                 throw new ClassCastException("Attempt to insert "
2159                         + key.getClass() + " key into map with key type "
2160                         + keyType);
2161             }
2162 
2163             if (value != null && !valueType.isInstance(value)) {
2164                 throw new ClassCastException("Attempt to insert "
2165                         + value.getClass() + " value into map with value type "
2166                         + valueType);
2167             }
2168         }
2169 
2170         @Override
2171         public void addListener(InvalidationListener listener) {
2172             listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2173         }
2174 
2175         @Override
2176         public void removeListener(InvalidationListener listener) {
2177             listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2178         }
2179 
2180         @Override
2181         public void addListener(MapChangeListener<? super K, ? super V> listener) {
2182             listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2183         }
2184 
2185         @Override
2186         public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2187             listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2188         }
2189 
2190         @Override
2191         public int size() {
2192             return backingMap.size();
2193         }
2194 
2195         @Override
2196         public boolean isEmpty() {
2197             return backingMap.isEmpty();
2198         }
2199 
2200         @Override
2201         public boolean containsKey(Object key) {
2202             return backingMap.containsKey(key);
2203         }
2204 
2205         @Override
2206         public boolean containsValue(Object value) {
2207             return backingMap.containsValue(value);
2208         }
2209 
2210         @Override
2211         public V get(Object key) {
2212             return backingMap.get(key);
2213         }
2214 
2215         @Override
2216         public V put(K key, V value) {
2217             typeCheck(key, value);
2218             return backingMap.put(key, value);
2219         }
2220 
2221         @Override
2222         public V remove(Object key) {
2223             return backingMap.remove(key);
2224         }
2225 
2226         @Override
2227         @SuppressWarnings("unchecked")
2228         public void putAll(Map t) {
2229             // Satisfy the following goals:
2230             // - good diagnostics in case of type mismatch
2231             // - all-or-nothing semantics
2232             // - protection from malicious t
2233             // - correct behavior if t is a concurrent map
2234             Object[] entries = t.entrySet().toArray();
2235             List<Map.Entry<K,V>> checked =
2236                 new ArrayList<Map.Entry<K,V>>(entries.length);
2237             for (Object o : entries) {
2238                 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
2239                 Object k = e.getKey();
2240                 Object v = e.getValue();
2241                 typeCheck(k, v);
2242                 checked.add(
2243                     new AbstractMap.SimpleImmutableEntry<K,V>((K) k, (V) v));
2244             }
2245             for (Map.Entry<K,V> e : checked)
2246                 backingMap.put(e.getKey(), e.getValue());
2247         }
2248 
2249         @Override
2250         public void clear() {
2251             backingMap.clear();
2252         }
2253 
2254         @Override
2255         public Set<K> keySet() {
2256             return backingMap.keySet();
2257         }
2258 
2259         @Override
2260         public Collection<V> values() {
2261             return backingMap.values();
2262         }
2263 
2264         private transient Set<Map.Entry<K,V>> entrySet = null;
2265 
2266         @Override
2267         public Set entrySet() {
2268             if (entrySet==null)
2269                 entrySet = new CheckedEntrySet<K,V>(backingMap.entrySet(), valueType);
2270             return entrySet;
2271         }
2272 
2273         @Override
2274         public boolean equals(Object o) {
2275             return o == this || backingMap.equals(o);
2276         }
2277 
2278         @Override
2279         public int hashCode() {
2280             return backingMap.hashCode();
2281         }
2282 
2283         static class CheckedEntrySet<K,V> implements Set<Map.Entry<K,V>> {
2284             private final Set<Map.Entry<K,V>> s;
2285             private final Class<V> valueType;
2286 
2287             CheckedEntrySet(Set<Map.Entry<K, V>> s, Class<V> valueType) {
2288                 this.s = s;
2289                 this.valueType = valueType;
2290             }
2291 
2292             @Override
2293             public int size() {
2294                 return s.size();
2295             }
2296 
2297             @Override
2298             public boolean isEmpty() {
2299                 return s.isEmpty();
2300             }
2301 
2302             @Override
2303             public String toString() {
2304                 return s.toString();
2305             }
2306 
2307             @Override
2308             public int hashCode() {
2309                 return s.hashCode();
2310             }
2311 
2312             @Override
2313             public void clear() {
2314                 s.clear();
2315             }
2316 
2317             @Override
2318             public boolean add(Map.Entry<K, V> e) {
2319                 throw new UnsupportedOperationException();
2320             }
2321 
2322             @Override
2323             public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
2324                 throw new UnsupportedOperationException();
2325             }
2326 
2327             @Override
2328             public Iterator<Map.Entry<K,V>> iterator() {
2329                 final Iterator<Map.Entry<K, V>> i = s.iterator();
2330                 final Class<V> valueType = this.valueType;
2331 
2332                 return new Iterator<Map.Entry<K,V>>() {
2333                     @Override
2334                     public boolean hasNext() {
2335                         return i.hasNext();
2336                     }
2337 
2338                     @Override
2339                     public void remove() {
2340                         i.remove();
2341                     }
2342 
2343                     @Override
2344                     public Map.Entry<K,V> next() {
2345                         return checkedEntry(i.next(), valueType);
2346                     }
2347                 };
2348             }
2349 
2350             @Override
2351             @SuppressWarnings("unchecked")
2352             public Object[] toArray() {
2353                 Object[] source = s.toArray();
2354 
2355                 /*
2356                  * Ensure that we don't get an ArrayStoreException even if
2357                  * s.toArray returns an array of something other than Object
2358                  */
2359                 Object[] dest = (CheckedEntry.class.isInstance(
2360                     source.getClass().getComponentType()) ? source :
2361                                  new Object[source.length]);
2362 
2363                 for (int i = 0; i < source.length; i++)
2364                     dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
2365                                            valueType);
2366                 return dest;
2367             }
2368 
2369             @Override
2370             @SuppressWarnings("unchecked")
2371             public <T> T[] toArray(T[] a) {
2372                 // We don't pass a to s.toArray, to avoid window of
2373                 // vulnerability wherein an unscrupulous multithreaded client
2374                 // could get his hands on raw (unwrapped) Entries from s.
2375                 T[] arr = s.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));
2376 
2377                 for (int i=0; i<arr.length; i++)
2378                     arr[i] = (T) checkedEntry((Map.Entry<K,V>)arr[i],
2379                                               valueType);
2380                 if (arr.length > a.length)
2381                     return arr;
2382 
2383                 System.arraycopy(arr, 0, a, 0, arr.length);
2384                 if (a.length > arr.length)
2385                     a[arr.length] = null;
2386                 return a;
2387             }
2388 
2389             /**
2390              * This method is overridden to protect the backing set against
2391              * an object with a nefarious equals function that senses
2392              * that the equality-candidate is Map.Entry and calls its
2393              * setValue method.
2394              */
2395             @Override
2396             public boolean contains(Object o) {
2397                 if (!(o instanceof Map.Entry))
2398                     return false;
2399                 Map.Entry<?,?> e = (Map.Entry<?,?>) o;
2400                 return s.contains(
2401                     (e instanceof CheckedEntry) ? e : checkedEntry(e, valueType));
2402             }
2403 
2404             /**
2405              * The bulk collection methods are overridden to protect
2406              * against an unscrupulous collection whose contains(Object o)
2407              * method senses when o is a Map.Entry, and calls o.setValue.
2408              */
2409             @Override
2410             public boolean containsAll(Collection<?> c) {
2411                 for (Object o : c)
2412                     if (!contains(o)) // Invokes safe contains() above
2413                         return false;
2414                 return true;
2415             }
2416 
2417             @Override
2418             public boolean remove(Object o) {
2419                 if (!(o instanceof Map.Entry))
2420                     return false;
2421                 return s.remove(new AbstractMap.SimpleImmutableEntry
2422                                 <Object, Object>((Map.Entry<?,?>)o));
2423             }
2424 
2425             @Override
2426             public boolean removeAll(Collection<?> c) {
2427                 return batchRemove(c, false);
2428             }
2429 
2430             @Override
2431             public boolean retainAll(Collection<?> c) {
2432                 return batchRemove(c, true);
2433             }
2434 
2435             private boolean batchRemove(Collection<?> c, boolean complement) {
2436                 boolean modified = false;
2437                 Iterator<Map.Entry<K,V>> it = iterator();
2438                 while (it.hasNext()) {
2439                     if (c.contains(it.next()) != complement) {
2440                         it.remove();
2441                         modified = true;
2442                     }
2443                 }
2444                 return modified;
2445             }
2446 
2447             @Override
2448             public boolean equals(Object o) {
2449                 if (o == this)
2450                     return true;
2451                 if (!(o instanceof Set))
2452                     return false;
2453                 Set<?> that = (Set<?>) o;
2454                 return that.size() == s.size()
2455                     && containsAll(that); // Invokes safe containsAll() above
2456             }
2457 
2458             static <K,V,T> CheckedEntry<K,V,T> checkedEntry(Map.Entry<K,V> e,
2459                                                             Class<T> valueType) {
2460                 return new CheckedEntry<K,V,T>(e, valueType);
2461             }
2462 
2463             /**
2464              * This "wrapper class" serves two purposes: it prevents
2465              * the client from modifying the backing Map, by short-circuiting
2466              * the setValue method, and it protects the backing Map against
2467              * an ill-behaved Map.Entry that attempts to modify another
2468              * Map.Entry when asked to perform an equality check.
2469              */
2470             private static class CheckedEntry<K,V,T> implements Map.Entry<K,V> {
2471                 private final Map.Entry<K, V> e;
2472                 private final Class<T> valueType;
2473 
2474                 CheckedEntry(Map.Entry<K, V> e, Class<T> valueType) {
2475                     this.e = e;
2476                     this.valueType = valueType;
2477                 }
2478 
2479                 @Override
2480                 public K getKey() {
2481                     return e.getKey();
2482                 }
2483 
2484                 @Override
2485                 public V getValue() {
2486                     return e.getValue();
2487                 }
2488 
2489                 @Override
2490                 public int hashCode() {
2491                     return e.hashCode();
2492                 }
2493 
2494                 @Override
2495                 public String toString() {
2496                     return e.toString();
2497                 }
2498 
2499                 @Override
2500                 public V setValue(V value) {
2501                     if (value != null && !valueType.isInstance(value))
2502                         throw new ClassCastException(badValueMsg(value));
2503                     return e.setValue(value);
2504                 }
2505 
2506                 private String badValueMsg(Object value) {
2507                     return "Attempt to insert " + value.getClass() +
2508                         " value into map with value type " + valueType;
2509                 }
2510 
2511                 @Override
2512                 public boolean equals(Object o) {
2513                     if (o == this)
2514                         return true;
2515                     if (!(o instanceof Map.Entry))
2516                         return false;
2517                     return e.equals(new AbstractMap.SimpleImmutableEntry
2518                                     <Object, Object>((Map.Entry<?,?>)o));
2519                 }
2520             }
2521         }
2522 
2523     }
2524 
2525     private static class SynchronizedMap<K, V> implements Map<K, V> {
2526         final Object mutex;
2527         private final Map<K, V> backingMap;
2528 
2529         SynchronizedMap(Map<K, V> map, Object mutex) {
2530             backingMap = map;
2531             this.mutex = mutex;
2532         }
2533 
2534         SynchronizedMap(Map<K, V> map) {
2535             this(map, new Object());
2536         }
2537 
2538         @Override
2539         public int size() {
2540             synchronized (mutex) {
2541                 return backingMap.size();
2542             }
2543         }
2544 
2545         @Override
2546         public boolean isEmpty() {
2547             synchronized (mutex) {
2548                 return backingMap.isEmpty();
2549             }
2550         }
2551 
2552         @Override
2553         public boolean containsKey(Object key) {
2554             synchronized (mutex) {
2555                 return backingMap.containsKey(key);
2556             }
2557         }
2558 
2559         @Override
2560         public boolean containsValue(Object value) {
2561             synchronized (mutex) {
2562                 return backingMap.containsValue(value);
2563             }
2564         }
2565 
2566         @Override
2567         public V get(Object key) {
2568             synchronized (mutex) {
2569                 return backingMap.get(key);
2570             }
2571         }
2572 
2573         @Override
2574         public V put(K key, V value) {
2575             synchronized (mutex) {
2576                 return backingMap.put(key, value);
2577             }
2578         }
2579 
2580         @Override
2581         public V remove(Object key) {
2582             synchronized (mutex) {
2583                 return backingMap.remove(key);
2584             }
2585         }
2586 
2587         @Override
2588         public void putAll(Map<? extends K, ? extends V> m) {
2589             synchronized (mutex) {
2590                 backingMap.putAll(m);
2591             }
2592         }
2593 
2594         @Override
2595         public void clear() {
2596             synchronized (mutex) {
2597                 backingMap.clear();
2598             }
2599         }
2600 
2601         private transient Set<K> keySet = null;
2602         private transient Set<Map.Entry<K,V>> entrySet = null;
2603         private transient Collection<V> values = null;
2604 
2605         @Override
2606         public Set<K> keySet() {
2607             synchronized(mutex) {
2608                 if (keySet==null)
2609                     keySet = new SynchronizedSet<K>(backingMap.keySet(), mutex);
2610                 return keySet;
2611             }
2612         }
2613 
2614         @Override
2615         public Collection<V> values() {
2616             synchronized(mutex) {
2617                 if (values==null)
2618                     values = new SynchronizedCollection<V>(backingMap.values(), mutex);
2619                 return values;
2620             }
2621         }
2622 
2623         @Override
2624         public Set<Entry<K, V>> entrySet() {
2625             synchronized(mutex) {
2626                 if (entrySet==null)
2627                     entrySet = new SynchronizedSet<Map.Entry<K,V>>(backingMap.entrySet(), mutex);
2628                 return entrySet;
2629             }
2630         }
2631 
2632         @Override
2633         public boolean equals(Object o) {
2634             if (o == this) {
2635                 return true;
2636             }
2637             synchronized(mutex) {
2638                 return backingMap.equals(o);
2639             }
2640         }
2641 
2642         @Override
2643         public int hashCode() {
2644             synchronized(mutex) {
2645                 return backingMap.hashCode();
2646             }
2647         }
2648 
2649     }
2650 
2651     private static class SynchronizedCollection<E> implements Collection<E> {
2652 
2653         private final Collection<E> backingCollection;
2654         final Object mutex;
2655 
2656         SynchronizedCollection(Collection<E> c, Object mutex) {
2657             backingCollection = c;
2658             this.mutex = mutex;
2659         }
2660 
2661         SynchronizedCollection(Collection<E> c) {
2662             this(c, new Object());
2663         }
2664 
2665         @Override
2666         public int size() {
2667             synchronized (mutex) {
2668                 return backingCollection.size();
2669             }
2670         }
2671 
2672         @Override
2673         public boolean isEmpty() {
2674             synchronized (mutex) {
2675                 return backingCollection.isEmpty();
2676             }
2677         }
2678 
2679         @Override
2680         public boolean contains(Object o) {
2681             synchronized (mutex) {
2682                 return backingCollection.contains(o);
2683             }
2684         }
2685 
2686         @Override
2687         public Iterator<E> iterator() {
2688             return backingCollection.iterator();
2689         }
2690 
2691         @Override
2692         public Object[] toArray() {
2693             synchronized (mutex) {
2694                 return backingCollection.toArray();
2695             }
2696         }
2697 
2698         @Override
2699         public <T> T[] toArray(T[] a) {
2700             synchronized (mutex) {
2701                 return backingCollection.toArray(a);
2702             }
2703         }
2704 
2705         @Override
2706         public boolean add(E e) {
2707             synchronized (mutex) {
2708                 return backingCollection.add(e);
2709             }
2710         }
2711 
2712         @Override
2713         public boolean remove(Object o) {
2714             synchronized (mutex) {
2715                 return backingCollection.remove(o);
2716             }
2717         }
2718 
2719         @Override
2720         public boolean containsAll(Collection<?> c) {
2721             synchronized (mutex) {
2722                 return backingCollection.containsAll(c);
2723             }
2724         }
2725 
2726         @Override
2727         public boolean addAll(Collection<? extends E> c) {
2728             synchronized (mutex) {
2729                 return backingCollection.addAll(c);
2730             }
2731         }
2732 
2733         @Override
2734         public boolean removeAll(Collection<?> c) {
2735             synchronized (mutex) {
2736                 return backingCollection.removeAll(c);
2737             }
2738         }
2739 
2740         @Override
2741         public boolean retainAll(Collection<?> c) {
2742             synchronized (mutex) {
2743                 return backingCollection.retainAll(c);
2744             }
2745         }
2746 
2747         @Override
2748         public void clear() {
2749             synchronized (mutex) {
2750                 backingCollection.clear();
2751             }
2752         }
2753     }
2754 
2755     private static class SynchronizedObservableMap<K, V> extends SynchronizedMap<K, V> implements ObservableMap<K, V> {
2756 
2757         private final ObservableMap<K, V> backingMap;
2758         private MapListenerHelper listenerHelper;
2759         private final MapChangeListener<K, V> listener;
2760 
2761         SynchronizedObservableMap(ObservableMap<K, V> map, Object mutex) {
2762             super(map, mutex);
2763             backingMap = map;
2764             listener = c -> {
2765                 MapListenerHelper.fireValueChangedEvent(listenerHelper, new MapAdapterChange<K, V>(SynchronizedObservableMap.this, c));
2766             };
2767             backingMap.addListener(new WeakMapChangeListener<K, V>(listener));
2768         }
2769 
2770         SynchronizedObservableMap(ObservableMap<K, V> map) {
2771             this(map, new Object());
2772         }
2773 
2774         @Override
2775         public void addListener(InvalidationListener listener) {
2776             synchronized (mutex) {
2777                 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2778             }
2779         }
2780 
2781         @Override
2782         public void removeListener(InvalidationListener listener) {
2783             synchronized (mutex) {
2784                 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2785             }
2786         }
2787 
2788         @Override
2789         public void addListener(MapChangeListener<? super K, ? super V> listener) {
2790             synchronized (mutex) {
2791                 listenerHelper = MapListenerHelper.addListener(listenerHelper, listener);
2792             }
2793         }
2794 
2795         @Override
2796         public void removeListener(MapChangeListener<? super K, ? super V> listener) {
2797             synchronized (mutex) {
2798                 listenerHelper = MapListenerHelper.removeListener(listenerHelper, listener);
2799             }
2800         }
2801 
2802     }
2803 
2804 }