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