An attempt to make the result hold the data weak, but it does not work because of GC of template's class weak_proxy_lookup_but_does_not_GC_template_and_its_class
authorJaroslav Tulach <jtulach@netbeans.org>
Tue, 05 Feb 2008 19:43:00 +0100
branchweak_proxy_lookup_but_does_not_GC_template_and_its_class
changeset 340c059ff4c4133
parent 326 00a401f0f875
child 341 29bbadcb8e5f
An attempt to make the result hold the data weak, but it does not work because of GC of template's class
openide.util/src/org/openide/util/lookup/ProxyLookup.java
openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java
     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);