/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.util.cache;
import gw.internal.gosu.parser.StringCache;
import gw.util.DynamicArray;
import gw.util.Predicate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class FqnCache<T> implements IFqnCache<T> {
private static Map<String, String[]> PARTS_CACHE = new ConcurrentHashMap<String, String[]>();
private FqnCacheNode<T> _root = new FqnCacheNode<T>("root", null);
public FqnCacheNode<T> getRoot() {
return _root;
}
public FqnCacheNode<T> getNode(String fqn) {
FqnCacheNode<T> n = _root;
for (String part : getParts(fqn)) {
n = n.getChild(part);
if (n == null) {
break;
}
}
return n;
}
@Override
public final T get( String fqn ) {
FqnCacheNode<T> n = getNode( fqn );
return n == null ? null : n.getUserData();
}
@Override
public final boolean contains( String fqn ) {
return getNode(fqn) != null;
}
@Override
public final void add( String fqn ) {
add(fqn, null);
}
@Override
public void add( String fqn, T userData ) {
FqnCacheNode<T> n = _root;
for (String part : getParts(fqn)) {
n = n.getOrCreateChild(part);
}
n.setUserData(userData);
}
@Override
public final void remove( String[] fqns ) {
for (String fqn : fqns) {
remove(fqn);
}
}
@Override
public boolean remove( String fqn ) {
FqnCacheNode<T> n = _root;
for (String part : getParts(fqn)) {
n = n.getChild(part);
if( n == null ) {
return false;
}
}
n.delete();
return true;
}
@Override
public final void clear() {
_root.clear();
}
@Override
public Set<String> getFqns() {
Set<String> names = new HashSet<String>();
_root.collectNames(names, "");
return names;
}
public void visitDepthFirst( Predicate<T> visitor ) {
List<FqnCacheNode<T>> copy = new ArrayList<FqnCacheNode<T>>( _root.getChildren() );
for( FqnCacheNode<T> child: copy ) {
if( !child.visitDepthFirst( visitor ) ) {
return;
}
}
}
public void visitNodeDepthFirst( Predicate<FqnCacheNode> visitor ) {
List<FqnCacheNode<T>> copy = new ArrayList<FqnCacheNode<T>>( _root.getChildren() );
for( FqnCacheNode<T> child: copy ) {
if( !child.visitNodeDepthFirst( visitor ) ) {
return;
}
}
}
public void visitBreadthFirst( Predicate<T> visitor ) {
List<FqnCacheNode<T>> copy = new ArrayList<FqnCacheNode<T>>( _root.getChildren() );
for( FqnCacheNode<T> child: copy ) {
child.visitBreadthFirst( visitor );
}
}
private static String[] split( String fqn ) {
String theRest = fqn;
DynamicArray<String> parts = new DynamicArray<String>();
while( theRest != null ) {
int iParam = theRest.indexOf( '<' );
int iDot = theRest.indexOf( '.' );
int iArray = theRest.indexOf( '[' );
String part;
if( iParam == 0 ) {
if( iArray > 0 ) {
part = theRest.substring( 0, iArray );
theRest = iArray < theRest.length() ? theRest.substring( iArray ) : null;
}
else {
if( theRest.charAt( theRest.length()-1 ) != '>' ) {
throw new RuntimeException( "\"" + theRest + "\" does not end with '>'" );
}
part = theRest;
theRest = null;
}
}
else if( iArray == 0 ) {
part = theRest.substring( 0, 2 );
theRest = part.length() == theRest.length() ? null : theRest.substring( 2 );
}
else if( iParam > 0 ) {
if( iDot > 0 && iDot < iParam ) {
part = theRest.substring( 0, iDot );
theRest = iDot + 1 < theRest.length() ? theRest.substring( iDot + 1 ) : null;
}
else {
part = theRest.substring( 0, iParam );
theRest = iParam < theRest.length() ? theRest.substring( iParam ) : null;
}
}
else if( iDot > 0 ) {
part = theRest.substring( 0, iDot );
theRest = iDot + 1 < theRest.length() ? theRest.substring( iDot + 1 ) : null;
}
else {
part = theRest;
theRest = null;
}
parts.add( StringCache.get( part ) );
}
return parts.toArray(new String[parts.size()]);
}
public static String[] getParts(String fqn) {
String[] strings = PARTS_CACHE.get(fqn);
if (strings == null) {
strings = split(fqn);
PARTS_CACHE.put(fqn, strings);
}
return strings;
}
}