/* * Copyright 2013 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<T> implements IFqnCache<T> { private FqnCache<WeakReference<T>> _cache; private ReferenceQueue<T> _queue; public WeakFqnCache() { _cache = new FqnCache<WeakReference<T>>(); _queue = new ReferenceQueue<T>(); } @Override public void add( String fqn ) { add( fqn, null ); } @Override public void add( String fqn, T userData ) { // removeReleasedEntries(); KeyedReference<T> ref = new KeyedReference<T>( 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<T> ref = _cache.get( fqn ); return ref == null ? null : ref.get(); } @Override public FqnCacheNode<WeakReference<T>> 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<String> getFqns() { return _cache.getFqns(); } @Override public void visitDepthFirst( final Predicate<T> visitor ) { Predicate<WeakReference<T>> delegate = new Predicate<WeakReference<T>>() { @Override public boolean evaluate( WeakReference<T> node ) { T userData = node == null ? null : node.get(); return visitor.evaluate( userData ); } }; List<FqnCacheNode<WeakReference<T>>> copy = new ArrayList<FqnCacheNode<WeakReference<T>>>( _cache.getRoot().getChildren() ); for( FqnCacheNode<WeakReference<T>> child: copy ) { if( !child.visitDepthFirst( delegate ) ) { return; } } } public void visitNodeDepthFirst( final Predicate<FqnCacheNode> visitor ) { List<FqnCacheNode<WeakReference<T>>> copy = new ArrayList<FqnCacheNode<WeakReference<T>>>( _cache.getRoot().getChildren() ); for( FqnCacheNode<WeakReference<T>> child: copy ) { if( !child.visitNodeDepthFirst( visitor ) ) { return; } } } @Override public void visitBreadthFirst( final Predicate<T> visitor ) { Predicate<WeakReference<T>> delegate = new Predicate<WeakReference<T>>() { @Override public boolean evaluate( WeakReference<T> node ) { T userData = node == null ? null : node.get(); return visitor.evaluate( userData ); } }; List<FqnCacheNode<WeakReference<T>>> copy = new ArrayList<FqnCacheNode<WeakReference<T>>>( _cache.getRoot().getChildren() ); for( FqnCacheNode<WeakReference<T>> child: copy ) { child.visitBreadthFirst( delegate ); } } private static class KeyedReference<T> extends WeakReference<T> { 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 <T> 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<T> ref = (KeyedReference<T>)_queue.poll(); // if( ref == null ) { // break; // } // FqnCacheNode<WeakReference<T>> node = getNode( ref._fqn ); // if( node != null && node.isLeaf() && node.getUserData() == ref ) { // _remove( ref._fqn ); // // System.out.println( "XXXXXX: " + (++_removed) + " : " + ref._fqn ); // } // } // } }