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