openide.util/src/org/openide/util/lookup/ProxyLookup.java
branchweak_proxy_lookup_but_does_not_GC_template_and_its_class
changeset 340 c059ff4c4133
parent 326 00a401f0f875
child 341 29bbadcb8e5f
     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  }