#104806: Additional fix, by making the ExcludingLookup result listening using a weak listener
1.1 --- a/openide.util/src/org/openide/util/lookup/ExcludingLookup.java Wed Aug 15 12:13:23 2007 +0000
1.2 +++ b/openide.util/src/org/openide/util/lookup/ExcludingLookup.java Fri Aug 17 20:13:12 2007 +0000
1.3 @@ -18,10 +18,13 @@
1.4 */
1.5 package org.openide.util.lookup;
1.6
1.7 +import java.lang.ref.Reference;
1.8 +import java.lang.ref.WeakReference;
1.9 import org.openide.util.Lookup;
1.10 import org.openide.util.LookupListener;
1.11
1.12 import java.util.*;
1.13 +import org.openide.util.LookupEvent;
1.14
1.15
1.16 /** Allows exclusion of certain instances from lookup.
1.17 @@ -49,6 +52,7 @@
1.18 }
1.19 }
1.20
1.21 + @Override
1.22 public String toString() {
1.23 return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
1.24 }
1.25 @@ -80,6 +84,7 @@
1.26 }
1.27 }
1.28
1.29 + @Override
1.30 public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
1.31 if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
1.32 return null;
1.33 @@ -244,12 +249,14 @@
1.34 */
1.35 private final class R<T> extends WaitableResult<T> implements LookupListener {
1.36 private Result<T> result;
1.37 + private WeakResult<T> weak;
1.38 private Object listeners;
1.39 private Class<?> from;
1.40
1.41 R(Class<?> from, Result<T> delegate) {
1.42 this.from = from;
1.43 this.result = delegate;
1.44 + this.weak = new WeakResult<T>(this, delegate);
1.45 }
1.46
1.47 protected void beforeLookup(Template t) {
1.48 @@ -267,7 +274,7 @@
1.49 }
1.50
1.51 if (add) {
1.52 - result.addLookupListener(this);
1.53 + result.addLookupListener(weak);
1.54 }
1.55 }
1.56
1.57 @@ -280,7 +287,7 @@
1.58 }
1.59
1.60 if (remove) {
1.61 - result.removeLookupListener(this);
1.62 + result.removeLookupListener(weak);
1.63 }
1.64 }
1.65
1.66 @@ -292,10 +299,12 @@
1.67 return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
1.68 }
1.69
1.70 + @Override
1.71 public Set<Class<? extends T>> allClasses() {
1.72 return filter(classes(), from, result.allClasses(), 1, new HashSet<Class<? extends T>>());
1.73 }
1.74
1.75 + @Override
1.76 public Collection<? extends Item<T>> allItems() {
1.77 return openCol(result.allItems(), 2);
1.78 }
1.79 @@ -326,5 +335,67 @@
1.80 final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
1.81 AbstractLookup.notifyListeners(ll, newev, evAndListeners);
1.82 }
1.83 - }
1.84 + } // end of R
1.85 +
1.86 + private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
1.87 + private Lookup.Result source;
1.88 + private Reference<R<T>> result;
1.89 +
1.90 + public WeakResult(R<T> r, Lookup.Result<T> s) {
1.91 + this.result = new WeakReference<R<T>>(r);
1.92 + this.source = s;
1.93 + }
1.94 +
1.95 + protected void beforeLookup(Lookup.Template t) {
1.96 + R r = (R)result.get();
1.97 + if (r != null) {
1.98 + r.beforeLookup(t);
1.99 + } else {
1.100 + source.removeLookupListener(this);
1.101 + }
1.102 + }
1.103 +
1.104 + protected void collectFires(Collection<Object> evAndListeners) {
1.105 + R<T> r = result.get();
1.106 + if (r != null) {
1.107 + r.collectFires(evAndListeners);
1.108 + } else {
1.109 + source.removeLookupListener(this);
1.110 + }
1.111 + }
1.112 +
1.113 + public void addLookupListener(LookupListener l) {
1.114 + assert false;
1.115 + }
1.116 +
1.117 + public void removeLookupListener(LookupListener l) {
1.118 + assert false;
1.119 + }
1.120 +
1.121 + public Collection<T> allInstances() {
1.122 + assert false;
1.123 + return null;
1.124 + }
1.125 +
1.126 + public void resultChanged(LookupEvent ev) {
1.127 + R r = (R)result.get();
1.128 + if (r != null) {
1.129 + r.resultChanged(ev);
1.130 + } else {
1.131 + source.removeLookupListener(this);
1.132 + }
1.133 + }
1.134 +
1.135 + @Override
1.136 + public Collection<? extends Item<T>> allItems() {
1.137 + assert false;
1.138 + return null;
1.139 + }
1.140 +
1.141 + @Override
1.142 + public Set<Class<? extends T>> allClasses() {
1.143 + assert false;
1.144 + return null;
1.145 + }
1.146 + } // end of WeakResult
1.147 }
2.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java Wed Aug 15 12:13:23 2007 +0000
2.2 +++ b/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java Fri Aug 17 20:13:12 2007 +0000
2.3 @@ -28,6 +28,7 @@
2.4 import junit.framework.*;
2.5 import org.netbeans.junit.*;
2.6 import java.io.Serializable;
2.7 +import java.lang.ref.Reference;
2.8 import org.openide.util.Lookup.Template;
2.9
2.10 public class AbstractLookupBaseHid extends NbTestCase {
2.11 @@ -1567,10 +1568,46 @@
2.12 Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
2.13 assertTrue("It is empty: " + c, c.isEmpty());
2.14 }
2.15 +
2.16 + public void testCanGCResults() throws Exception {
2.17 + class L implements LookupListener {
2.18 + int cnt;
2.19 +
2.20 + public void resultChanged(LookupEvent ev) {
2.21 + cnt++;
2.22 + }
2.23 +
2.24 + }
2.25 + L listener1 = new L();
2.26 + L listener2 = new L();
2.27 +
2.28 + Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
2.29 + Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
2.30 +
2.31 + assertEquals("Empty1", 0, res1.allItems().size());
2.32 + assertEquals("Empty2", 0, res2.allItems().size());
2.33 +
2.34 + res1.addLookupListener(listener1);
2.35 + res2.addLookupListener(listener2);
2.36 +
2.37 + addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
2.38 + this.ic.add("Ahoj");
2.39 +
2.40 + assertEquals("Change1", 1, listener1.cnt);
2.41 + assertEquals("Change2", 1, listener2.cnt);
2.42 +
2.43 + assertEquals("Full1", 1, res1.allItems().size());
2.44 + assertEquals("Full2", 1, res2.allItems().size());
2.45 +
2.46 +
2.47 + Reference<Object> ref2 = new WeakReference<Object>(res2);
2.48 + res2 = null;
2.49 + assertGC("Result can disappear", ref2);
2.50 + }
2.51
2.52 /** Adds instances to the instance lookup.
2.53 */
2.54 - private void addInstances (Object[] instances) {
2.55 + private void addInstances (Object... instances) {
2.56 for (int i = 0; i < instances.length; i++) {
2.57 ic.add(instances[i]);
2.58 }