An attempt to make the result hold the data weak, but it does not work because of GC of template's class
1.1 --- a/openide.util/src/org/openide/util/lookup/ProxyLookup.java Tue Feb 05 17:53:22 2008 +0100
1.2 +++ b/openide.util/src/org/openide/util/lookup/ProxyLookup.java Tue Feb 05 19:43:00 2008 +0100
1.3 @@ -310,31 +310,22 @@
1.4 * that was found (not too useful) and also to all objects found
1.5 * (more useful).
1.6 */
1.7 - private final class R<T> extends WaitableResult<T> {
1.8 + private static final class R<T> extends WaitableResult<T> {
1.9 /** list of listeners added */
1.10 private javax.swing.event.EventListenerList listeners;
1.11
1.12 - /** template for this result */
1.13 - private final Lookup.Template<T> template;
1.14 -
1.15 /** collection of Objects */
1.16 private Collection[] cache;
1.17
1.18 /** weak listener & result */
1.19 private final WeakResult<T> weakL;
1.20 + private final Lookup.Template<T> template;
1.21
1.22 /** Constructor.
1.23 */
1.24 - public R(Lookup.Template<T> t) {
1.25 - template = t;
1.26 - weakL = new WeakResult<T>(this);
1.27 - }
1.28 -
1.29 - /** When garbage collected, remove the template from the has map.
1.30 - */
1.31 - @Override
1.32 - protected void finalize() {
1.33 - unregisterTemplate(template);
1.34 + public R(ProxyLookup proxy, Lookup.Template<T> t) {
1.35 + this.weakL = new WeakResult<T>(proxy, this);
1.36 + this.template = t;
1.37 }
1.38
1.39 @SuppressWarnings("unchecked")
1.40 @@ -347,11 +338,11 @@
1.41 private Result<T>[] initResults() {
1.42 BIG_LOOP: for (;;) {
1.43 Lookup[] myLkps;
1.44 - synchronized (ProxyLookup.this) {
1.45 + synchronized (weakL.getLock()) {
1.46 if (weakL.getResults() != null) {
1.47 return weakL.getResults();
1.48 }
1.49 - myLkps = getLookups(false);
1.50 + myLkps = weakL.getLookups(false);
1.51 }
1.52
1.53 Result<T>[] arr = newResults(myLkps.length);
1.54 @@ -360,8 +351,8 @@
1.55 arr[i] = myLkps[i].lookup(template);
1.56 }
1.57
1.58 - synchronized (ProxyLookup.this) {
1.59 - Lookup[] currentLkps = getLookups(false);
1.60 + synchronized (weakL.getLock()) {
1.61 + Lookup[] currentLkps = weakL.getLookups(false);
1.62 if (currentLkps.length != myLkps.length) {
1.63 continue BIG_LOOP;
1.64 }
1.65 @@ -397,7 +388,7 @@
1.66 Set<Lookup> added, Set<Lookup> removed, Lookup[] old, Lookup[] current,
1.67 Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
1.68 ) {
1.69 - synchronized (ProxyLookup.this) {
1.70 + synchronized (weakL.getLock()) {
1.71 if (weakL.getResults() == null) {
1.72 // not computed yet, do not need to do anything
1.73 return;
1.74 @@ -442,7 +433,7 @@
1.75 /** Just delegates.
1.76 */
1.77 public void addLookupListener(LookupListener l) {
1.78 - synchronized (ProxyLookup.this) {
1.79 + synchronized (weakL.getLock()) {
1.80 if (listeners == null) {
1.81 listeners = new EventListenerList();
1.82 }
1.83 @@ -496,7 +487,7 @@
1.84 Lookup.Result<T>[] arr = myBeforeLookup();
1.85
1.86 // if the call to beforeLookup resulted in deletion of caches
1.87 - synchronized (ProxyLookup.this) {
1.88 + synchronized (weakL.getLock()) {
1.89 if (getCache() != null) {
1.90 Collection result = getCache()[indexToCache];
1.91 if (result != null) {
1.92 @@ -538,7 +529,7 @@
1.93
1.94
1.95
1.96 - synchronized (ProxyLookup.this) {
1.97 + synchronized (weakL.getLock()) {
1.98 if (getCache() == null) {
1.99 // initialize the cache to indicate this result is in use
1.100 setCache(new Collection[3]);
1.101 @@ -564,7 +555,7 @@
1.102 // clear cached instances
1.103 Collection oldItems;
1.104 Collection oldInstances;
1.105 - synchronized (ProxyLookup.this) {
1.106 + synchronized (weakL.getLock()) {
1.107 if (getCache() == null) {
1.108 // nobody queried the result yet
1.109 return;
1.110 @@ -598,7 +589,7 @@
1.111 modified = false;
1.112 }
1.113 } else {
1.114 - synchronized (ProxyLookup.this) {
1.115 + synchronized (weakL.getLock()) {
1.116 if (getCache() == null) {
1.117 // we have to initialize the cache
1.118 // to show that the result has been initialized
1.119 @@ -618,7 +609,7 @@
1.120 * @return results to work on.
1.121 */
1.122 private Lookup.Result<T>[] myBeforeLookup() {
1.123 - ProxyLookup.this.beforeLookup(template);
1.124 + weakL.proxyBefore(template);
1.125
1.126 Lookup.Result<T>[] arr = initResults();
1.127
1.128 @@ -646,7 +637,7 @@
1.129 }
1.130
1.131 private void setCache(Collection[] cache) {
1.132 - assert Thread.holdsLock(ProxyLookup.this);
1.133 + assert Thread.holdsLock(weakL.getLock());
1.134 this.cache = cache;
1.135 }
1.136 }
1.137 @@ -656,8 +647,11 @@
1.138
1.139 private final Reference<R> result;
1.140
1.141 - public WeakResult(R r) {
1.142 - this.result = new WeakReference<R>(r);//, Utilities.activeReferenceQueue());
1.143 + private final Reference<ProxyLookup> proxy;
1.144 +
1.145 + public WeakResult(ProxyLookup proxy, R r) {
1.146 + this.result = new RefR(r, this);
1.147 + this.proxy = new WeakReference<ProxyLookup>(proxy);
1.148 }
1.149
1.150 protected void beforeLookup(Lookup.Template t) {
1.151 @@ -668,8 +662,44 @@
1.152 removeListeners();
1.153 }
1.154 }
1.155 +
1.156 + final void unregisterTemplate() {
1.157 + ProxyLookup p = proxy.get();
1.158 + R r = result.get();
1.159 + Lookup.Template<T> template = r == null ? null : r.template;
1.160 + if (p != null && template != null) {
1.161 + p.unregisterTemplate(template);
1.162 + }
1.163 + }
1.164 +
1.165 + final void proxyBefore(Template template) {
1.166 + ProxyLookup p = proxy.get();
1.167 + if (p != null) {
1.168 + p.beforeLookup(template);
1.169 + }
1.170 + }
1.171
1.172 - private void removeListeners() {
1.173 + final Object getLock() {
1.174 + ProxyLookup p = proxy.get();
1.175 + if (p != null) {
1.176 + return p;
1.177 + } else {
1.178 + // some fallback to lock on that will not change once the ProxyLookup is GCed
1.179 + return EMPTY_ARR;
1.180 + }
1.181 + }
1.182 +
1.183 + final Lookup[] getLookups(boolean clone) {
1.184 + ProxyLookup p = proxy.get();
1.185 + if (p != null) {
1.186 + return p.getLookups(clone);
1.187 + } else {
1.188 + return EMPTY_ARR;
1.189 + }
1.190 + }
1.191 +
1.192 +
1.193 + final void removeListeners() {
1.194 Lookup.Result<T>[] arr = this.getResults();
1.195 if (arr == null) {
1.196 return;
1.197 @@ -782,10 +812,22 @@
1.198 res = new HashMap<Template<?>, Reference<R>>(oldAndNew[0].results);
1.199 }
1.200
1.201 - R<T> newR = proxy.new R<T>(template);
1.202 + R<T> newR = new R<T>(proxy, template);
1.203 res.put(template, new java.lang.ref.SoftReference<R>(newR));
1.204 oldAndNew[0] = new ImmutableInternalData(res);
1.205 return newR;
1.206 }
1.207 }
1.208 +
1.209 + private static final class RefR extends WeakReference<R> implements Runnable {
1.210 + private WeakResult weakL;
1.211 + public RefR(R r, WeakResult weakL) {
1.212 + super(r, Utilities.activeReferenceQueue());
1.213 + this.weakL = weakL;
1.214 + }
1.215 +
1.216 + public void run() {
1.217 + weakL.unregisterTemplate();
1.218 + }
1.219 + }
1.220 }
2.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Tue Feb 05 17:53:22 2008 +0100
2.2 +++ b/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Tue Feb 05 19:43:00 2008 +0100
2.3 @@ -100,7 +100,7 @@
2.4
2.5 Lookup.Result<Object> res = lookup.lookup (template);
2.6
2.7 - assertSize("Bigger", Collections.singleton(lookup), 336, IGNORE);
2.8 + assertSize("Bigger", Collections.singleton(lookup), 368, IGNORE);
2.9
2.10 LL ll = new LL ();
2.11 res.addLookupListener (ll);