All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gw.util.concurrent.ConcurrentWeakValueHashMap Maven / Gradle / Ivy

There is a newer version: 1.18.2
Show newest version
/*
 * Copyright 2014 Guidewire Software, Inc.
 */

package gw.util.concurrent;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Adapted from com.intellij.util.containers.ConcurrentWeakValueHashMap
 */
public final class ConcurrentWeakValueHashMap implements ConcurrentMap {
  private final ConcurrentHashMap> myMap;
  private final ReferenceQueue myQueue = new ReferenceQueue();

  public ConcurrentWeakValueHashMap( final Map map ) {
    this();
    putAll( map );
  }

  public ConcurrentWeakValueHashMap() {
    myMap = new ConcurrentHashMap>();
  }

  public ConcurrentWeakValueHashMap( int initialCapacity ) {
    myMap = new ConcurrentHashMap>( initialCapacity );
  }

  public ConcurrentWeakValueHashMap( int initialCapaciy, float loadFactor, int concurrenycLevel ) {
    myMap = new ConcurrentHashMap>( initialCapaciy, loadFactor, concurrenycLevel );
  }

  private static class MyReference extends WeakReference {
    private final K key;

    public MyReference( K key, T referent, ReferenceQueue q ) {
      super( referent, q );
      this.key = key;
    }

    public boolean equals( final Object o ) {
      if( this == o ) {
        return true;
      }
      if( o == null || getClass() != o.getClass() ) {
        return false;
      }

      final MyReference that = (MyReference)o;

      return key.equals( that.key ) && areEqual( get(), that.get() );
    }

    private boolean areEqual( Object p1, Object p2 ) {
      if( p1 == null || p2 == null ) {
        return p1 == p2;
      }
      else if( p1 instanceof Object[] && p2 instanceof Object[] ) {
        Object[] arr1 = (Object[])p1;
        Object[] arr2 = (Object[])p2;
        return Arrays.equals( arr1, arr2 );
      }
      else {
        return p1.equals( p2 );
      }
    }
    
    public int hashCode() {
      return key.hashCode();
    }
  }

  private void processQueue() {
    while( true ) {
      MyReference ref = (MyReference)myQueue.poll();
      if( ref == null ) {
        break;
      }
      if( myMap.get( ref.key ) == ref ) {
        myMap.remove( ref.key );
      }
    }
  }

  public V get( Object key ) {
    MyReference ref = myMap.get( key );
    if( ref == null ) {
      return null;
    }
    return ref.get();
  }

  public V put( K key, V value ) {
    processQueue();
    MyReference oldRef = myMap.put( key, createRef( key, value ) );
    return oldRef != null ? oldRef.get() : null;
  }

  private MyReference createRef( K key, V value ) {
    return new MyReference( key, value, myQueue );
  }

  public V putIfAbsent( K key, V value ) {
    while( true ) {
      processQueue();
      MyReference newRef = createRef( key, value );
      MyReference oldRef = myMap.putIfAbsent( key, newRef );
      if( oldRef == null ) {
        return null;
      }
      final V oldVal = oldRef.get();
      if( oldVal == null ) {
        if( myMap.replace( key, oldRef, newRef ) ) {
          return null;
        }
      }
      else {
        return oldVal;
      }
    }
  }

  public boolean remove( final Object key, final Object value ) {
    processQueue();
    return myMap.remove( key, createRef( (K)key, (V)value ) );
  }

  public boolean replace( final K key, final V oldValue, final V newValue ) {
    processQueue();
    return myMap.replace( key, createRef( key, oldValue ), createRef( key, newValue ) );
  }

  public V replace( final K key, final V value ) {
    processQueue();
    MyReference ref = myMap.replace( key, createRef( key, value ) );
    return ref == null ? null : ref.get();
  }

  public V remove( Object key ) {
    processQueue();
    MyReference ref = myMap.remove( key );
    return ref != null ? ref.get() : null;
  }

  public void putAll( Map t ) {
    processQueue();
    for( K k : t.keySet() ) {
      V v = t.get( k );
      if( v != null ) {
        put( k, v );
      }
    }
  }

  public void clear() {
    myMap.clear();
    processQueue();
  }

  public int size() {
    return myMap.size(); //?
  }

  public boolean isEmpty() {
    return myMap.isEmpty(); //?
  }

  public boolean containsKey( Object key ) {
    return get( key ) != null;
  }

  public boolean containsValue( Object value ) {
    throw new RuntimeException( "method not implemented" );
  }

  public Set keySet() {
    return myMap.keySet();
  }

  public Collection values() {
    List result = new ArrayList();
    final Collection> refs = myMap.values();
    for( MyReference ref : refs ) {
      final V value = ref.get();
      if( value != null ) {
        result.add( value );
      }
    }
    return result;
  }

  public Set> entrySet() {
    final Set keys = keySet();
    Set> entries = new HashSet>();

    for( final K key : keys ) {
      final V value = get( key );
      if( value != null ) {
        entries.add( new Entry() {
          public K getKey() {
            return key;
          }

          public V getValue() {
            return value;
          }

          public V setValue( V value ) {
            throw new UnsupportedOperationException( "setValue is not implemented" );
          }
        } );
      }
    }

    return entries;
  }

  @Override
  public String toString() {
    String s = "ConcurrentWeakValueHashMap size:" + size() + " [";
    for( K k : myMap.keySet() ) {
      Object v = get( k );
      s += "'" + k + "': '" + v + "', ";
    }
    s += "] ";
    return s;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy