1 19 package org.openide.util.lookup; 20 21 import org.openide.util.Enumerations; 22 import org.openide.util.Lookup; 23 import org.openide.util.lookup.AbstractLookup.Pair; 24 import org.openide.util.lookup.AbstractLookup.ReferenceIterator; 25 import org.openide.util.lookup.AbstractLookup.ReferenceToResult; 26 27 import java.io.*; 28 29 import java.lang.ref.WeakReference ; 30 31 import java.util.*; 32 33 34 98 final class InheritanceTree extends Object 99 implements Serializable, AbstractLookup.Storage<ArrayList<Class >> { 100 private static final long serialVersionUID = 1L; 101 102 103 private transient Node object; 104 105 108 private transient Map<Class ,Object > interfaces; 109 110 113 private transient Map<Class ,ReferenceToResult> reg; 114 115 117 public InheritanceTree() { 118 object = new Node(java.lang.Object .class); 119 } 120 121 private void writeObject(ObjectOutputStream oos) throws IOException { 122 oos.writeObject(object); 123 124 if (interfaces != null) { 125 Iterator it = interfaces.entrySet().iterator(); 126 127 while (it.hasNext()) { 128 Map.Entry e = (Map.Entry) it.next(); 129 Class c = (Class ) e.getKey(); 130 oos.writeObject(c.getName()); 131 132 Object o = e.getValue(); 133 134 if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) { 135 throw new ClassCastException (String.valueOf(o)); 136 } 137 138 oos.writeObject(o); 139 } 140 } 141 142 oos.writeObject(null); 143 } 144 145 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 146 object = (Node) ois.readObject(); 147 interfaces = new WeakHashMap<Class ,Object >(); 148 149 String clazz; 150 ClassLoader l = Lookup.getDefault().lookup(ClassLoader .class); 151 152 while ((clazz = (String ) ois.readObject()) != null) { 153 Object o = ois.readObject(); 154 155 if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) { 156 throw new ClassCastException (String.valueOf(o)); 157 } 158 159 Class c = Class.forName(clazz, false, l); 160 interfaces.put(c, o); 161 } 162 } 163 164 169 public boolean add(AbstractLookup.Pair<?> item, ArrayList<Class > affected) { 170 Node node = registerClass(object, item); 171 172 affected.add(node.getType()); 173 174 if (node.assignItem(this, item)) { 175 } else { 178 return false; 180 } 181 182 boolean registeredAsInterface = registerInterface(item, affected); 183 184 return registeredAsInterface; 185 } 186 187 189 public void remove(AbstractLookup.Pair item, ArrayList<Class > affected) { 190 Node n = removeClass(object, item); 191 192 if (n != null) { 193 affected.add(n.getType()); 194 } 195 196 removeInterface(item, affected); 197 } 198 199 203 public void retainAll(Map retain, ArrayList<Class > notify) { 204 retainAllInterface(retain, notify); 205 retainAllClasses(object, retain, notify); 206 } 207 208 213 @SuppressWarnings ("unchecked") 214 public <T> Enumeration<Pair<T>> lookup(Class <T> clazz) { 215 if ((clazz != null) && clazz.isInterface()) { 216 return (Enumeration)searchInterface(clazz); 217 } else { 218 return (Enumeration)searchClass(object, clazz); 219 } 220 } 221 222 228 public static boolean unsorted(Enumeration en) { 229 return en instanceof NeedsSortEnum; 230 } 231 232 236 public void print(java.io.PrintStream out, boolean instances) { 237 printNode(object, "", out, instances); } 239 240 244 247 private static Node registerClass(Node n, AbstractLookup.Pair item) { 248 if (!n.accepts(item)) { 249 return null; 250 } 251 252 if (n.children != null) { 253 Iterator it = n.children.iterator(); 254 255 for (;;) { 256 Node ch = extractNode(it); 257 258 if (ch == null) { 259 break; 260 } 261 262 Node result = registerClass(ch, item); 263 264 if (result != null) { 265 return result; 268 } 269 } 270 } 271 272 return n; 274 } 275 276 279 private static Node removeClass(Node n, AbstractLookup.Pair item) { 280 if (!n.accepts(item)) { 281 return null; 282 } 283 284 if ((n.items != null) && n.items.remove(item)) { 285 return n; 287 } 288 289 if (n.children != null) { 290 Iterator it = n.children.iterator(); 291 292 for (;;) { 293 Node ch = extractNode(it); 294 295 if (ch == null) { 296 break; 297 } 298 299 Node result = removeClass(ch, item); 300 301 if (((ch.items == null) || ch.items.isEmpty()) && ((ch.children == null) || ch.children.isEmpty())) { 303 it.remove(); 304 } 305 306 if (result != null) { 307 return result; 310 } 311 } 312 } 313 314 return null; 316 } 317 318 324 private Node classToNode(final Node n, final Class <?> clazz) { 325 if (!n.accepts(clazz)) { 326 return null; 328 } 329 330 if (n.getType() == clazz) { 331 return n; 333 } 334 335 if (n.children != null) { 336 Iterator it = n.children.iterator(); 338 339 for (;;) { 340 final Node ch = extractNode(it); 341 342 if (ch == null) { 343 break; 344 } 345 346 Node found = classToNode(ch, clazz); 347 348 if ((found != null) && ch.deserialized()) { 349 class VerifyJob implements AbstractLookup.ISE.Job { 350 private AbstractLookup.Pair<?>[] pairs; 351 private boolean[] answers; 352 353 public VerifyJob(Collection<Pair> items) { 354 if (items != null) { 355 pairs = items.toArray(new AbstractLookup.Pair[0]); 356 } 357 } 358 359 public void before() { 360 ch.deserialized(); 362 363 if (pairs != null) { 364 answers = new boolean[pairs.length]; 365 366 for (int i = 0; i < pairs.length; i++) { 367 answers[i] = pairs[i].instanceOf(clazz); 368 } 369 } 370 } 371 372 public void inside() { 373 if (pairs != null) { 374 for (int i = 0; i < pairs.length; i++) { 375 if (answers[i]) { 376 ch.assignItem(InheritanceTree.this, pairs[i]); 377 n.items.remove(pairs[i]); 378 } 379 } 380 } 381 382 if (n.children != null) { 383 HashMap<Class ,Node> nodes = new HashMap<Class ,Node>(n.children.size() * 3); 385 386 Iterator child = n.children.iterator(); 387 388 while (child.hasNext()) { 389 Node node = extractNode(child); 390 Node prev = nodes.put(node.getType(), node); 391 392 if (prev != null) { 393 child.remove(); 394 nodes.put(node.getType(), prev); 395 396 prev.markDeserialized(); 398 399 if (prev.children == null) { 400 prev.children = node.children; 401 } else { 402 if (node.children != null) { 403 prev.children.addAll(node.children); 404 } 405 } 406 407 if (node.items != null) { 408 Iterator items = node.items.iterator(); 409 410 while (items.hasNext()) { 411 AbstractLookup.Pair item = (AbstractLookup.Pair) items.next(); 412 prev.assignItem(InheritanceTree.this, item); 413 } 414 } 415 } 416 } 417 } 418 } 419 } 420 421 VerifyJob verify = new VerifyJob(n.items); 422 423 try { 424 verify.before(); 425 } catch (AbstractLookup.ISE ex) { 426 ch.markDeserialized(); 428 ex.registerJob(verify); 429 throw ex; 430 } 431 432 verify.inside(); 433 434 found = classToNode(ch, clazz); 435 } 436 437 if (found != null) { 438 return found; 440 } 441 } 442 } 443 444 class TwoJobs implements AbstractLookup.ISE.Job { 445 private AbstractLookup.Pair[] pairs; 446 private boolean[] answers; 447 private Node newNode; 448 449 public void before() { 450 AbstractLookup.Pair[] arr = null; 455 boolean[] boolArr = null; 456 457 if (n.items != null) { 458 arr = new AbstractLookup.Pair[n.items.size()]; 459 boolArr = new boolean[n.items.size()]; 460 461 int i = 0; 462 Iterator<Pair> it = n.items.iterator(); 463 464 while (it.hasNext()) { 465 AbstractLookup.Pair<?> item = it.next(); 466 arr[i] = item; 467 boolArr[i] = item.instanceOf(clazz); 468 i++; 469 } 470 } 471 472 pairs = arr; 473 answers = boolArr; 474 } 475 476 public void inside() { 477 if (pairs != null) { 479 if (!Arrays.equals(n.items.toArray(), pairs)) { 480 return; 482 } 483 } 484 485 internal(); 486 } 487 488 public void internal() { 489 ArrayList<Node> reparent = null; 490 491 if (n.children == null) { 492 n.children = new ArrayList<Node>(); 493 } else { 494 Iterator it = n.children.iterator(); 497 498 for (;;) { 499 Node r = extractNode(it); 500 501 if (r == null) { 502 break; 503 } 504 505 if (clazz.isAssignableFrom(r.getType())) { 506 if (reparent == null) { 507 reparent = new ArrayList<Node>(); 508 } 509 510 reparent.add(r); 511 it.remove(); 512 } 513 } 514 } 515 516 newNode = new Node(clazz); 517 n.children.add(newNode); 518 519 if (reparent != null) { 520 newNode.children = reparent; 522 } 523 524 if (n.items != null) { 527 Iterator it = n.items.iterator(); 528 int i = 0; 529 530 while (it.hasNext()) { 531 AbstractLookup.Pair item = (AbstractLookup.Pair) it.next(); 532 533 if (answers[i]) { it.remove(); 535 newNode.assignItem(InheritanceTree.this, pairs[i]); 536 } 537 538 i++; 539 } 540 } 541 } 542 } 543 544 TwoJobs j = new TwoJobs(); 545 546 try { 547 j.before(); 548 } catch (AbstractLookup.ISE ex) { 549 ex.registerJob(j); 553 throw ex; 554 } 555 556 j.internal(); 557 558 return j.newNode; 560 } 561 562 565 private Enumeration<Pair> searchClass(Node n, Class <?> clazz) { 566 if (clazz != null) { 567 n = classToNode(n, clazz); 568 } 569 570 if (n == null) { 571 return org.openide.util.Enumerations.empty(); 573 } else { 574 return nodeToEnum(n); 575 } 576 } 577 578 586 private boolean retainAllClasses(Node node, Map retain, Collection<Class > notify) { 587 boolean retained = false; 588 589 if ((node.items != null) && (retain != null)) { 590 Iterator<Pair> it = node.items.iterator(); 591 592 while (it.hasNext()) { 593 AbstractLookup.Pair<?> item = it.next(); 594 AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(item); 595 596 if (n == null) { 597 it.remove(); 599 retained = true; 600 } else { 601 if (item.getIndex() != n.index) { 603 item.setIndex(null, n.index); 604 605 } 607 } 608 } 609 610 if (retained && (notify != null)) { 611 notify.add(node.getType()); 613 } 614 } 615 616 if (node.children != null) { 617 for (Iterator it = node.children.iterator();;) { 618 Node ch = extractNode(it); 619 620 if (ch == null) { 621 break; 622 } 623 624 boolean result = retainAllClasses(ch, retain, notify); 625 626 if (result) { 627 it.remove(); 629 } 630 } 631 } 632 633 return retained && node.items.isEmpty() && ((node.children == null) || node.children.isEmpty()); 634 } 635 636 641 private static Enumeration<Pair> nodeToEnum(Node n) { 642 if (n.children == null) { 643 Enumeration<Pair> e; 645 if (n.items == null) { 646 e = Enumerations.empty(); 647 } else { 648 e = Collections.enumeration(n.items); 649 } 650 return e; 651 } 652 653 class DeepAndItems implements Enumerations.Processor<Node,Enumeration<Pair>> { 656 public Enumeration<Pair> process(Node n2, Collection<Node> toAdd) { 657 if (n2.children != null) { 658 toAdd.addAll(n2.children); 659 } 660 661 if ((n2.items == null) || n2.items.isEmpty()) { 662 return Enumerations.empty(); 663 } else { 664 return Collections.enumeration(n2.items); 665 } 666 } 667 } 668 669 Enumeration<Enumeration<Pair>> en = Enumerations.queue( 670 Enumerations.singleton(n), new DeepAndItems() 672 ); 673 Enumeration<Pair> all = Enumerations.concat(en); 674 return new NeedsSortEnum<Pair>(all); 676 } 677 678 682 687 @SuppressWarnings ("unchecked") 688 private boolean registerInterface(AbstractLookup.Pair<?> item, Collection<Class > affected) { 689 if (interfaces == null) { 690 return true; 691 } 692 693 Iterator<Map.Entry<Class ,Object >> it = interfaces.entrySet().iterator(); 694 695 while (it.hasNext()) { 696 Map.Entry<Class ,Object > entry = it.next(); 697 Class <?> iface = entry.getKey(); 698 699 if (item.instanceOf(iface)) { 700 Object value = entry.getValue(); 701 702 if (value instanceof Collection) { 703 Collection<Object > set = (Collection<Object >) value; 704 705 if (!set.add(item)) { 706 return false; 709 } 710 } else { 711 if (value.equals(item)) { 713 return false; 715 } 716 717 ArrayList<Object > ll = new ArrayList<Object >(3); 719 ll.add(value); 720 ll.add(item); 721 entry.setValue(ll); 722 } 723 724 affected.add(iface); 725 } 726 } 727 728 return true; 729 } 730 731 735 @SuppressWarnings ("unchecked") 736 private void removeInterface(AbstractLookup.Pair item, Collection affected) { 737 if (interfaces == null) { 738 return; 739 } 740 741 Iterator it = interfaces.entrySet().iterator(); 742 743 while (it.hasNext()) { 744 Map.Entry entry = (Map.Entry) it.next(); 745 Object value = entry.getValue(); 746 747 if (value instanceof Collection) { 748 Collection set = (Collection) value; 749 750 if (set.remove(item)) { 751 if (set.size() == 1) { 752 entry.setValue(set.iterator().next()); 754 } 755 756 affected.add(entry.getKey()); 758 } 759 } else { 760 if (value.equals(item)) { 762 it.remove(); 764 765 affected.add(entry.getKey()); 766 } 767 } 768 } 769 } 770 771 776 @SuppressWarnings ("unchecked") 777 private void retainAllInterface(Map retainItems, Collection affected) { 778 if (interfaces == null) { 779 return; 780 } 781 782 Iterator it = interfaces.entrySet().iterator(); 783 784 while (it.hasNext()) { 785 Map.Entry entry = (Map.Entry) it.next(); 786 Object value = entry.getValue(); 787 788 HashMap<?,?> retain = new HashMap(retainItems); 789 790 Iterator elems; 791 boolean multi = value instanceof Collection; 792 793 if (multi) { 794 elems = ((Collection) value).iterator(); 796 } else { 797 elems = Collections.singleton(value).iterator(); 799 } 800 801 boolean changed = false; 802 boolean reordered = false; 803 804 while (elems.hasNext()) { 805 AbstractLookup.Pair p = (AbstractLookup.Pair) elems.next(); 806 807 AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(p); 808 809 if (n == null) { 810 if (multi) { 811 elems.remove(); 813 } 814 815 changed = true; 816 } else { 817 if (p.getIndex() != n.index) { 818 p.setIndex(null, n.index); 820 821 reordered = true; 823 } 824 } 825 } 826 827 if (reordered && value instanceof List) { 828 List l = (List) value; 830 Collections.sort(l, ALPairComparator.DEFAULT); 831 } 832 833 if (changed) { 834 if (multi) { 835 Collection c = (Collection) value; 836 837 if (c.size() == 1) { 838 entry.setValue(c.iterator().next()); 840 } 841 } else { 842 it.remove(); 844 } 845 846 affected.add(entry.getKey()); 848 } 849 } 850 } 851 852 856 @SuppressWarnings ("unchecked") 857 private Enumeration<Pair> searchInterface(final Class <?> clazz) { 858 if (interfaces == null) { 859 interfaces = new WeakHashMap(); 861 } 862 863 Object obj = interfaces.get(clazz); 864 865 if (obj == null) { 866 AbstractLookup.Pair one = null; 868 ArrayList items = null; 869 870 Enumeration en = lookup(Object .class); 871 872 while (en.hasMoreElements()) { 873 AbstractLookup.Pair it = (AbstractLookup.Pair) en.nextElement(); 874 875 if (it.instanceOf(clazz)) { 876 if (one == null) { 878 one = it; 879 } else { 880 if (items == null) { 881 items = new ArrayList(3); 882 items.add(one); 883 } 884 885 items.add(it); 886 } 887 } 888 } 889 890 if ((items == null) && (one != null)) { 891 interfaces.put(clazz, one); 893 894 return org.openide.util.Enumerations.singleton(one); 895 } else { 896 if (items == null) { 897 items = new ArrayList(2); 898 } 899 900 interfaces.put(clazz, items); 901 902 return Collections.enumeration(items); 903 } 904 } else { 905 if (obj instanceof Collection) { 906 return Collections.enumeration((Collection) obj); 907 } else { 908 return org.openide.util.Enumerations.singleton((Pair)obj); 910 } 911 } 912 } 913 914 916 private static Node extractNode(Iterator it) { 917 while (it.hasNext()) { 918 Node n = (Node) it.next(); 919 920 if (n.get() == null) { 921 it.remove(); 922 } else { 923 return n; 924 } 925 } 926 927 return null; 928 } 929 930 936 private static void printNode(Node n, String sp, java.io.PrintStream out, boolean instances) { 937 int i; 938 Iterator it; 939 940 Class type = n.getType(); 941 942 out.print(sp); 943 out.println("Node for: " + type + "\t" + ((type == null) ? null : type.getClassLoader())); 945 if (n.items != null) { 946 i = 0; 947 it = new ArrayList<Pair>(n.items).iterator(); 948 949 while (it.hasNext()) { 950 AbstractLookup.Pair p = (AbstractLookup.Pair) it.next(); 951 out.print(sp); 952 out.print(" item (" + i++ + "): "); 953 out.print(p); out.print(" id: " + Integer.toHexString(System.identityHashCode(p))); out.print(" index: "); out.print(p.getIndex()); 957 958 if (instances) { 959 out.print(" I: " + p.getInstance()); 960 } 961 962 out.println(); 963 } 964 } 965 966 if (n.children != null) { 967 i = 0; 968 it = n.children.iterator(); 969 970 while (it.hasNext()) { 971 Node ch = (Node) it.next(); 972 printNode(ch, sp + " ", out, instances); } 974 } 975 } 976 977 public ReferenceToResult registerReferenceToResult(ReferenceToResult<?> newRef) { 978 if (reg == null) { 979 reg = new HashMap<Class ,ReferenceToResult>(); 980 } 981 982 Class <? extends Object > clazz = newRef.template.getType(); 983 984 lookup(clazz); 986 987 return reg.put(clazz, newRef); 989 } 990 991 public ReferenceToResult cleanUpResult(Lookup.Template templ) { 992 collectListeners(null, templ.getType()); 993 994 return (reg == null) ? null : reg.get(templ.getType()); 995 } 996 997 public ArrayList<Class > beginTransaction(int ensure) { 998 return new ArrayList<Class >(); 999 } 1000 1001 public void endTransaction(ArrayList<Class > list, Set<AbstractLookup.R> allAffectedResults) { 1002 if (list.size() == 1) { 1003 collectListeners(allAffectedResults, list.get(0)); 1005 } else { 1006 Iterator it = list.iterator(); 1007 1008 while (it.hasNext()) { 1009 collectListeners(allAffectedResults, (Class ) it.next()); 1010 } 1011 } 1012 } 1013 1014 1019 private void collectListeners(Set<AbstractLookup.R> allAffectedResults, Class c) { 1020 if (reg == null) { 1021 return; 1022 } 1023 1024 while (c != null) { 1025 ReferenceToResult first = reg.get(c); 1026 ReferenceIterator it = new ReferenceIterator(first); 1027 1028 while (it.next()) { 1029 AbstractLookup.R result = it.current().getResult(); 1030 1031 if (allAffectedResults != null) { 1032 allAffectedResults.add(result); 1034 } 1035 } 1036 1037 if (first != it.first()) { 1038 if (it.first() == null) { 1039 reg.remove(c); 1041 } else { 1042 reg.put(c, it.first()); 1044 } 1045 } 1046 1047 c = c.getSuperclass(); 1048 } 1049 1050 if (reg.isEmpty()) { 1051 reg = null; 1053 } 1054 } 1055 1056 1058 static final class Node extends WeakReference <Class > implements Serializable { 1059 static final long serialVersionUID = 3L; 1060 1061 1062 public ArrayList<Node> children; 1063 1064 1065 public List<Pair> items; 1066 1067 1069 public Node(Class clazz) { 1070 super(clazz); 1071 } 1072 1073 1076 public boolean deserialized() { 1077 if ((items == null) || items instanceof ArrayList) { 1078 return false; 1079 } 1080 1081 if (items.isEmpty()) { 1082 items = null; 1083 } else { 1084 items = new ArrayList<Pair>(items); 1085 } 1086 1087 return true; 1088 } 1089 1090 1092 public void markDeserialized() { 1093 if (items == null || items == Collections.EMPTY_LIST) { 1094 items = Collections.emptyList(); 1095 } else { 1096 items = Collections.synchronizedList(items); 1097 } 1098 } 1099 1100 1102 public Class <?> getType() { 1103 Class <?> c = get(); 1104 1105 return (c == null) ? Void.TYPE : c; 1107 } 1108 1109 1111 public boolean accepts(Class <?> clazz) { 1112 if (getType() == Object .class) { 1113 return true; 1114 } 1115 1116 return getType().isAssignableFrom(clazz); 1117 } 1118 1119 1121 public boolean accepts(AbstractLookup.Pair<?> item) { 1122 if (getType() == Object .class) { 1123 return true; 1125 } 1126 1127 return item.instanceOf(getType()); 1128 } 1129 1130 1134 public boolean assignItem(InheritanceTree tree, AbstractLookup.Pair<?> item) { 1135 if ((items == null) || (items == Collections.EMPTY_LIST)) { 1136 items = new ArrayList<Pair>(); 1137 items.add(item); 1138 1139 return true; 1140 } 1141 1142 if (items.contains(item)) { 1143 int i = items.indexOf(item); 1144 AbstractLookup.Pair old = items.get(i); 1145 1146 if (old != item) { 1147 item.setIndex(tree, old.getIndex()); 1149 } 1150 1151 items.remove(old); 1152 items.add(item); 1153 1154 return false; 1155 } 1156 1157 items.add(item); 1158 1159 return true; 1160 } 1161 1162 private Object writeReplace() { 1163 return new R(this); 1164 } 1165 1166 public String toString() { 1167 return "Node for " + get(); 1168 } 1169 } 1170 1172 private static final class R implements Serializable { 1173 static final long serialVersionUID = 1L; 1174 private static ClassLoader l; 1175 private String clazzName; 1176 private transient Class <?> clazz; 1177 private ArrayList<Node> children; 1178 private ArrayList<Pair> items; 1179 1180 public R(Node n) { 1181 this.clazzName = n.getType().getName(); 1182 this.children = n.children; 1183 1184 if (n.items instanceof ArrayList || (n.items == null)) { 1185 this.items = (ArrayList<Pair>) n.items; 1186 } else { 1187 this.items = new ArrayList<Pair>(n.items); 1188 } 1189 } 1190 1191 private void readObject(ObjectInputStream ois) 1192 throws IOException, ClassNotFoundException { 1193 ois.defaultReadObject(); 1194 1195 if (l == null) { 1196 l = Lookup.getDefault().lookup(ClassLoader .class); 1197 } 1198 1199 clazz = Class.forName(clazzName, false, l); 1200 } 1201 1202 private Object readResolve() throws ObjectStreamException { 1203 Node n = new Node(clazz); 1204 n.children = children; 1205 n.items = items; 1206 n.markDeserialized(); 1207 1208 return n; 1209 } 1210 } 1211 1213 1216 private static final class NeedsSortEnum<T> implements Enumeration<T> { 1217 private Enumeration<T> en; 1218 1219 public NeedsSortEnum(Enumeration<T> en) { 1220 this.en = en; 1221 } 1222 1223 public boolean hasMoreElements() { 1224 return en.hasMoreElements(); 1225 } 1226 1227 public T nextElement() { 1228 return en.nextElement(); 1229 } 1230 } 1231 } 1233 | Popular Tags |