gw.util.cache.WeakFqnCache Maven / Gradle / Ivy
/*
* Copyright 2014 Guidewire Software, Inc.
*/
package gw.util.cache;
import gw.util.Predicate;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
*/
public class WeakFqnCache implements IFqnCache {
private FqnCache> _cache;
private ReferenceQueue _queue;
public WeakFqnCache() {
_cache = new FqnCache<>();
_queue = new ReferenceQueue();
}
@Override
public void add( String fqn ) {
add( fqn, null );
}
@Override
public void add( String fqn, T userData ) {
removeReleasedEntries();
KeyedReference ref = new KeyedReference( fqn, userData, _queue );
_cache.add( fqn, ref );
}
@Override
public boolean remove( String fqn ) {
removeReleasedEntries();
return _remove( fqn );
}
private boolean _remove( String fqn ) {
return _cache.remove( fqn );
}
@Override
public T get( String fqn ) {
WeakReference ref = _cache.get( fqn );
return ref == null ? null : ref.get();
}
@Override
public FqnCacheNode> getNode( String fqn ) {
return _cache.getNode( fqn );
}
@Override
public boolean contains( String fqn ) {
return _cache.contains( fqn );
}
@Override
public void remove( String[] fqns ) {
removeReleasedEntries();
_cache.remove( fqns );
}
@Override
public void clear() {
_cache.clear();
}
@Override
public Set getFqns() {
return _cache.getFqns();
}
@Override
public void visitDepthFirst( final Predicate visitor ) {
Predicate> delegate = new Predicate>() {
@Override
public boolean evaluate( WeakReference node ) {
T userData = node == null ? null : node.get();
return visitor.evaluate( userData );
}
};
List>> copy = new ArrayList>>( _cache.getRoot().getChildren() );
for( FqnCacheNode> child: copy ) {
if( !child.visitDepthFirst( delegate ) ) {
return;
}
}
}
public void visitNodeDepthFirst( final Predicate visitor ) {
List>> copy = new ArrayList>>( _cache.getRoot().getChildren() );
for( FqnCacheNode> child: copy ) {
if( !child.visitNodeDepthFirst( visitor ) ) {
return;
}
}
}
@Override
public void visitBreadthFirst( final Predicate visitor ) {
Predicate> delegate = new Predicate>() {
@Override
public boolean evaluate( WeakReference node ) {
T userData = node == null ? null : node.get();
return visitor.evaluate( userData );
}
};
List>> copy = new ArrayList>>( _cache.getRoot().getChildren() );
for( FqnCacheNode> child: copy ) {
child.visitBreadthFirst( delegate );
}
}
private static class KeyedReference extends WeakReference {
private String _fqn;
public KeyedReference( String fqn, T referent, ReferenceQueue super T> queue ) {
super( referent, queue );
_fqn = fqn;
}
public boolean equals( final Object o ) {
if( this == o ) {
return true;
}
if( o == null || getClass() != o.getClass() ) {
return false;
}
final KeyedReference that = (KeyedReference)o;
return _fqn.equals( that._fqn ) && equal( get(), that.get() );
}
private boolean equal( T p1, T 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 _fqn.hashCode();
}
}
private void removeReleasedEntries() {
while( true ) {
KeyedReference ref = (KeyedReference)_queue.poll();
if( ref == null ) {
break;
}
FqnCacheNode> node = getNode( ref._fqn );
if( node != null && node.isLeaf() && node.getUserData() == ref ) {
_remove( ref._fqn );
}
}
}
}