Package org.jboss.el.util

Source Code of org.jboss.el.util.ReferenceCache$SoftReferenceFactory

/*
* ReferenceMap.java
*
* Created on December 11, 2006, 9:58 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/

package org.jboss.el.util;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

/**
*
* @author jhook
*/
public abstract class ReferenceCache<K,V> {
   
  /*
   *
   */
    public abstract class ReferenceFactory<K,V> {
        public abstract ReferenceKey<K> createKey(ReferenceQueue queue, K key);
        public abstract ReferenceValue<V> createValue(ReferenceQueue queue, V value);
    }
   
    private class StrongReferenceFactory extends ReferenceFactory<K,V> {
        public ReferenceValue<V> createValue(ReferenceQueue queue, final V value) {
            return new ReferenceValue<V>() {
                public V get() {
                    return value;
                }
            };
        }
       
        public ReferenceKey<K> createKey(ReferenceQueue queue, final K key) {
            return new ReferenceKey<K>(key) {
                public K get() {
                    return key;
                }
            };
        }
    }
   
    private class WeakReferenceFactory extends ReferenceFactory<K,V> {
      private class WeakReferenceKey extends ReferenceKey<K> {
        private final WeakReference<K> ref;
       
        public WeakReferenceKey(final ReferenceQueue queue, final K key) {
          super(key);
          this.ref = new WeakReference<K>(key, queue) {
            public void clear() {
              remove();
              super.clear();
            }
          };
        }
       
        public K get() {
          return this.ref.get();
        }
      }
     
        public ReferenceValue<V> createValue(final ReferenceQueue queue, final V value) {
            return new ReferenceValue<V>() {
                private final WeakReference<V> ref = new WeakReference<V>(value, queue);
                public V get() {
                    return ref.get();
                }
            };
        }
       
        public ReferenceKey<K> createKey(ReferenceQueue queue, K key) {
            return new WeakReferenceKey(queue, key);
        }
    }
   
    private class SoftReferenceFactory extends ReferenceFactory<K,V> {
      private class SoftReferenceKey extends ReferenceKey<K> {
        private final SoftReference<K> ref;
       
        public SoftReferenceKey(final ReferenceQueue queue, final K key) {
          super(key);
          this.ref = new SoftReference<K>(key, queue) {
            public void clear() {
              remove();
              super.clear();
            }
          };
        }
       
        public K get() {
          return this.ref.get();
        }
      }
     
      public ReferenceValue<V> createValue(final ReferenceQueue queue, final V value) {
            return new ReferenceValue<V>() {
                private final SoftReference<V> ref = new SoftReference<V>(value, queue);
                public V get() {
                    return ref.get();
                }
            };
        }
       
        public ReferenceKey<K> createKey(final ReferenceQueue queue, final K key) {
            return new SoftReferenceKey(queue, key);
        }
    }
   
    public abstract class ReferenceKey<K> {
        private final int hashCode;
       
        public ReferenceKey(K key) {
            this.hashCode = key.hashCode();
        }
       
        protected abstract K get();
       
        public boolean equals(Object obj) {
          if (this == obj) return true;
            K me = this.get();
            if (me != null) {
                if (obj == me) return true;
                if (obj instanceof ReferenceKey) {
                    K them = ((ReferenceKey<K>) obj).get();
                    return me == them || me.equals(them);
                }
            }
            return false;
        }
       
        public void remove() {
          cache.remove(this);
        }
       
        public int hashCode() {
            return this.hashCode;
        }
    }
   
    public interface ReferenceValue<V> {
        public V get();
    }
   
    private class ReferenceQueueRunner extends ReferenceQueue implements Runnable {
        public void run() {
            Reference ref = null;
            while (true) {
                try {
                    ref = this.remove();
                    if (ref != null) {
                        ref.clear();
                    }
                } catch (InterruptedException e) {
                    //e.printStackTrace();
                }
            }
        }
    }
   
    private final ConcurrentMap<ReferenceKey<K>,Future<ReferenceValue<V>>> cache;
    private final ReferenceFactory keyFactory;
    private final ReferenceFactory valueFactory;
    private final ReferenceFactory lookupFactory;
    private final ReferenceQueueRunner queue;
   
    public static enum Type { Strong, Weak, Soft };
   
    /**
     * Creates a new instance of ReferenceMap
     */
    public ReferenceCache(Type keyType, Type valueType) {
        this(keyType, valueType, 0);
    }
   
    public ReferenceCache(Type keyType, Type valueType, int initialSize) {
        this.keyFactory = toFactory(keyType);
        this.valueFactory = toFactory(valueType);
        this.lookupFactory = new StrongReferenceFactory();
        this.cache = new ConcurrentHashMap<ReferenceKey<K>,Future<ReferenceValue<V>>>(initialSize);
        this.queue = new ReferenceQueueRunner();
        Thread t = new Thread(this.queue);
        t.setDaemon(true);
        t.start();
    }
   
    private final ReferenceFactory<K,V> toFactory(Type type) {
        switch (type) {
            case Strong : return new StrongReferenceFactory();
            case Weak : return new WeakReferenceFactory();
            case Soft : return new SoftReferenceFactory();
            default : throw new IllegalArgumentException("Invalid ReferenceType: " + type);
        }
    }
   
    protected abstract V create(K key);
   
    public V get(final Object key) {
        try {
            ReferenceKey<K> refKey = this.lookupFactory.createKey(this.queue, (K) key);
            Future<ReferenceValue<V>> f = this.cache.get(refKey);
            V value = dereferenceValue(f);
            if (value != null) {
              return value;
            } else {
                Callable<ReferenceValue<V>> call = new Callable() {
                    public ReferenceValue<V> call() throws Exception {
                        V created = create((K) key);
                        if (created != null) {
                            return valueFactory.createValue(queue, created);
                        } else {
                          throw new NullPointerException("Value created was Null");
                        }
                    }
                };
                FutureTask<ReferenceValue<V>> task = new FutureTask<ReferenceValue<V>>(call);
                refKey = this.keyFactory.createKey(this.queue, (K) key);
                f = this.cache.putIfAbsent(refKey, task);
                if (f == null) {
                    f = task;
                    task.run();
                }
               
                value = dereferenceValue(f);
                if (value == null) {
                  value = this.create((K) key);
                  this.put((K) key, value);
                }
                return value;
            }
        } catch (Exception e) {
            if (e instanceof RuntimeException) throw (RuntimeException) e;
            throw new IllegalStateException(e);
        }
    }
   
    private V dereferenceValue(ReferenceValue<V> refValue) {
        return refValue == null ? null : refValue.get();
    }
   
    private V dereferenceValue(Future<ReferenceValue<V>> futureValue) {
        try {
            return futureValue == null ? null : dereferenceValue(futureValue.get());
        } catch (Exception e) {
            return null;
        }
    }
   
    public V put(K key, final V value) {
        ReferenceKey refKey = this.keyFactory.createKey(this.queue, key);
        Callable<ReferenceValue<V>> call = new Callable() {
            public ReferenceValue<V> call() throws Exception {
                return valueFactory.createValue(queue, value);
            }
        };
        FutureTask<ReferenceValue<V>> task = new FutureTask<ReferenceValue<V>>(call);
        Future f = this.cache.putIfAbsent(refKey, task);
        if (f == null) {
            f = task;
            task.run();
        }
        return value;
    }
   
    public V remove(Object key) {
      ReferenceKey<K> keyRef = this.lookupFactory.createKey(this.queue, key);
        return this.dereferenceValue(this.cache.remove(keyRef));
    }
   
    public int size() {
      return this.cache.size();
    }
   
    public void clear() {
        this.cache.clear();
    }
}
TOP

Related Classes of org.jboss.el.util.ReferenceCache$SoftReferenceFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.