1 19 20 package org.openide.nodes; 21 22 import java.lang.ref.Reference ; 23 import java.lang.ref.WeakReference ; 24 import java.util.ArrayList ; 25 import java.util.Arrays ; 26 import java.util.Collection ; 27 import java.util.Collections ; 28 import java.util.Comparator ; 29 import java.util.Enumeration ; 30 import java.util.HashMap ; 31 import java.util.HashSet ; 32 import java.util.Iterator ; 33 import java.util.LinkedList ; 34 import java.util.List ; 35 import java.util.Set ; 36 import java.util.TreeSet ; 37 import java.util.logging.Level ; 38 import java.util.logging.Logger ; 39 import org.openide.util.Enumerations; 40 import org.openide.util.Mutex; 41 42 52 public abstract class Children extends Object { 53 56 static final Mutex.Privileged PR = new Mutex.Privileged(); 57 58 68 public static final Mutex MUTEX = new Mutex(PR); 69 70 74 public static final Children LEAF = new Empty(); 75 private static final Object LOCK = new Object (); 76 private static final Logger LOG_GET_ARRAY = Logger.getLogger( 77 "org.openide.nodes.Children.getArray" 78 ); 80 81 private Node parent; 82 83 84 private java.util.Map <Entry,Info> map; 85 86 87 private Collection <? extends Entry> entries = Collections.emptyList(); 88 89 private Reference <ChildrenArray> array = new WeakReference <ChildrenArray>(null); 90 91 99 private Thread initThread; 100 101 114 115 117 public Children() { 118 } 119 120 130 final void attachTo(final Node n) throws IllegalStateException { 131 if (this == LEAF) { 133 return; 136 } 137 138 synchronized (this) { 139 if (parent != null) { 140 throw new IllegalStateException ( 142 "An instance of Children may not be used for more than one parent node." 143 ); } 145 146 parent = n; 148 } 149 150 try { 154 PR.enterReadAccess(); 155 156 Node[] nodes = testNodes(); 157 158 if (nodes == null) { 159 return; 160 } 161 162 for (int i = 0; i < nodes.length; i++) { 164 Node node = nodes[i]; 165 node.assignTo(Children.this, i); 166 node.fireParentNodeChange(null, parent); 167 } 168 } finally { 169 PR.exitReadAccess(); 170 } 171 } 172 173 178 final void detachFrom() { 179 if (this == LEAF) { 181 return; 183 } 184 185 Node oldParent = null; 186 187 synchronized (this) { 188 if (parent == null) { 189 throw new IllegalStateException ("Trying to detach children which do not have parent"); } 192 193 oldParent = parent; 195 196 parent = null; 198 } 199 200 try { 204 PR.enterReadAccess(); 205 206 Node[] nodes = testNodes(); 207 208 if (nodes == null) { 209 return; 210 } 211 212 for (int i = 0; i < nodes.length; i++) { 214 Node node = nodes[i]; 215 node.deassignFrom(Children.this); 216 node.fireParentNodeChange(oldParent, null); 217 } 218 } finally { 219 PR.exitReadAccess(); 220 } 221 } 222 223 226 protected final Node getNode() { 227 return parent; 228 } 229 230 234 final Object cloneHierarchy() throws CloneNotSupportedException { 235 return clone(); 236 } 237 238 247 protected Object clone() throws CloneNotSupportedException { 248 Children ch = (Children) super.clone(); 249 250 ch.parent = null; 251 ch.map = null; 252 ch.entries = Collections.emptyList(); 253 ch.array = new WeakReference <ChildrenArray>(null); 254 255 return ch; 256 } 257 258 273 public abstract boolean add(final Node[] nodes); 274 275 281 public abstract boolean remove(final Node[] nodes); 282 283 286 public final Enumeration <Node> nodes() { 287 return Enumerations.array(getNodes()); 288 } 289 290 301 public Node findChild(String name) { 302 Node[] list = getNodes(); 303 304 if (list.length == 0) { 305 return null; 306 } 307 308 if (name == null) { 309 return list[0]; 311 } 312 313 for (int i = 0; i < list.length; i++) { 314 if (name.equals(list[i].getName())) { 315 return list[i]; 317 } 318 } 319 320 return null; 321 } 322 323 328 protected final boolean isInitialized() { 329 ChildrenArray arr = array.get(); 330 331 return (arr != null) && arr.isInitialized(); 332 } 333 334 337 final Node getNodeAt(int i) { 338 return getNodes()[i]; 339 } 340 341 350 351 public final Node[] getNodes() { 353 boolean[] results = new boolean[2]; 356 357 for (;;) { 358 results[1] = isInitialized(); 359 360 ChildrenArray array = getArray(results); 364 Node[] nodes; 365 366 try { 367 PR.enterReadAccess(); 368 369 nodes = array.nodes(); 370 } finally { 371 PR.exitReadAccess(); 372 } 373 374 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 375 if (IS_LOG_GET_ARRAY) { 376 LOG_GET_ARRAY.fine(" length : " + nodes.length); LOG_GET_ARRAY.fine(" entries : " + entries); LOG_GET_ARRAY.fine(" init now : " + isInitialized()); } 380 if (results[1]) { 385 return nodes; 387 } 388 389 if (results[0]) { 390 return (nodes == null) ? new Node[0] : nodes; 392 } 393 } 394 } 395 396 423 public Node[] getNodes(boolean optimalResult) { 424 ChildrenArray hold; 425 Node find; 426 if (optimalResult) { 427 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 428 if (IS_LOG_GET_ARRAY) { 429 LOG_GET_ARRAY.fine("computing optimal result"); } 431 hold = getArray(null); 432 if (IS_LOG_GET_ARRAY) { 433 LOG_GET_ARRAY.fine("optimal result is here: " + hold); } 435 find = findChild(null); 436 if (IS_LOG_GET_ARRAY) { 437 LOG_GET_ARRAY.fine("Find child got: " + find); } 439 } 440 441 return getNodes(); 442 } 443 444 447 public final int getNodesCount() { 448 return getNodes().length; 449 } 450 451 455 462 protected void addNotify() { 463 } 464 465 471 protected void removeNotify() { 472 } 473 474 477 void callAddNotify() { 478 addNotify(); 479 } 480 481 485 488 private Node[] testNodes() { 489 ChildrenArray arr = array.get(); 490 491 return (arr == null) ? null : arr.nodes(); 492 } 493 494 private ChildrenArray getArray(boolean[] cannotWorkBetter) { 495 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 496 497 ChildrenArray arr; 498 boolean doInitialize = false; 499 synchronized (LOCK) { 500 arr = array.get(); 501 502 if (arr == null) { 503 arr = new ChildrenArray(); 504 505 registerChildrenArray(arr, true); 507 doInitialize = true; 508 initThread = Thread.currentThread(); 509 } 510 } 511 512 if (doInitialize) { 513 if (IS_LOG_GET_ARRAY) { 514 LOG_GET_ARRAY.fine("Initialize " + this + " on " + Thread.currentThread()); } 516 517 try { 520 this.callAddNotify(); 521 522 if (IS_LOG_GET_ARRAY) { 523 LOG_GET_ARRAY.fine("addNotify successfully called for " + this + " on " + Thread.currentThread()); } 525 } finally { 526 boolean notifyLater; 527 notifyLater = MUTEX.isReadAccess(); 528 529 if (IS_LOG_GET_ARRAY) { 530 LOG_GET_ARRAY.fine( 531 "notifyAll for " + this + " on " + Thread.currentThread() + " notifyLater: " + notifyLater 532 ); } 534 535 arr.children = this; 538 class SetAndNotify implements Runnable { 539 public ChildrenArray toSet; 540 public Children whatSet; 541 542 public void run() { 543 synchronized (LOCK) { 544 initThread = null; 545 LOCK.notifyAll(); 546 } 547 548 if (IS_LOG_GET_ARRAY) { 549 LOG_GET_ARRAY.fine( 550 "notifyAll done" 551 ); } 553 554 } 555 } 556 557 SetAndNotify setAndNotify = new SetAndNotify(); 558 setAndNotify.toSet = arr; 559 setAndNotify.whatSet = this; 560 561 if (notifyLater) { 562 MUTEX.postWriteRequest(setAndNotify); 567 } else { 568 setAndNotify.run(); 569 } 570 } 571 } else { 572 if (MUTEX.isReadAccess() || MUTEX.isWriteAccess() || (initThread == Thread.currentThread())) { 575 if (IS_LOG_GET_ARRAY) { 577 LOG_GET_ARRAY.log(Level.FINE, 578 "cannot initialize better " + this + " on " + Thread.currentThread() + " read access: " + MUTEX.isReadAccess() + " initThread: " + initThread, new Exception ("StackTrace") ); 584 } 585 586 if (cannotWorkBetter != null) { 587 cannotWorkBetter[0] = true; 588 } 589 590 return arr; 591 } 592 593 synchronized (LOCK) { 595 while (initThread != null) { 596 if (IS_LOG_GET_ARRAY) { 597 LOG_GET_ARRAY.fine( 598 "waiting for children for " + this + " on " + Thread.currentThread() ); 601 } 602 603 try { 604 LOCK.wait(); 605 } catch (InterruptedException ex) { 606 } 607 } 608 } 609 if (IS_LOG_GET_ARRAY) { 610 LOG_GET_ARRAY.fine( 611 " children are here for " + this + " on " + Thread.currentThread() + " children " + arr.children 614 ); 615 } 616 } 617 618 return arr; 619 } 620 621 623 private void clearNodes() { 624 ChildrenArray arr = array.get(); 625 626 if (arr != null) { 628 arr.clear(); 630 } 631 } 632 633 636 final void finalizeNodes() { 637 ChildrenArray arr = array.get(); 638 639 if (arr != null) { 640 arr.finalizeNodes(); 641 } 642 } 643 644 648 final void registerChildrenArray(final ChildrenArray chArr, boolean weak) { 649 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 650 if (IS_LOG_GET_ARRAY) { 651 LOG_GET_ARRAY.fine("registerChildrenArray: " + chArr + " weak: " + weak); } 653 if (weak) { 654 this.array = new WeakReference <ChildrenArray>(chArr); 655 } else { 656 this.array = new WeakReference <ChildrenArray>(chArr) { 658 @Override 659 public ChildrenArray get() { 660 return chArr; 661 } 662 }; 663 } 664 665 chArr.pointedBy(this.array); 666 if (IS_LOG_GET_ARRAY) { 667 LOG_GET_ARRAY.fine("pointed by: " + chArr + " to: " + this.array); } 669 } 670 671 673 final void finalizedChildrenArray(Reference caller) { 674 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 675 try { 677 PR.enterWriteAccess(); 678 679 if (IS_LOG_GET_ARRAY) { 680 LOG_GET_ARRAY.fine("previous array: " + array + " caller: " + caller); 681 } 682 if (array == caller) { 683 removeNotify(); 685 } 686 687 692 } finally { 693 PR.exitWriteAccess(); 694 } 695 } 696 697 699 final Node[] justComputeNodes() { 700 if (map == null) { 701 map = Collections.synchronizedMap(new HashMap <Entry,Info>(17)); 702 703 } 706 707 List <Node> l = new LinkedList <Node>(); 708 for (Entry entry : entries) { 709 Info info = findInfo(entry); 710 711 try { 712 l.addAll(info.nodes()); 713 } catch (RuntimeException ex) { 714 NodeOp.warning(ex); 715 } 716 } 717 718 Node[] arr = l.toArray(new Node[l.size()]); 719 720 for (int i = 0; i < arr.length; i++) { 722 Node n = arr[i]; 723 n.assignTo(this, i); 724 n.fireParentNodeChange(null, parent); 725 } 726 727 return arr; 728 } 729 730 733 private Info findInfo(Entry entry) { 734 synchronized(map) { 735 Info info = map.get(entry); 736 737 if (info == null) { 738 info = new Info(entry); 739 map.put(entry, info); 740 741 } 745 return info; 746 } 747 } 748 749 753 756 final List <Entry> getEntries() { 757 return new ArrayList <Entry>(this.entries); 758 } 759 760 final void setEntries(Collection <? extends Entry> entries) { 761 final boolean IS_LOG_GET_ARRAY = LOG_GET_ARRAY.isLoggable(Level.FINE); 762 ChildrenArray holder = array.get(); 764 765 if (IS_LOG_GET_ARRAY) { 766 LOG_GET_ARRAY.fine("setEntries for " + this + " on " + Thread.currentThread()); LOG_GET_ARRAY.fine(" values: " + entries); LOG_GET_ARRAY.fine(" holder: " + holder); } 770 if (holder == null) { 771 this.entries = entries; 774 775 if (map != null) { 776 map.keySet().retainAll(new HashSet <Entry>(entries)); 777 } 778 779 return; 780 } 781 782 Node[] current = holder.nodes(); 783 784 if (current == null) { 785 this.entries = entries; 789 790 if (map != null) { 791 map.keySet().retainAll(new HashSet <Entry>(entries)); 792 } 793 794 return; 795 } 796 797 map.keySet().retainAll(new HashSet <Entry>(this.entries)); 800 801 Set <Entry> toRemove = new HashSet <Entry>(map.keySet()); 803 Set <Entry> entriesSet = new HashSet <Entry>(entries); 804 toRemove.removeAll(entriesSet); 805 806 if (!toRemove.isEmpty()) { 807 updateRemove(current, toRemove); 810 current = holder.nodes(); 811 } 812 813 Collection <Info> toAdd = updateOrder(current, entries); 816 817 if (!toAdd.isEmpty()) { 818 updateAdd(toAdd, entries); 821 } 822 } 823 824 private void checkInfo(Info info, Entry entry, Collection <? extends Entry> entries, java.util.Map <Entry,Info> map) { 825 if (info == null) { 826 throw new IllegalStateException ( 827 "Error in " + getClass().getName() + " with entry " + entry + " from among " + entries + " in " + map + " probably caused by faulty key implementation." + " The key hashCode() and equals() methods must behave as for an IMMUTABLE object" + " and the hashCode() must return the same value for equals() keys." 831 ); } 833 } 834 835 837 private void updateRemove(Node[] current, Set <Entry> toRemove) { 838 List <Node> nodes = new LinkedList <Node>(); 839 840 for (Entry en : toRemove) { 841 Info info = map.remove(en); 842 843 checkInfo(info, en, null, map); 847 848 nodes.addAll(info.nodes()); 849 } 850 851 this.entries.removeAll(toRemove); 855 856 clearNodes(); 860 861 notifyRemove(nodes, current); 862 } 863 864 873 Node[] notifyRemove(Collection <Node> nodes, Node[] current) { 874 Node[] arr = nodes.toArray(new Node[nodes.size()]); 883 884 if (parent == null) { 885 return arr; 886 } 887 888 parent.fireSubNodesChange(false, arr, current 891 ); 892 893 Iterator it = nodes.iterator(); 895 896 while (it.hasNext()) { 897 Node n = (Node) it.next(); 898 n.deassignFrom(this); 899 n.fireParentNodeChange(parent, null); 900 } 901 902 return arr; 903 } 904 905 910 private List <Info> updateOrder(Node[] current, Collection <? extends Entry> newEntries) { 911 List <Info> toAdd = new LinkedList <Info>(); 912 913 java.util.Map <Info,Integer > offsets = new HashMap <Info,Integer >(); 916 917 { 918 int previousPos = 0; 919 920 for (Entry entry : entries) { 921 Info info = map.get(entry); 922 checkInfo(info, entry, entries, map); 923 924 offsets.put(info, previousPos); 925 926 previousPos += info.length(); 927 } 928 } 929 930 map.keySet().retainAll(new HashSet <Entry>(entries)); 935 936 int[] perm = new int[current.length]; 937 int currentPos = 0; 938 int permSize = 0; 939 List <Entry> reorderedEntries = null; 940 941 for (Entry entry : newEntries) { 942 Info info = map.get(entry); 943 944 if (info == null) { 945 info = new Info(entry); 947 toAdd.add(info); 948 } else { 949 int len = info.length(); 950 951 if (reorderedEntries == null) { 952 reorderedEntries = new LinkedList <Entry>(); 953 } 954 955 reorderedEntries.add(entry); 956 957 Integer previousInt = offsets.get(info); 959 960 975 int previousPos = previousInt; 976 977 if (currentPos != previousPos) { 978 for (int i = 0; i < len; i++) { 979 perm[previousPos + i] = 1 + currentPos + i; 980 } 981 982 permSize += len; 983 } 984 } 985 986 currentPos += info.length(); 987 } 988 989 if (permSize > 0) { 990 for (int i = 0; i < perm.length; i++) { 994 if (perm[i] == 0) { 995 perm[i] = i; 997 } else { 998 perm[i]--; 1000 } 1001 } 1002 1003 this.entries = reorderedEntries; 1005 1006 clearNodes(); 1010 1011 Node p = parent; 1013 1014 if (p != null) { 1015 p.fireReorderChange(perm); 1016 } 1017 } 1018 1019 return toAdd; 1020 } 1021 1022 1026 private void updateAdd(Collection <Info> infos, Collection <? extends Entry> entries) { 1027 List <Node> nodes = new LinkedList <Node>(); 1028 for (Info info : infos) { 1029 nodes.addAll(info.nodes()); 1030 map.put(info.entry, info); 1031 1032 } 1035 1036 this.entries = entries; 1037 1038 clearNodes(); 1041 1042 notifyAdd(nodes); 1043 } 1044 1045 1052 private void notifyAdd(Collection <Node> nodes) { 1053 for (Node n : nodes) { 1055 n.assignTo(this, -1); 1056 n.fireParentNodeChange(null, parent); 1057 } 1058 1059 Node[] arr = nodes.toArray(new Node[nodes.size()]); 1060 1061 Node n = parent; 1062 1063 if (n != null) { 1064 n.fireSubNodesChange(true, arr, null); 1065 } 1066 } 1067 1068 1071 final void refreshEntry(Entry entry) { 1072 ChildrenArray holder = array.get(); 1074 1075 if (holder == null) { 1076 return; 1077 } 1078 1079 Node[] current = holder.nodes(); 1080 1081 if (current == null) { 1082 return; 1084 } 1085 1086 map.keySet().retainAll(new HashSet <Entry>(this.entries)); 1091 1092 Info info = map.get(entry); 1093 1094 if (info == null) { 1095 return; 1097 } 1098 1099 Collection <Node> oldNodes = info.nodes(); 1100 Collection <Node> newNodes = info.entry.nodes(); 1101 1102 if (oldNodes.equals(newNodes)) { 1103 return; 1105 } 1106 1107 Set <Node> toRemove = new HashSet <Node>(oldNodes); 1108 toRemove.removeAll(newNodes); 1109 1110 if (!toRemove.isEmpty()) { 1111 oldNodes.removeAll(toRemove); 1115 clearNodes(); 1116 1117 notifyRemove(toRemove, current); 1119 1120 current = holder.nodes(); 1121 } 1122 1123 List <Node> toAdd = refreshOrder(entry, oldNodes, newNodes); 1124 info.useNodes(newNodes); 1125 1126 if (!toAdd.isEmpty()) { 1127 clearNodes(); 1129 notifyAdd(toAdd); 1130 } 1131 } 1132 1133 1139 private List <Node> refreshOrder(Entry entry, Collection <Node> oldNodes, Collection <Node> newNodes) { 1140 List <Node> toAdd = new LinkedList <Node>(); 1141 1142 int currentPos = 0; 1143 1144 Iterator <? extends Entry> it1 = this.entries.iterator(); 1146 1147 for (;;) { 1148 Entry e = it1.next(); 1149 1150 if (e.equals(entry)) { 1151 break; 1152 } 1153 1154 Info info = findInfo(e); 1155 currentPos += info.length(); 1156 } 1157 1158 Set <Node> oldNodesSet = new HashSet <Node>(oldNodes); 1159 Set <Node> toProcess = new HashSet <Node>(oldNodesSet); 1160 1161 Node[] permArray = new Node[oldNodes.size()]; 1162 Iterator <Node> it2 = newNodes.iterator(); 1163 1164 int pos = 0; 1165 1166 while (it2.hasNext()) { 1167 Node n = it2.next(); 1168 1169 if (oldNodesSet.remove(n)) { 1170 permArray[pos++] = n; 1172 } else { 1173 if (!toProcess.contains(n)) { 1174 toAdd.add(n); 1176 } else { 1177 it2.remove(); 1178 } 1179 } 1180 } 1181 1182 int[] perm = NodeOp.computePermutation(oldNodes.toArray(new Node[oldNodes.size()]), permArray); 1186 1187 if (perm != null) { 1188 clearNodes(); 1190 1191 findInfo(entry).useNodes(Arrays.asList(permArray)); 1193 1194 Node p = parent; 1195 1196 if (p != null) { 1197 p.fireReorderChange(perm); 1198 } 1199 } 1200 1201 return toAdd; 1202 } 1203 1204 1206 static interface Entry { 1207 1209 public Collection <Node> nodes(); 1210 } 1211 1212 1215 final class Info extends Object { 1216 int length; 1217 final Entry entry; 1218 1219 public Info(Entry entry) { 1220 this.entry = entry; 1221 } 1222 1223 1225 protected void finalize() { 1226 finalizeNodes(); 1227 } 1228 1229 public Collection <Node> nodes() { 1230 ChildrenArray arr = getArray(null); 1232 1233 return arr.nodesFor(this); 1234 } 1235 1236 public void useNodes(Collection <Node> nodes) { 1237 ChildrenArray arr = getArray(null); 1239 1240 arr.useNodes(this, nodes); 1241 1242 for (Node n : nodes) { 1244 n.assignTo(Children.this, -1); 1245 n.fireParentNodeChange(null, parent); 1246 } 1247 } 1248 1249 public int length() { 1250 return length; 1251 } 1252 1253 @Override 1254 public String toString() { 1255 return "Children.Info[" + entry + ",length=" + length + "]"; } 1257 } 1258 1259 1262 private static final class Empty extends Children { 1263 Empty() { 1264 } 1265 1266 1267 public boolean add(Node[] nodes) { 1268 return false; 1269 } 1270 1271 1272 public boolean remove(Node[] nodes) { 1273 return false; 1274 } 1275 } 1276 1277 1286 public static class Array extends Children implements Cloneable { 1287 1293 private Entry nodesEntry; 1294 1295 1296 protected Collection <Node> nodes; 1297 1298 1305 protected Array(Collection <Node> c) { 1306 this(); 1307 nodes = c; 1308 } 1309 1310 1314 public Array() { 1315 nodesEntry = createNodesEntry(); 1316 this.setEntries(Collections.singleton(getNodesEntry())); 1317 } 1318 1319 1323 public Object clone() { 1324 try { 1325 final Children.Array ar = (Array) super.clone(); 1326 1327 try { 1328 PR.enterReadAccess(); 1329 1330 if (nodes != null) { 1331 ar.nodes = ar.initCollection(); 1339 ar.nodes.clear(); 1340 1341 for (Node n : nodes) { 1343 ar.nodes.add(n.cloneNode()); 1344 } 1345 } 1346 } finally { 1347 PR.exitReadAccess(); 1348 } 1349 1350 return ar; 1351 } catch (CloneNotSupportedException e) { 1352 throw new InternalError (); 1354 } 1355 } 1356 1357 1365 protected Collection <Node> initCollection() { 1366 return new ArrayList <Node>(); 1367 } 1368 1369 1375 final void refreshImpl() { 1376 if (isInitialized()) { 1377 Array.this.refreshEntry(getNodesEntry()); 1378 super.getArray(null).nodes(); 1379 } else if (nodes != null) { 1380 for (Node n : nodes) { 1381 n.assignTo(this, -1); 1382 } 1383 } 1384 } 1385 1386 1390 protected final void refresh() { 1391 MUTEX.postWriteRequest(new Runnable () { 1392 public void run() { 1393 refreshImpl(); 1394 } 1395 } 1396 ); 1397 } 1398 1399 1401 final Entry getNodesEntry() { 1402 return nodesEntry; 1403 } 1404 1405 1408 Entry createNodesEntry() { 1409 return new AE(); 1410 } 1411 1412 1414 final Collection <Node> getCollection() { 1415 synchronized (getNodesEntry()) { 1416 if (nodes == null) { 1417 nodes = initCollection(); 1418 } 1419 } 1420 1421 return nodes; 1422 } 1423 1424 1428 public boolean add(final Node[] arr) { 1429 synchronized (getNodesEntry()) { 1430 if (!getCollection().addAll(Arrays.asList(arr))) { 1431 return false; 1433 } 1434 1435 ; 1436 } 1437 1438 refresh(); 1439 1440 return true; 1441 } 1442 1443 1447 public boolean remove(final Node[] arr) { 1448 synchronized (getNodesEntry()) { 1449 if (!getCollection().removeAll(Arrays.asList(arr))) { 1450 return false; 1452 } 1453 } 1454 1455 refresh(); 1456 1457 return true; 1458 } 1459 1460 1463 private final class AE extends Object implements Entry { 1464 AE() { 1465 } 1466 1467 1469 public Collection <Node> nodes() { 1470 Collection <Node> c = getCollection(); 1471 1472 if (c.isEmpty()) { 1473 return Collections.emptyList(); 1474 } else { 1475 return new ArrayList <Node>(c); 1476 } 1477 } 1478 1479 @Override 1480 public String toString() { 1481 return "Children.Array.AE" + getCollection(); } 1483 1484 } 1485 } 1486 1487 1494 public static class Map<T> extends Children { 1495 1499 protected java.util.Map <T,Node> nodes; 1500 1501 1507 protected Map(java.util.Map <T,Node> m) { 1508 nodes = m; 1509 } 1510 1511 1513 public Map() { 1514 } 1515 1516 1519 final java.util.Map <T,Node> getMap() { 1520 if (nodes == null) { 1522 nodes = initMap(); 1523 } 1524 1525 return nodes; 1526 } 1527 1528 1530 final void callAddNotify() { 1531 this.setEntries(createEntries(getMap())); 1532 1533 super.callAddNotify(); 1534 } 1535 1536 1541 Collection <? extends Entry> createEntries(java.util.Map <T,Node> map) { 1542 List <ME> l = new LinkedList <ME>(); 1543 for (java.util.Map.Entry<T,Node> e : map.entrySet()) { 1544 l.add(new ME(e.getKey(), e.getValue())); 1545 } 1546 return l; 1547 } 1548 1549 1554 final void refreshImpl() { 1555 this.setEntries(createEntries(getMap())); 1556 } 1557 1558 1561 protected final void refresh() { 1562 try { 1563 PR.enterWriteAccess(); 1564 refreshImpl(); 1565 } finally { 1566 PR.exitWriteAccess(); 1567 } 1568 } 1569 1570 1577 final void refreshKeyImpl(T key) { 1578 this.refreshEntry(new ME(key, null)); 1579 } 1580 1581 1586 protected final void refreshKey(final T key) { 1587 try { 1588 PR.enterWriteAccess(); 1589 refreshKeyImpl(key); 1590 } finally { 1591 PR.exitWriteAccess(); 1592 } 1593 } 1594 1595 1600 protected final void putAll(final java.util.Map <? extends T,? extends Node> map) { 1601 try { 1602 PR.enterWriteAccess(); 1603 nodes.putAll(map); 1604 refreshImpl(); 1605 1606 } finally { 1608 PR.exitWriteAccess(); 1609 } 1610 } 1611 1612 1616 protected final void put(final T key, final Node node) { 1617 try { 1618 PR.enterWriteAccess(); 1619 1620 if (nodes.put(key, node) != null) { 1621 refreshKeyImpl(key); 1622 } else { 1623 refreshImpl(); 1624 } 1625 } finally { 1626 PR.exitWriteAccess(); 1627 } 1628 } 1629 1630 1633 protected final void removeAll(final Collection <? extends T> keys) { 1634 try { 1635 PR.enterWriteAccess(); 1636 nodes.keySet().removeAll(keys); 1637 refreshImpl(); 1638 } finally { 1639 PR.exitWriteAccess(); 1640 } 1641 } 1642 1643 1646 protected void remove(final T key) { 1647 try { 1648 PR.enterWriteAccess(); 1649 1650 if (nodes.remove(key) != null) { 1651 refreshImpl(); 1652 } 1653 } finally { 1654 PR.exitWriteAccess(); 1655 } 1656 } 1657 1658 1667 protected java.util.Map <T,Node> initMap() { 1668 return new HashMap <T,Node>(7); 1669 } 1670 1671 1677 public boolean add(Node[] arr) { 1678 return false; 1679 } 1680 1681 1686 public boolean remove(Node[] arr) { 1687 return false; 1688 } 1689 1690 1692 final static class ME extends Object implements Entry { 1693 1694 public Object key; 1695 1696 1697 public Node node; 1698 1699 1701 public ME(Object key, Node node) { 1702 this.key = key; 1703 this.node = node; 1704 } 1705 1706 1707 public Collection <Node> nodes() { 1708 return Collections.singleton(node); 1709 } 1710 1711 1713 public int hashCode() { 1714 return key.hashCode(); 1715 } 1716 1717 1719 public boolean equals(Object o) { 1720 if (o instanceof ME) { 1721 ME me = (ME) o; 1722 1723 return key.equals(me.key); 1724 } 1725 1726 return false; 1727 } 1728 1729 public String toString() { 1730 return "Key (" + key + ")"; } 1732 } 1733 } 1734 1735 1739 public static class SortedArray extends Children.Array { 1740 1741 private Comparator <? super Node> comp; 1742 1743 1744 public SortedArray() { 1745 } 1746 1747 1752 protected SortedArray(Collection <Node> c) { 1753 super(c); 1754 } 1755 1756 1763 public void setComparator(final Comparator <? super Node> c) { 1764 try { 1765 PR.enterWriteAccess(); 1766 comp = c; 1767 refresh(); 1768 } finally { 1769 PR.exitWriteAccess(); 1770 } 1771 } 1772 1773 1776 public Comparator <? super Node> getComparator() { 1777 return comp; 1778 } 1779 1780 1783 Entry createNodesEntry() { 1784 return new SAE(); 1785 } 1786 1787 1790 private final class SAE extends Object implements Entry { 1791 1793 public SAE() { 1794 } 1795 1796 1798 public Collection <Node> nodes() { 1799 List <Node> al = new ArrayList <Node>(getCollection()); 1800 Collections.sort(al, comp); 1801 1802 return al; 1803 } 1804 } 1805 } 1806 1808 1811 public static class SortedMap<T> extends Children.Map<T> { 1812 1813 private Comparator <? super Node> comp; 1814 1815 1816 public SortedMap() { 1817 } 1818 1819 1824 protected SortedMap(java.util.Map <T,Node> map) { 1825 super(map); 1826 } 1827 1828 1835 public void setComparator(final Comparator <? super Node> c) { 1836 try { 1837 PR.enterWriteAccess(); 1838 comp = c; 1839 refresh(); 1840 } finally { 1841 PR.exitWriteAccess(); 1842 } 1843 } 1844 1845 1848 public Comparator <? super Node> getComparator() { 1849 return comp; 1850 } 1851 1852 1857 Collection <? extends Entry> createEntries(java.util.Map <T,Node> map) { 1858 Set <ME> l = new TreeSet <ME>(new SMComparator()); 1860 1861 for (java.util.Map.Entry<T,Node> e : map.entrySet()) { 1862 l.add(new ME(e.getKey(), e.getValue())); 1863 } 1864 1865 return l; 1866 } 1867 1868 1870 final class SMComparator implements Comparator <ME> { 1871 public int compare(ME me1, ME me2) { 1872 Comparator <? super Node> c = comp; 1873 1874 if (c == null) { 1875 @SuppressWarnings ("unchecked") int r = ((Comparable ) me1.key).compareTo(me2.key); 1878 return r; 1879 } else { 1880 return c.compare(me1.node, me2.node); 1881 } 1882 } 1883 } 1884 } 1885 1887 1918 public static abstract class Keys<T> extends Children.Array { 1919 1921 private static java.util.Map <Keys<?>,Runnable > lastRuns = new HashMap <Keys<?>,Runnable >(11); 1922 1923 1924 private boolean before; 1925 1926 public Keys() { 1927 super(); 1928 } 1929 1930 1932 public Object clone() { 1933 Keys<?> k = (Keys<?>) super.clone(); 1934 1935 return k; 1936 } 1937 1938 1941 @Deprecated 1942 public boolean add(Node[] arr) { 1943 return super.add(arr); 1944 } 1945 1946 1949 @Deprecated 1950 public boolean remove(final Node[] arr) { 1951 try { 1952 PR.enterWriteAccess(); 1953 1954 if (nodes != null) { 1955 for (int i = 0; i < arr.length; i++) { 1959 if (!nodes.contains(arr[i])) { 1960 arr[i] = null; 1961 } 1962 } 1963 1964 super.remove(arr); 1965 } 1966 } finally { 1967 PR.exitWriteAccess(); 1968 } 1969 1970 return true; 1971 } 1972 1973 1977 protected final void refreshKey(final T key) { 1978 MUTEX.postWriteRequest( 1979 new Runnable () { 1980 public void run() { 1981 Keys.this.refreshEntry(new KE(key)); 1982 } 1983 } 1984 ); 1985 } 1986 1987 1993 protected final void setKeys(Collection <? extends T> keysSet) { 1994 boolean asserts = false; 1995 assert asserts = true; 1996 int sz = keysSet.size(); 1997 if (asserts && sz < 10) { 1998 List <? extends T> keys = new ArrayList <T>(keysSet); 1999 for (int i = 0; i < sz - 1; i++) { 2000 T a = keys.get(i); 2001 for (int j = i + 1; j < sz; j++) { 2002 T b = keys.get(j); 2003 assert !(a.equals(b) && a.hashCode() != b.hashCode()) : "bad equals/hashCode in " + a + " vs. " + b; 2004 } 2005 } 2006 } 2007 2008 final List <Entry> l = new ArrayList <Entry>(keysSet.size() + 1); 2009 2010 if (before) { 2011 l.add(getNodesEntry()); 2012 } 2013 2014 KE updator = new KE(); 2015 updator.updateList(keysSet, l); 2016 2017 if (!before) { 2018 l.add(getNodesEntry()); 2019 } 2020 2021 applyKeys(l); 2022 } 2023 2024 2029 protected final void setKeys(final T[] keys) { 2030 boolean asserts = false; 2031 assert asserts = true; 2032 int sz = keys.length; 2033 if (asserts && sz < 10) { 2034 for (int i = 0; i < sz - 1; i++) { 2035 T a = keys[i]; 2036 for (int j = i + 1; j < sz; j++) { 2037 T b = keys[j]; 2038 assert !(a.equals(b) && a.hashCode() != b.hashCode()) : "bad equals/hashCode in " + a + " vs. " + b; 2039 } 2040 } 2041 } 2042 2043 final List <Entry> l = new ArrayList <Entry>(keys.length + 1); 2044 2045 KE updator = new KE(); 2046 2047 if (before) { 2048 l.add(getNodesEntry()); 2049 } 2050 2051 updator.updateList(keys, l); 2052 2053 if (!before) { 2054 l.add(getNodesEntry()); 2055 } 2056 2057 applyKeys(l); 2058 } 2059 2060 2062 private void applyKeys(final List <? extends Entry> l) { 2063 Runnable invoke = new Runnable () { 2064 public void run() { 2065 if (keysCheck(Keys.this, this)) { 2066 Keys.this.setEntries(l); 2068 2069 keysExit(Keys.this, this); 2071 } 2072 } 2073 }; 2074 2075 keysEnter(this, invoke); 2076 MUTEX.postWriteRequest(invoke); 2077 } 2078 2079 2083 protected final void setBefore(final boolean b) { 2084 try { 2085 PR.enterWriteAccess(); 2086 2087 if (before != b) { 2088 List <Entry> l = Keys.this.getEntries(); 2089 l.remove(getNodesEntry()); 2090 before = b; 2091 2092 if (b) { 2093 l.add(0, getNodesEntry()); 2094 } else { 2095 l.add(getNodesEntry()); 2096 } 2097 2098 Keys.this.setEntries(l); 2099 } 2100 } finally { 2101 PR.exitWriteAccess(); 2102 } 2103 } 2104 2105 2110 protected abstract Node[] createNodes(T key); 2111 2112 2120 protected void destroyNodes(Node[] arr) { 2121 for (int i = 0; i < arr.length; i++) { 2122 arr[i].fireNodeDestroyed(); 2123 } 2124 } 2125 2126 2128 Node[] notifyRemove(Collection <Node> nodes, Node[] current) { 2129 Node[] arr = super.notifyRemove(nodes, current); 2130 destroyNodes(arr); 2131 2132 return arr; 2133 } 2134 2135 2139 private static synchronized void keysEnter(Keys<?> ch, Runnable run) { 2140 lastRuns.put(ch, run); 2141 } 2142 2143 2146 private static synchronized void keysExit(Keys ch, Runnable r) { 2147 Runnable reg = lastRuns.remove(ch); 2148 2149 if ((reg != null) && !reg.equals(r)) { 2150 lastRuns.put(ch, reg); 2151 } 2152 } 2153 2154 2159 private static synchronized boolean keysCheck(Keys ch, Runnable run) { 2160 return run == lastRuns.get(ch); 2161 } 2162 2163 2165 private final class KE extends Dupl<T> { 2166 2169 public KE() { 2170 } 2171 2172 2174 public KE(T key) { 2175 this.key = key; 2176 } 2177 2178 2180 public Collection <Node> nodes() { 2181 Node[] arr = createNodes(getKey()); 2182 2183 if (arr == null) { 2184 return Collections.emptyList(); 2185 } else { 2186 return new LinkedList <Node>(Arrays.asList(arr)); 2187 } 2188 } 2189 2190 @Override 2191 public String toString() { 2192 String s = getKey().toString(); 2193 if (s.length() > 80) { 2194 s = s.substring(0, 80); 2195 } 2196 return "Children.Keys.KE[" + s + "," + getCnt() + "]"; } 2198 } 2199 } 2200 2202 2209 private static abstract class Dupl<T> implements Cloneable , Entry { 2210 2211 protected Object key; 2212 2213 Dupl() { 2214 } 2215 2216 2220 public final void updateList(Collection <? extends T> src, Collection <? super Dupl<T>> target) { 2221 java.util.Map <T,Object > map = new HashMap <T,Object >(src.size() * 2); 2222 for (T o : src) { 2223 updateListAndMap(o, target, map); 2224 } 2225 } 2226 2227 2231 public final void updateList(T[] arr, Collection <? super Dupl<T>> target) { 2232 java.util.Map <T,Object > map = new HashMap <T,Object >(arr.length * 2); 2233 for (T o : arr) { 2234 updateListAndMap(o, target, map); 2235 } 2236 } 2237 2238 2246 public final void updateListAndMap(T obj, Collection <? super Dupl<T>> list, java.util.Map <T,Object > map) { 2247 Object prev = map.put(obj, this); 2250 2251 if (prev == null) { 2252 list.add(createInstance(obj, 0)); 2254 2255 return; 2256 } else { 2257 if (prev == this) { 2258 map.put(obj, 1); 2260 list.add(createInstance(obj, 1)); 2261 2262 return; 2263 } else { 2264 int cnt = ((Integer ) prev) + 1; 2265 map.put(obj, cnt); 2266 list.add(createInstance(obj, cnt)); 2267 2268 return; 2269 } 2270 } 2271 } 2272 2273 2276 @SuppressWarnings ("unchecked") public final T getKey() { 2278 if (key instanceof Dupl) { 2279 return (T) ((Dupl) key).getKey(); 2280 } else { 2281 return (T) key; 2282 } 2283 } 2284 2285 2288 public final int getCnt() { 2289 int cnt = 0; 2290 Dupl d = this; 2291 2292 while (d.key instanceof Dupl) { 2293 d = (Dupl) d.key; 2294 cnt++; 2295 } 2296 2297 return cnt; 2298 } 2299 2300 2302 @SuppressWarnings ("unchecked") private final Dupl<T> createInstance(Object obj, int cnt) { 2304 try { 2305 Dupl d = (Dupl) this.clone(); 2309 Dupl first = d; 2310 2311 while (cnt-- > 0) { 2312 Dupl n = (Dupl) this.clone(); 2313 d.key = n; 2314 d = n; 2315 } 2316 2317 d.key = obj; 2318 2319 return first; 2320 } catch (CloneNotSupportedException ex) { 2321 throw new InternalError (); 2322 } 2323 } 2324 2325 @Override 2326 public int hashCode() { 2327 return getKey().hashCode(); 2328 } 2329 2330 @Override 2331 public boolean equals(Object o) { 2332 if (o instanceof Dupl) { 2333 Dupl d = (Dupl) o; 2334 2335 return getKey().equals(d.getKey()) && (getCnt() == d.getCnt()); 2336 } 2337 2338 return false; 2339 } 2340 } 2341 2342 2349 2367} 2368 | Popular Tags |