Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
   *
   * Copyright (c) 2013-2014 sagyf Yang. The Four Group.
   */
  
  package com.github.sog.controller.session.ref;
  
 
 import java.util.Map;
 import java.util.Set;
 
 import static com.github.sog.controller.session.ref.ReferenceType.STRONG;

.

Author(s):
sagyf yang
Version:
1.0 2014-01-31 2:06
Since:
JDK 1.6
 
 public class ReferenceMap<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {
 
     protected final ReferenceType keyReferenceType;
     protected final ReferenceType valueReferenceType;
     protected transient ConcurrentMap<ObjectObjectdelegate;
     private volatile Set<Map.Entry<K, V>> entrySet;
 
     // ---------------------------------------------------------------- map implementations
 
    
Concurrent hash map that wraps keys and/or values based on specified reference types.

Parameters:
keyReferenceType key reference type
valueReferenceType value reference type
 
     public ReferenceMap(ReferenceType keyReferenceTypeReferenceType valueReferenceType) {
         if ((keyReferenceType == null) || (valueReferenceType == null)) {
             throw new IllegalArgumentException("References types can not be null");
         }
         if (keyReferenceType == . || valueReferenceType == .) {
             throw new IllegalArgumentException("Phantom references not supported");
         }
         this. = new ConcurrentHashMap<ObjectObject>();
         this. = keyReferenceType;
         this. = valueReferenceType;
     }

    
Tests weak and soft references for identity equality. Compares references to other references and wrappers. If o is a reference, this returns true if r == o or if r and o reference the same non-null object. If o is a wrapper, this returns true if r's referent is identical to the wrapped object.
 
     private static boolean referenceEquals(Reference rObject o) {
         if (o instanceof InternalReference) {   // compare reference to reference.
             if (o == r) {       // are they the same reference? used in cleanup.
                 return true;
             }
             Object referent = ((Referenceo).get();    // do they reference identical values? used in conditional puts.
             return referent != null && referent == r.get();
         }
         return ((ReferenceAwareWrappero).unwrap() == r.get();     // is the wrapped object identical to the referent? used in lookups.
     }

    
Returns true if the specified value reference has been garbage collected. The value behind the reference is also passed in, rather than queried inside this method, to ensure that the return statement of this method will still hold true after it has returned (that is, a value reference exists outside of this method which will prevent that value from being garbage collected).

Parameters:
valueReference the value reference to be tested
value the object referenced by valueReference
Returns:
true if valueReference is non-null and value is null
 
     private static boolean isExpired(Object valueReferenceObject value) {
         return (valueReference != null) && (value == null);
     }
 
     @Override
     public V get(final Object key) {
         Object referenceAwareKey = makeKeyReferenceAware(key);
         Object valueReference = .get(referenceAwareKey);
        return dereferenceValue(valueReference);
    }
    @Override
    public V put(K key, V value) {
        Object referenceKey = referenceKey(key);
        Object referenceValue = referenceValue(referenceKeyvalue);
        return dereferenceValue(.put(referenceKeyreferenceValue));
        //return (V) PutStrategy.PUT.execute(this, referenceKey, referenceValue);
    }
    @Override
    public V remove(Object key) {
        Object referenceAwareKey = makeKeyReferenceAware(key);
        Object valueReference = .remove(referenceAwareKey);
        return dereferenceValue(valueReference);
    }
    @Override
    public int size() {
        return .size();
    }
    @Override
    public boolean isEmpty() {
        return .isEmpty();
    }
    @Override
    public boolean containsKey(Object key) {
        Object referenceAwareKey = makeKeyReferenceAware(key);
        return .containsKey(referenceAwareKey);
    }
    @Override
    public boolean containsValue(Object value) {
        for (Object valueReference : .values()) {
            if (value.equals(dereferenceValue(valueReference))) {
                return true;
            }
        }
        return false;
    }
    @Override
    public void putAll(Map<? extends K, ? extends V> t) {
        for (Map.Entry<? extends K, ? extends V> entry : t.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
    }
    @Override
    public void clear() {
        .clear();
    }
    public V putIfAbsent(K key, V value) {
        Object referenceKey = referenceKey(key);
        Object referenceValue = referenceValue(referenceKeyvalue);
        Object existingValueReference;
        Object existingValue;
        do {
            existingValueReference = .putIfAbsent(referenceKeyreferenceValue);
            existingValue = dereferenceValue(existingValueReference);
        } while (isExpired(existingValueReferenceexistingValue));
        return (V) existingValue;
        //return (V) PutStrategy.PUT_IF_ABSENT.execute(this, referenceKey, referenceValue);
    }
    // ---------------------------------------------------------------- conversions
    public boolean remove(Object keyObject value) {
        return .remove(makeKeyReferenceAware(key), makeValueReferenceAware(value));
    }
    public boolean replace(K key, V oldValue, V newValue) {
        Object keyReference = referenceKey(key);
        Object referenceAwareOldValue = makeValueReferenceAware(oldValue);
        return .replace(keyReferencereferenceAwareOldValuereferenceValue(keyReferencenewValue));
    }
    public V replace(K key, V value) {
        Object referenceKey = referenceKey(key);
        Object referenceValue = referenceValue(referenceKeyvalue);
        // ensure that the existing value is not collected
        do {
            Object existingValueReference;
            Object existingValue;
            do {
                existingValueReference = .get(referenceKey);
                existingValue = dereferenceValue(existingValueReference);
            } while (isExpired(existingValueReferenceexistingValue));
            if (existingValueReference == null) {
                return (V) Boolean.valueOf(false);  // nothing to replace
            }
            if (.replace(referenceKeyexistingValueReferencereferenceValue)) {
                return (V) existingValue;       // existingValue did not expire since we still have a reference to it
            }
        } while (true);
        //return (V) PutStrategy.REPLACE.execute(this, referenceKey, referenceValue);
    }

    
Dereferences an entry. Returns null if the key or value has been gc'ed.
        K key = dereferenceKey(entry.getKey());
        V value = dereferenceValue(entry.getValue());
        return (key == null || value == null) ? null : new Entry(keyvalue);
    }

    
Creates a reference for a key.
    Object referenceKey(K key) {
        switch () {
            case :
                return key;
            case :
                return new SoftKeyReference(key);
            case :
                return new WeakKeyReference(key);
            default:
                throw new AssertionError();
        }
    }

    
Converts a reference to a key.
    K dereferenceKey(Object o) {
        return (K) dereference(o);
    }

    
Converts a reference to a value.
    V dereferenceValue(Object o) {
        if (o == null) {
            return null;
        }
        Object value = dereference(o);
        if (o instanceof InternalReference) {
            InternalReference reference = (InternalReferenceo;
            if (value == null) {
                reference.finalizeReferent();     // old value was garbage collected
            }
        }
        return (V) value;
    }

    
Returns the refererent for reference given its reference type.
    private Object dereference(ReferenceType referenceTypeObject reference) {
        return referenceType ==  ? reference : ((Referencereference).get();
    }
    // ---------------------------------------------------------------- inner classes

    
Creates a reference for a value.
    Object referenceValue(Object keyReferenceObject value) {
        switch () {
            case :
                return value;
            case :
                return new SoftValueReference(keyReferencevalue);
            case :
                return new WeakValueReference(keyReferencevalue);
            default:
                throw new AssertionError();
        }
    }

    
Wraps key so it can be compared to a referenced key for equality.
    private Object makeKeyReferenceAware(Object o) {
        return  ==  ? o : new KeyReferenceAwareWrapper(o);
    }

    
Wraps value so it can be compared to a referenced value for equality.
    private Object makeValueReferenceAware(Object o) {
        return  ==  ? o : new ReferenceAwareWrapper(o);
    }
    @Override
    public Set<Map.Entry<K, V>> entrySet() {
        if ( == null) {
             = new EntrySet();
        }
        return ;
    }

    
Marker interface to differentiate external and internal references. Also duplicates FinalizableReference and Reference.get for internal use.
    interface InternalReference {
        
Invoked on a background thread after the referent has been garbage collected.
        void finalizeReferent();
        Object get();
    }

    
Big hack. Used to compare keys and values to referenced keys and values without creating more references.
    static class ReferenceAwareWrapper {
        final Object wrapped;
        ReferenceAwareWrapper(Object wrapped) {
            this. = wrapped;
        }
        Object unwrap() {
            return ;
        }
        @Override
        public int hashCode() {
            return .hashCode();
        }
        @Override
        public boolean equals(Object obj) {
            return obj.equals(this);    // defer to references equals() logic.
        }
    }

    
Used for keys. Overrides hash code to use identity hash code.
    static class KeyReferenceAwareWrapper extends ReferenceAwareWrapper {
        KeyReferenceAwareWrapper(Object wrapped) {
            super(wrapped);
        }
        @Override
        public int hashCode() {
            return System.identityHashCode();
        }
    }
    static class FinalizableReferenceQueue extends ReferenceQueue<Object> {
        static final ReferenceQueue<Objectinstance = createAndStart();
        private FinalizableReferenceQueue() {
        }
        static FinalizableReferenceQueue createAndStart() {
            FinalizableReferenceQueue queue = new FinalizableReferenceQueue();
            queue.start();
            return queue;
        }

        
Gets instance.
        public static ReferenceQueue<ObjectgetInstance() {
            return ;
        }
        void cleanUp(Reference reference) {
            try {
                ((InternalReferencereference).finalizeReferent();
            } catch (Throwable t) {
                throw new IllegalStateException("Clean up after reference error"t);
            }
        }
        void start() {
            Thread thread = new Thread("FinalizableReferenceQueue") {
                @Override
                @SuppressWarnings({"InfiniteLoopStatement"})
                public void run() {
                    while (true) {
                        try {
                            cleanUp(remove());
                        } catch (InterruptedException iex) { /* ignore */ }
                    }
                }
            };
            thread.setDaemon(true);
            thread.start();
        }
    }
    class SoftKeyReference extends SoftReference<Objectimplements InternalReference {
        final int hashCode;
        SoftKeyReference(Object key) {
            super(key, FinalizableReferenceQueue.getInstance());
            this. = System.identityHashCode(key);
        }
        public void finalizeReferent() {
            .remove(this);
        }
        @Override
        public int hashCode() {
            return this.;
        }
        @Override
        public boolean equals(Object o) {
            return referenceEquals(thiso);
        }
    }
    class WeakKeyReference extends WeakReference<Objectimplements InternalReference {
        final int hashCode;
        WeakKeyReference(Object key) {
            super(key, FinalizableReferenceQueue.getInstance());
            this. = System.identityHashCode(key);
        }
        public void finalizeReferent() {
            .remove(this);
        }
        @Override
        public int hashCode() {
            return this.;
        }
        @Override
        public boolean equals(Object o) {
            return referenceEquals(thiso);
        }
    }
    // ---------------------------------------------------------------- map entry set
    class SoftValueReference extends SoftReference<Objectimplements InternalReference {
        final Object keyReference;
        SoftValueReference(Object keyReferenceObject value) {
            super(value, FinalizableReferenceQueue.getInstance());
            this. = keyReference;
        }
        public void finalizeReferent() {
            .remove(this);
        }
        @Override
        public boolean equals(Object obj) {
            return referenceEquals(thisobj);
        }
    }
    class WeakValueReference extends WeakReference<Objectimplements InternalReference {
        final Object keyReference;
        WeakValueReference(Object keyReferenceObject value) {
            super(value, FinalizableReferenceQueue.getInstance());
            this. = keyReference;
        }
        public void finalizeReferent() {
            .remove(this);
        }
        @Override
        public boolean equals(Object obj) {
            return referenceEquals(thisobj);
        }
    }
    class Entry implements Map.Entry<K, V> {
        final K key;
        V value;
        Entry(K key, V value) {
            this. = key;
            this. = value;
        }
        public K getKey() {
            return this.;
        }
        public V getValue() {
            return this.;
        }
        public V setValue(V newValue) {
             = newValue;
            return put(newValue);
        }
        @Override
        public int hashCode() {
            return .hashCode() * 31 + .hashCode();
        }
        @Override
        public boolean equals(Object o) {
            if (!(o instanceof ReferenceMap.Entry)) {
                return false;
            }
            Entry entry = (Entryo;
            return .equals(entry.key) && .equals(entry.value);
        }
        @Override
        public String toString() {
            return  + . + ;
        }
    }
    private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
        @Override
        public Iterator<Map.Entry<K, V>> iterator() {
            return new ReferenceIterator();
        }
        @Override
        public int size() {
            return .size();
        }
        @Override
        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry)) {
                return false;
            }
            Map.Entry<K, V> e = (Map.Entry<K, V>) o;
            V v = ReferenceMap.this.get(e.getKey());
            return v != null && v.equals(e.getValue());
        }
        @Override
        public boolean remove(Object o) {
            if (!(o instanceof Map.Entry)) {
                return false;
            }
            Map.Entry<K, V> e = (Map.Entry<K, V>) o;
            return ReferenceMap.this.remove(e.getKey(), e.getValue());
        }
        @Override
        public void clear() {
            .clear();
        }
    }
    private class ReferenceIterator implements Iterator<Map.Entry<K, V>> {
        private Iterator<Map.Entry<ObjectObject>> i = .entrySet().iterator();
        private Map.Entry<K, V> nextEntry;
        private Map.Entry<K, V> lastReturned;
        private ReferenceIterator() {
            advanceToNext();
        }
        private void advanceToNext() {
            while (.hasNext()) {
                Map.Entry<K, V> entry = dereferenceEntry(.next());
                if (entry != null) {
                     = entry;
                    return;
                }
            }
             = null;
        }
        public boolean hasNext() {
            return  != null;
        }
        public Map.Entry<K, V> next() {
            if ( == null) {
                throw new NoSuchElementException();
            }
             = ;
            advanceToNext();
            return ;
        }
        public void remove() {
            ReferenceMap.this.remove(.getKey());
        }
    }
New to GrepCode? Check out our FAQ X