1 19 package org.openide.util.lookup; 20 21 import org.openide.util.Lookup; 22 import org.openide.util.LookupEvent; 23 import org.openide.util.LookupListener; 24 25 import java.io.IOException ; 26 import java.io.ObjectOutputStream ; 27 import java.io.Serializable ; 28 29 import java.lang.ref.*; 30 import java.lang.ref.ReferenceQueue ; 31 32 import java.util.*; 33 import org.openide.util.Utilities; 34 35 36 44 public class AbstractLookup extends Lookup implements Serializable { 45 static final long serialVersionUID = 5L; 46 47 48 private static Object treeLock = new Object (); 49 50 51 private Object tree; 52 53 54 private int count; 55 56 64 public AbstractLookup(Content content) { 65 content.attach(this); 66 } 67 68 71 AbstractLookup(Content content, Storage<?> storage) { 72 this(content); 73 this.tree = storage; 74 initialize(); 75 } 76 77 81 AbstractLookup(Content content, Integer trashhold) { 82 this(content); 83 this.tree = trashhold; 84 } 85 86 88 protected AbstractLookup() { 89 } 90 91 public String toString() { 92 if (tree instanceof Storage) { 93 return "AbstractLookup" + lookup(new Lookup.Template<Object >(Object .class)).allItems(); } else { 95 return super.toString(); 96 } 97 } 98 99 101 @SuppressWarnings ("unchecked") 102 private <T> AbstractLookup.Storage<T> enterStorage() { 103 for (;;) { 104 synchronized (treeLock) { 105 if (tree instanceof AbstractLookup.Storage) { 106 if (tree instanceof DelegatingStorage) { 107 DelegatingStorage del = (DelegatingStorage) tree; 109 110 del.checkForTreeModification(); 113 114 try { 115 treeLock.wait(); 116 } catch (InterruptedException ex) { 117 } 119 120 continue; 121 } else { 122 tree = new DelegatingStorage((Storage<T>) tree); 124 125 return (Storage<T>) tree; 126 } 127 } 128 129 if (tree instanceof Integer ) { 131 tree = new ArrayStorage((Integer ) tree); 132 } else { 133 tree = new ArrayStorage(); 134 } 135 } 136 137 initialize(); 139 } 140 } 141 142 144 private AbstractLookup.Storage exitStorage() { 145 synchronized (treeLock) { 146 AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate(); 147 tree = stor; 148 treeLock.notifyAll(); 149 150 return stor; 151 } 152 } 153 154 156 protected void initialize() { 157 } 158 159 162 protected void beforeLookup(Template<?> template) { 163 } 164 165 168 protected final void addPair(Pair<?> pair) { 169 addPairImpl(pair); 170 } 171 172 private final <Transaction> void addPairImpl(Pair<?> pair) { 173 HashSet<R> toNotify = new HashSet<R>(); 174 175 AbstractLookup.Storage<Transaction> t = enterStorage(); 176 Transaction transaction = null; 177 178 try { 179 transaction = t.beginTransaction(-2); 180 181 if (t.add(pair, transaction)) { 182 try { 183 pair.setIndex(t, count++); 184 } catch (IllegalStateException ex) { 185 t.remove(pair, transaction); 187 188 throw ex; 190 } 191 192 t.endTransaction(transaction, toNotify); 194 } else { 195 t.endTransaction(transaction, new HashSet<R>()); 197 } 198 } finally { 199 exitStorage(); 200 } 201 202 notifyListeners(toNotify); 203 } 204 205 208 protected final void removePair(Pair<?> pair) { 209 removePairImpl(pair); 210 } 211 212 private <Transaction> void removePairImpl(Pair<?> pair) { 213 HashSet<R> toNotify = new HashSet<R>(); 214 215 AbstractLookup.Storage<Transaction> t = enterStorage(); 216 Transaction transaction = null; 217 218 try { 219 transaction = t.beginTransaction(-1); 220 t.remove(pair, transaction); 221 t.endTransaction(transaction, toNotify); 222 } finally { 223 exitStorage(); 224 } 225 226 notifyListeners(toNotify); 227 } 228 229 232 protected final void setPairs(Collection<? extends Pair> collection) { 233 notifyCollectedListeners(setPairsAndCollectListeners(collection)); 234 } 235 236 239 final LinkedHashSet<Pair<?>> getPairsAsLHS() { 240 AbstractLookup.Storage<?> t = enterStorage(); 241 242 try { 243 Enumeration<Pair<Object >> en = t.lookup(Object .class); 244 LinkedHashSet<Pair<?>> arr = new LinkedHashSet<Pair<?>>(); 245 while (en.hasMoreElements()) { 246 Pair<Object > item = en.nextElement(); 247 arr.add(item); 248 } 249 return arr; 250 } finally { 251 exitStorage(); 252 } 253 } 254 255 258 final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) { 259 HashSet<R> toNotify = new HashSet<R>(27); 260 261 AbstractLookup.Storage<Transaction> t = enterStorage(); 262 Transaction transaction = null; 263 264 try { 265 HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2); 267 268 count = 0; 269 270 Iterator it = collection.iterator(); 271 transaction = t.beginTransaction(collection.size()); 272 273 while (it.hasNext()) { 274 Pair item = (Pair) it.next(); 275 276 if (t.add(item, transaction)) { 277 } 280 281 shouldBeThere.put(item, new Info(count++, transaction)); 283 284 } 286 287 t.retainAll(shouldBeThere, transaction); 290 291 t.endTransaction(transaction, toNotify); 293 294 313 } finally { 314 exitStorage(); 315 } 316 317 return toNotify; 318 } 319 320 323 final void notifyCollectedListeners(Set<R> listeners) { 324 notifyListeners(listeners); 325 } 326 327 private final void writeObject(ObjectOutputStream oos) 328 throws IOException { 329 AbstractLookup.Storage s = enterStorage(); 330 331 try { 332 s.beginTransaction(Integer.MAX_VALUE); 334 335 oos.defaultWriteObject(); 337 } finally { 338 exitStorage(); 339 } 340 } 341 342 public final <T> T lookup(Class <T> clazz) { 343 Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz)); 344 return (item == null) ? null : item.getInstance(); 345 } 346 347 public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) { 348 AbstractLookup.this.beforeLookup(template); 349 350 ArrayList<Pair<T>> list = null; 351 AbstractLookup.Storage<?> t = enterStorage(); 352 353 try { 354 Enumeration<Pair<T>> en; 355 356 try { 357 en = t.lookup(template.getType()); 358 359 return findSmallest(en, template, false); 360 } catch (AbstractLookup.ISE ex) { 361 list = new ArrayList<Pair<T>>(); 364 en = t.lookup(null); 366 while (en.hasMoreElements()) { 368 list.add(en.nextElement()); 369 } 370 } 371 } finally { 372 exitStorage(); 373 } 374 375 return findSmallest(Collections.enumeration(list), template, true); 376 } 377 378 private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) { 379 int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE; 380 Pair<T> res = null; 381 382 while (en.hasMoreElements()) { 383 Pair<T> item = en.nextElement(); 384 385 if (matches(template, item, deepCheck)) { 386 if (smallest == Integer.MIN_VALUE) { 387 return item; 389 } else { 390 if (smallest > item.getIndex()) { 392 smallest = item.getIndex(); 393 res = item; 394 } 395 } 396 } 397 } 398 399 return res; 400 } 401 402 public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) { 403 for (;;) { 404 AbstractLookup.ISE toRun = null; 405 406 AbstractLookup.Storage<?> t = enterStorage(); 407 408 try { 409 R<T> r = new R<T>(); 410 ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template); 411 newRef.next = t.registerReferenceToResult(newRef); 412 413 return r; 414 } catch (AbstractLookup.ISE ex) { 415 toRun = ex; 416 } finally { 417 exitStorage(); 418 } 419 420 toRun.recover(this); 421 422 } 424 } 425 426 429 private static void notifyListeners(Set<R> allAffectedResults) { 430 if (allAffectedResults.isEmpty()) { 431 return; 432 } 433 434 ArrayList<Object > evAndListeners = new ArrayList<Object >(); 435 { 436 for (R<?> result : allAffectedResults) { 437 result.collectFires(evAndListeners); 438 } 439 } 440 441 { 442 Iterator it = evAndListeners.iterator(); 443 while (it.hasNext()) { 444 LookupEvent ev = (LookupEvent)it.next(); 445 LookupListener l = (LookupListener)it.next(); 446 l.resultChanged(ev); 447 } 448 } 449 } 450 451 458 static void notifyListeners(Object [] listeners, LookupEvent ev, Collection<Object > evAndListeners) { 459 for (int i = listeners.length - 1; i >= 0; i--) { 460 if (! (listeners[i] instanceof LookupListener)) { 461 continue; 462 } 463 LookupListener ll = (LookupListener)listeners[i]; 464 465 try { 466 if (evAndListeners != null) { 467 if (ll instanceof WaitableResult) { 468 WaitableResult<?> wr = (WaitableResult<?>)ll; 469 wr.collectFires(evAndListeners); 470 } else { 471 evAndListeners.add(ev); 472 evAndListeners.add(ll); 473 } 474 } else { 475 ll.resultChanged(ev); 476 } 477 } catch (RuntimeException e) { 478 e.printStackTrace(); 480 } 481 } 482 } 483 484 490 static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) { 491 String id = t.getId(); 492 493 if ((id != null) && !item.getId().equals(id)) { 494 return false; 495 } 496 497 Object instance = t.getInstance(); 498 499 if ((instance != null) && !item.creatorOf(instance)) { 500 return false; 501 } 502 503 if (deepCheck) { 504 return item.instanceOf(t.getType()); 505 } else { 506 return true; 507 } 508 } 509 510 515 private static boolean compareArrays(Object [] a, Object [] b) { 516 if (a == null) { 518 return (b == null); 519 } else { 520 if (b == null) { 521 return false; 522 } 523 } 524 525 if (a.length != b.length) { 526 return false; 527 } 528 529 for (int i = 0; i < a.length; i++) { 530 if (a[i] == null) { 532 if (b[i] != null) { 533 return false; 534 } 535 536 continue; 538 } else { 539 if (b[i] == null) { 540 return false; 541 } 542 } 543 544 if (!a[i].equals(b[i])) { 546 return false; 547 } 548 } 549 550 return true; 551 } 552 553 558 <T> boolean cleanUpResult(Lookup.Template<T> template) { 559 AbstractLookup.Storage<?> t = enterStorage(); 560 561 try { 562 return t.cleanUpResult(template) == null; 563 } finally { 564 exitStorage(); 565 } 566 } 567 568 575 @SuppressWarnings ("unchecked") 576 static Object modifyListenerList(boolean add, LookupListener l, Object ref) { 577 if (add) { 578 if (ref == null) { 579 return l; 580 } 581 582 if (ref instanceof LookupListener) { 583 ArrayList arr = new ArrayList(); 584 arr.add(ref); 585 ref = arr; 586 } 587 588 ((ArrayList) ref).add(l); 589 590 return ref; 591 } else { 592 if (ref == null) { 594 return null; 595 } 596 597 if (ref == l) { 598 return null; 599 } 600 601 ArrayList arr = (ArrayList) ref; 602 arr.remove(l); 603 604 if (arr.size() == 1) { 605 return arr.iterator().next(); 606 } else { 607 return arr; 608 } 609 } 610 } 611 612 private static ReferenceQueue <Object > activeQueue() { 613 return Utilities.activeReferenceQueue(); 614 } 615 616 619 interface Storage<Transaction> { 620 630 public Transaction beginTransaction(int ensure); 631 632 638 public void endTransaction(Transaction transaction, Set<R> modifiedResults); 639 640 646 public boolean add(AbstractLookup.Pair<?> item, Transaction transaction); 647 648 650 public void remove(AbstractLookup.Pair item, Transaction transaction); 651 652 656 public void retainAll(Map retain, Transaction transaction); 657 658 663 public <T> Enumeration<Pair<T>> lookup(Class <T> clazz); 664 665 673 public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef); 674 675 679 public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ); 680 } 681 682 685 public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable { 686 private static final long serialVersionUID = 1L; 687 688 689 private int index = -1; 690 691 692 protected Pair() { 693 } 694 695 final int getIndex() { 696 return index; 697 } 698 699 final void setIndex(AbstractLookup.Storage<?> tree, int x) { 700 if (tree == null) { 701 this.index = x; 702 703 return; 704 } 705 706 if (this.index == -1) { 707 this.index = x; 708 } else { 709 throw new IllegalStateException ("You cannot use " + this + " in more than one AbstractLookup"); } 711 } 712 713 716 protected abstract boolean instanceOf(Class <?> c); 717 718 725 protected abstract boolean creatorOf(Object obj); 726 } 727 728 730 static final class R<T> extends WaitableResult<T> { 731 732 public ReferenceToResult<T> reference; 733 734 735 private Object listeners; 736 737 public R() { 738 } 739 740 742 private boolean isSimple() { 743 Storage s = (Storage) reference.lookup.tree; 744 745 return DelegatingStorage.isSimple(s); 746 } 747 748 private Object getFromCache(int indx) { 755 if (isSimple()) { 756 return null; 757 } 758 759 Object maybeArray = reference.caches; 760 761 if (maybeArray instanceof Object []) { 762 return ((Object []) maybeArray)[indx]; 763 } 764 765 return null; 766 } 767 768 @SuppressWarnings ("unchecked") 769 private Set<Class <? extends T>> getClassesCache() { 770 return (Set<Class <? extends T>>) getFromCache(0); 771 } 772 773 private void setClassesCache(Set s) { 774 if (isSimple()) { 775 reference.caches = reference; 777 778 return; 779 } 780 781 if (!(reference.caches instanceof Object [])) { 782 reference.caches = new Object [3]; 783 } 784 785 ((Object []) reference.caches)[0] = s; 786 } 787 788 @SuppressWarnings ("unchecked") 789 private Collection<T> getInstancesCache() { 790 return (Collection<T>) getFromCache(1); 791 } 792 793 private void setInstancesCache(Collection c) { 794 if (isSimple()) { 795 reference.caches = reference; 797 798 return; 799 } 800 801 if (!(reference.caches instanceof Object [])) { 802 reference.caches = new Object [3]; 803 } 804 805 ((Object []) reference.caches)[1] = c; 806 } 807 808 @SuppressWarnings ("unchecked") 809 private Pair<T>[] getItemsCache() { 810 return (Pair<T>[]) getFromCache(2); 811 } 812 813 private void setItemsCache(Collection<?> c) { 814 if (isSimple()) { 815 reference.caches = reference; 817 818 return; 819 } 820 821 if (!(reference.caches instanceof Object [])) { 822 reference.caches = new Object [3]; 823 } 824 825 ((Object []) reference.caches)[2] = c.toArray(new Pair[0]); 826 } 827 828 private void clearCaches() { 829 if (reference.caches instanceof Object []) { 830 reference.caches = new Object [3]; 831 } 832 } 833 834 836 public synchronized void addLookupListener(LookupListener l) { 837 listeners = modifyListenerList(true, l, listeners); 838 } 839 840 842 public synchronized void removeLookupListener(LookupListener l) { 843 listeners = modifyListenerList(false, l, listeners); 844 } 845 846 848 protected void collectFires(Collection<Object > evAndListeners) { 849 Object [] previousItems = getItemsCache(); 850 clearCaches(); 851 852 if (previousItems != null) { 853 Object [] newArray = allItemsWithoutBeforeLookup().toArray(); 854 855 if (compareArrays(previousItems, newArray)) { 856 return; 858 } 859 } 860 861 LookupListener[] arr; 862 863 synchronized (this) { 864 if (listeners == null) { 865 return; 866 } 867 868 if (listeners instanceof LookupListener) { 869 arr = new LookupListener[] { (LookupListener) listeners }; 870 } else { 871 ArrayList<?> l = (ArrayList<?>) listeners; 872 arr = l.toArray(new LookupListener[l.size()]); 873 } 874 } 875 876 final LookupListener[] ll = arr; 877 final LookupEvent ev = new LookupEvent(this); 878 notifyListeners(ll, ev, evAndListeners); 879 } 880 881 public Collection<T> allInstances() { 882 reference.lookup.beforeLookup(reference.template); 883 884 Collection<T> s = getInstancesCache(); 885 886 if (s != null) { 887 return s; 888 } 889 890 Collection<Pair<T>> items = allItemsWithoutBeforeLookup(); 891 ArrayList<T> list = new ArrayList<T>(items.size()); 892 893 Iterator<Pair<T>> it = items.iterator(); 894 895 while (it.hasNext()) { 896 Pair<T> item = it.next(); 897 T obj = item.getInstance(); 898 899 if (reference.template.getType().isInstance(obj)) { 900 list.add(obj); 901 } 902 } 903 904 s = Collections.unmodifiableList(list); 905 setInstancesCache(s); 906 907 return s; 908 } 909 910 913 public Set<Class <? extends T>> allClasses() { 914 reference.lookup.beforeLookup(reference.template); 915 916 Set<Class <? extends T>> s = getClassesCache(); 917 918 if (s != null) { 919 return s; 920 } 921 922 s = new HashSet<Class <? extends T>>(); 923 924 for (Pair<T> item : allItemsWithoutBeforeLookup()) { 925 Class <? extends T> clazz = item.getType(); 926 927 if (clazz != null) { 928 s.add(clazz); 929 } 930 } 931 932 s = Collections.unmodifiableSet(s); 933 setClassesCache(s); 934 935 return s; 936 } 937 938 940 public Collection<? extends Item<T>> allItems() { 941 reference.lookup.beforeLookup(reference.template); 942 943 return allItemsWithoutBeforeLookup(); 944 } 945 946 947 private Collection<Pair<T>> allItemsWithoutBeforeLookup() { 948 Pair<T>[] c = getItemsCache(); 949 950 if (c != null) { 951 return Collections.unmodifiableList(Arrays.asList(c)); 952 } 953 954 ArrayList<Pair<Object >> saferCheck = null; 955 AbstractLookup.Storage<?> t = reference.lookup.enterStorage(); 956 957 try { 958 try { 959 return Collections.unmodifiableCollection(initItems(t)); 960 } catch (AbstractLookup.ISE ex) { 961 saferCheck = new ArrayList<Pair<Object >>(); 964 965 Enumeration<Pair<Object >> en = t.lookup(null); 967 while (en.hasMoreElements()) { 968 Pair<Object > i = en.nextElement(); 969 saferCheck.add(i); 970 } 971 } 972 } finally { 973 reference.lookup.exitStorage(); 974 } 975 return extractPairs(saferCheck); 976 } 977 978 @SuppressWarnings ("unchecked") 979 private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object >> saferCheck) { 980 TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT); 981 for (Pair<Object > i : saferCheck) { 982 if (matches(reference.template, i, false)) { 983 items.add((Pair<T>)i); 984 } 985 } 986 return Collections.unmodifiableCollection(items); 987 } 988 989 991 private Collection<Pair<T>> initItems(Storage<?> t) { 992 Enumeration<Pair<T>> en = t.lookup(reference.template.getType()); 994 995 TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT); 997 998 while (en.hasMoreElements()) { 999 Pair<T> i = en.nextElement(); 1000 1001 if (matches(reference.template, i, false)) { 1002 items.add(i); 1003 } 1004 } 1005 1006 setItemsCache(items); 1008 1009 return items; 1010 } 1011 1012 1014 protected void beforeLookup(Lookup.Template t) { 1015 if (t.getType() == reference.template.getType()) { 1016 reference.lookup.beforeLookup(t); 1017 } 1018 } 1019 1020 1025 public String toString() { 1026 return super.toString() + " for " + reference.template; 1027 } 1028 } 1029 1031 1037 public static class Content extends Object implements Serializable { 1038 private static final long serialVersionUID = 1L; 1039 1040 1042 1043 private AbstractLookup al = null; 1044 private transient ArrayList<Pair> earlyPairs; 1045 1046 1048 final synchronized void attach(AbstractLookup al) { 1049 if (this.al == null) { 1050 this.al = al; 1051 1052 if (earlyPairs != null) { 1053 for (Pair<?> p : earlyPairs) { 1055 addPair(p); 1056 } 1057 } 1058 1059 earlyPairs = null; 1060 } else { 1061 throw new IllegalStateException ( 1062 "Trying to use content for " + al + " but it is already used for " + this.al 1063 ); } 1065 } 1066 1067 1070 public final void addPair(Pair<?> pair) { 1071 AbstractLookup a = al; 1072 1073 if (a != null) { 1074 a.addPair(pair); 1075 } else { 1076 if (earlyPairs == null) { 1077 earlyPairs = new ArrayList<Pair>(3); 1078 } 1079 1080 earlyPairs.add(pair); 1081 } 1082 } 1083 1084 1087 public final void removePair(Pair<?> pair) { 1088 AbstractLookup a = al; 1089 1090 if (a != null) { 1091 a.removePair(pair); 1092 } else { 1093 if (earlyPairs == null) { 1094 earlyPairs = new ArrayList<Pair>(3); 1095 } 1096 1097 earlyPairs.remove(pair); 1098 } 1099 } 1100 1101 1104 public final void setPairs(Collection<? extends Pair> c) { 1105 AbstractLookup a = al; 1106 1107 if (a != null) { 1108 a.setPairs(c); 1109 } else { 1110 earlyPairs = new ArrayList<Pair>(c); 1111 } 1112 } 1113 } 1114 1116 1118 final static class Info extends Object { 1119 public int index; 1120 public Object transaction; 1121 1122 public Info(int i, Object t) { 1123 index = i; 1124 transaction = t; 1125 } 1126 } 1127 1128 1130 static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable { 1131 1132 private ReferenceToResult<?> next; 1133 1134 1135 public final Template<T> template; 1136 1137 1138 public final AbstractLookup lookup; 1139 1140 1141 public Object caches; 1142 1143 1146 private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) { 1147 super(result, activeQueue()); 1148 this.template = template; 1149 this.lookup = lookup; 1150 getResult().reference = this; 1151 } 1152 1153 1155 R<T> getResult() { 1156 return get(); 1157 } 1158 1159 1162 public void run() { 1163 lookup.cleanUpResult(this.template); 1164 } 1165 1166 1169 public void cloneList(AbstractLookup.Storage<?> storage) { 1170 ReferenceIterator it = new ReferenceIterator(this); 1171 1172 while (it.next()) { 1173 ReferenceToResult<?> current = it.current(); 1174 ReferenceToResult<?> newRef = current.cloneRef(); 1175 newRef.next = storage.registerReferenceToResult(newRef); 1176 newRef.caches = current.caches; 1177 1178 if (current.caches == current) { 1179 current.getResult().initItems(storage); 1180 } 1181 } 1182 } 1183 1184 private ReferenceToResult<T> cloneRef() { 1185 return new ReferenceToResult<T>(getResult(), lookup, template); 1186 } 1187 } 1188 1190 1199 static final class ReferenceIterator extends Object { 1200 private ReferenceToResult<?> first; 1201 private ReferenceToResult<?> current; 1202 1203 1204 private R<?> currentResult; 1205 1206 1208 public ReferenceIterator(ReferenceToResult<?> first) { 1209 this.first = first; 1210 } 1211 1212 1213 public boolean next() { 1214 ReferenceToResult<?> prev; 1215 ReferenceToResult<?> ref; 1216 1217 if (current == null) { 1218 ref = first; 1219 prev = null; 1220 } else { 1221 prev = current; 1222 ref = current.next; 1223 } 1224 1225 while (ref != null) { 1226 R<?> result = ref.get(); 1227 1228 if (result == null) { 1229 if (prev == null) { 1230 first = ref.next; 1232 } else { 1233 prev.next = ref.next; 1235 } 1236 1237 prev = ref; 1238 ref = ref.next; 1239 } else { 1240 currentResult = result; 1242 current = ref; 1243 1244 return true; 1245 } 1246 } 1247 1248 currentResult = null; 1249 current = null; 1250 1251 return false; 1252 } 1253 1254 1256 public ReferenceToResult<?> current() { 1257 return current; 1258 } 1259 1260 1262 public ReferenceToResult<?> first() { 1263 return first; 1264 } 1265 } 1266 1267 1271 static final class ISE extends IllegalStateException { 1272 1273 private java.util.List <Job> jobs; 1274 1275 1277 public ISE(String msg) { 1278 super(msg); 1279 } 1280 1281 1284 public void registerJob(Job job) { 1285 if (jobs == null) { 1286 jobs = new java.util.ArrayList <Job>(); 1287 } 1288 1289 jobs.add(job); 1290 } 1291 1292 1294 public void recover(AbstractLookup lookup) { 1295 if (jobs == null) { 1296 throw this; 1298 } 1299 1300 for (Job j : jobs) { 1301 j.before(); 1302 } 1303 1304 AbstractLookup.Storage s = lookup.enterStorage(); 1305 1306 try { 1307 for (Job j : jobs) { 1308 j.inside(); 1309 } 1310 } finally { 1311 lookup.exitStorage(); 1312 } 1313 } 1314 1315 1318 static interface Job { 1319 public void before(); 1320 1321 public void inside(); 1322 } 1323 } 1324 } 1326 | Popular Tags |