package org.glassfish.gmbal.typelib;
import java.lang.reflect.Field;
import java.security.PrivilegedActionException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import static java.lang.reflect.Modifier.* ;
import java.lang.reflect.Type ;
import java.lang.reflect.GenericArrayType ;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.WildcardType ;
import java.lang.reflect.ParameterizedType ;
import java.lang.reflect.TypeVariable ;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.util.Date;
import java.util.Iterator;
import java.util.WeakHashMap;
import javax.management.ObjectName;
import org.glassfish.gmbal.impl.trace.TraceTypelib;
import org.glassfish.gmbal.impl.trace.TraceTypelibEval;
import org.glassfish.pfl.basic.algorithm.Algorithms;
import org.glassfish.pfl.basic.contain.Display;
import org.glassfish.pfl.basic.contain.Pair;
import org.glassfish.pfl.basic.func.UnaryFunction;
import org.glassfish.pfl.basic.logex.Chain;
import org.glassfish.pfl.basic.logex.OperationTracer;
import org.glassfish.pfl.tf.spi.annotation.InfoMethod;
@TraceTypelib
@TraceTypelibEval
public class TypeEvaluator {
private TypeEvaluator() {}
private static Map<Class<?>,EvaluatedType> immutableTypes =
new HashMap<Class<?>,EvaluatedType>() ;
private static Map<EvalMapKey,EvaluatedClassDeclaration> evalClassMap =
new HashMap<EvalMapKey,EvaluatedClassDeclaration>() ;
private static List<EvaluatedType> emptyETList =
new ArrayList<EvaluatedType>(0) ;
@TraceTypelib
private static void mapPut( EvaluatedClassDeclaration ecd,
Class cls ) {
immutableTypes.put( cls, ecd ) ;
EvalMapKey key = new EvalMapKey( cls, emptyETList ) ;
evalClassMap.put( key, ecd ) ;
}
static {
try {
final Class[] classes = {
int.class, byte.class, char.class, short.class, long.class,
boolean.class, float.class, double.class,
void.class, Integer.class, Byte.class, Character.class,
Short.class, Boolean.class, Float.class, Double.class,
Long.class, BigDecimal.class, BigInteger.class,
Date.class, ObjectName.class, Class.class,
Number.class
} ;
final Class objectClass = Object.class ;
final Class stringClass = String.class ;
final Class voidClass = Void.class ;
final Method toStringMethod = getDeclaredMethod( objectClass,
"toString" ) ;
final EvaluatedClassDeclaration objectECD = getECD( objectClass ) ;
final EvaluatedClassDeclaration voidECD = getECD( voidClass ) ;
final EvaluatedClassDeclaration stringECD = getECD( stringClass ) ;
final EvaluatedMethodDeclaration toStringEMD =
DeclarationFactory.emdecl( objectECD, PUBLIC, stringECD, "toString",
emptyETList, toStringMethod ) ;
final List<EvaluatedMethodDeclaration> toStringList =
Algorithms.list( toStringEMD ) ;
final List<EvaluatedClassDeclaration> objectList =
Algorithms.list( objectECD ) ;
voidECD.inheritance( objectList ) ;
voidECD.freeze() ;
objectECD.methods( toStringList ) ;
objectECD.freeze() ;
stringECD.inheritance( objectList ) ;
stringECD.freeze() ;
mapPut( voidECD, voidClass ) ;
mapPut( objectECD, objectClass ) ;
mapPut( stringECD, stringClass ) ;
for (Class cls : classes) {
EvaluatedClassDeclaration ecd = getECD( cls ) ;
ecd.inheritance( objectList ) ;
ecd.freeze() ;
mapPut( ecd, cls ) ;
}
} catch (Exception exc) {
throw Exceptions.self.internalTypeEvaluatorError( exc ) ;
}
setDebugLevel(
Integer.getInteger( "org.glassfish.gmbal.TypelibDebugLevel", 0 ) ) ;
}
private static EvaluatedType getImmutableEvaluatedType( Class<?> cls ) {
return immutableTypes.get( cls ) ;
}
public synchronized static void setDebugLevel( int level ) {
}
private static class EvalMapKey extends Pair<Class<?>,List<EvaluatedType>> {
public EvalMapKey( Class<?> cls, List<EvaluatedType> decls ) {
super( cls, decls ) ;
}
public static final EvalMapKey OBJECT_KEY = new EvalMapKey(
Object.class, new ArrayList<EvaluatedType>(0) ) ;
}
private static EvaluatedClassDeclaration getECD( Class cls ) {
return DeclarationFactory.ecdecl( PUBLIC,
cls.getName(), cls, true ) ;
}
private static List<Method> getDeclaredMethods( final Class<?> cls ) {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return Arrays.asList( cls.getDeclaredMethods() ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedAction<List<Method>>() {
public List<Method> run() {
return Arrays.asList( cls.getDeclaredMethods() ) ;
}
}
) ;
}
}
private static List<Field> getDeclaredFields( final Class<?> cls ) {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return Arrays.asList( cls.getDeclaredFields() ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedAction<List<Field>>() {
public List<Field> run() {
return Arrays.asList( cls.getDeclaredFields() ) ;
}
}
) ;
}
}
private static Method getDeclaredMethod( final Class<?> cls,
final String name, final Class<?>... sig )
throws NoSuchMethodException, PrivilegedActionException {
SecurityManager sman = System.getSecurityManager() ;
if (sman == null) {
return cls.getDeclaredMethod( name, sig ) ;
} else {
return AccessController.doPrivileged(
new PrivilegedExceptionAction<Method>() {
public Method run() throws Exception {
return cls.getDeclaredMethod( name, sig ) ;
}
}
) ;
}
}
public synchronized static int evalClassMapSize() {
return evalClassMap.size() ;
}
public synchronized static void dumpEvalClassMap() {
System.out.println( "TypeEvaluator: dumping eval class map") ;
int numSystem = 0 ;
int total = 0 ;
for (Map.Entry<EvalMapKey,EvaluatedClassDeclaration> entry
: evalClassMap.entrySet() ) {
System.out.println( "\tKey:" + entry.getKey() + "=>" ) ;
System.out.println( "\t\t" + entry.getValue() ) ;
String name = entry.getKey().first().getName() ;
if (!name.startsWith("org.glassfish.gmbal" )) {
numSystem++ ;
}
total ++ ;
}
System.out.printf(
"\nEvalClassMap contains %d entries, %d of which are system classes\n",
total, numSystem ) ;
}
private static Map<Class,EvaluatedType> classMap =
new WeakHashMap<Class, EvaluatedType>() ;
public static synchronized EvaluatedType getEvaluatedType( Class cls ) {
EvaluatedType etype = null ;
try {
etype = classMap.get( cls ) ;
if (etype == null) {
TypeEvaluationVisitor visitor = new TypeEvaluationVisitor() ;
etype = visitor.evaluateType( cls ) ;
classMap.put( cls, etype ) ;
}
} catch (Error err) {
IllegalStateException thr = Exceptions.self.errorInTypeEval( cls,
err ) ;
dumpEvalClassMap();
throw thr ;
}
return etype ;
}
private static class PartialDefinitions {
private Map<Pair<Class<?>,List<Type>>,EvaluatedType> table =
new HashMap<Pair<Class<?>,List<Type>>,EvaluatedType>() ;
private Pair<Class<?>,List<Type>> getKey( Class cls ) {
List<Type> list = new ArrayList<Type>() ;
for (TypeVariable tv : cls.getTypeParameters()) {
Type type ;
Type[] bounds = tv.getBounds() ;
if (bounds.length > 0) {
if (bounds.length > 1) {
throw Exceptions.self
.multipleUpperBoundsNotSupported( tv ) ;
} else {
type = bounds[0] ;
}
} else {
type = Object.class ;
}
list.add(type) ;
}
return new Pair<Class<?>,List<Type>>( cls, list ) ;
}
private Pair<Class<?>,List<Type>> getKey( ParameterizedType pt ) {
List<Type> list = new ArrayList<Type>() ;
for (Type type : pt.getActualTypeArguments()) {
list.add(type) ;
}
return new Pair<Class<?>,List<Type>>( (Class<?>)pt.getRawType(),
list ) ;
}
public EvaluatedType get( Class cls ) {
return table.get( getKey( cls ) ) ;
}
public EvaluatedType get( ParameterizedType pt ) {
return table.get( getKey( pt ) ) ;
}
public void put( Class cls, EvaluatedType et ) {
table.put( getKey( cls ), et ) ;
}
public void put( ParameterizedType pt, EvaluatedType et ) {
table.put( getKey( pt ), et ) ;
}
public void remove( Class cls ) {
table.remove( getKey( cls ) ) ;
}
public void remove( ParameterizedType pt ) {
table.remove( getKey( pt ) ) ;
}
}
@TraceTypelibEval
@TraceTypelib
private static class TypeEvaluationVisitor {
private final Display<String,EvaluatedType> display ;
private final PartialDefinitions partialDefinitions ;
public TypeEvaluationVisitor( ) {
display = new Display<String,EvaluatedType>() ;
partialDefinitions = new PartialDefinitions() ;
}
@TraceTypelibEval
public EvaluatedType evaluateType( Object type ) {
EvaluatedType result = null ;
if (type == null) {
result = null ;
} else if (type instanceof Class) {
Class cls = (Class)type ;
result = visitClassDeclaration( cls ) ;
} else if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)type ;
result = visitParameterizedType( pt ) ;
} else if (type instanceof TypeVariable) {
TypeVariable tvar = (TypeVariable)type ;
result = visitTypeVariable( tvar ) ;
} else if (type instanceof GenericArrayType) {
GenericArrayType gat = (GenericArrayType)type ;
result = visitGenericArrayType( gat ) ;
} else if (type instanceof WildcardType) {
WildcardType wt = (WildcardType)type ;
result = visitWildcardType( wt ) ;
} else if (type instanceof Method) {
throw Exceptions.self.evaluateTypeCalledWithMethod(type) ;
} else {
throw Exceptions.self.evaluateTypeCalledWithUnknownType(type) ;
}
return result ;
}
@InfoMethod
private void describe( String msg, Object data ) {}
@InfoMethod
private void message( String msg ) {}
@TraceTypelib
private EvaluatedType visitClassDeclaration( Class decl ) {
EvaluatedType result = null ;
try {
if (decl.isArray()) {
message( "decl is an array" ) ;
return DeclarationFactory.egat( evaluateType(
decl.getComponentType() ) ) ;
} else {
result = partialDefinitions.get( decl ) ;
if (result == null) {
EvaluatedClassDeclaration newDecl = DeclarationFactory.ecdecl(
decl.getModifiers(), decl.getName(), decl ) ;
partialDefinitions.put( decl, newDecl ) ;
try {
OrderedResult<String,EvaluatedType> bindings =
getBindings( decl ) ;
result = getCorrectDeclaration( bindings, decl, newDecl ) ;
} finally {
partialDefinitions.remove( decl ) ;
}
}
if (decl.isAnnotationPresent(ForceTypelibError.class )) {
throw new StackOverflowError(
"Simulating stack overflow in test") ;
}
}
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType visitParameterizedType( ParameterizedType pt ) {
Class<?> decl = (Class<?>)pt.getRawType() ;
EvaluatedType result = null ;
result = partialDefinitions.get( pt ) ;
if (result == null) {
EvaluatedClassDeclaration newDecl = DeclarationFactory.ecdecl(
decl.getModifiers(), decl.getName(), decl ) ;
partialDefinitions.put( pt, newDecl ) ;
try {
OrderedResult<String,EvaluatedType> bindings =
getBindings( pt ) ;
result = getCorrectDeclaration( bindings, decl, newDecl ) ;
} finally {
partialDefinitions.remove( pt ) ;
}
}
return result ;
}
@InfoMethod
private void fieldException( @Chain Exception exc, Field fld ) {}
@TraceTypelib
private EvaluatedFieldDeclaration visitFieldDeclaration(
final EvaluatedClassDeclaration cdecl, final Field fld ) {
EvaluatedFieldDeclaration result = null ;
try {
if (!Modifier.isFinal(fld.getModifiers())) {
return null ;
}
final Class fieldType = fld.getType() ;
EvaluatedType ftype = getImmutableEvaluatedType( fieldType ) ;
if (ftype == null) {
return null ;
}
result = DeclarationFactory.efdecl(cdecl, fld.getModifiers(),
ftype, fld.getName(), fld ) ;
} catch (Exception exc) {
fieldException( exc, fld ) ;
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedMethodDeclaration visitMethodDeclaration(
final EvaluatedClassDeclaration cdecl, final Method mdecl ) {
final List<EvaluatedType> eptypes =
Algorithms.map( Arrays.asList( mdecl.getGenericParameterTypes() ),
new UnaryFunction<Type,EvaluatedType>() {
public EvaluatedType evaluate( Type type ) {
return evaluateType( type ) ;
} } ) ;
describe( "eptypes", eptypes ) ;
if (mdecl.getName().equals( "getThing" )) {
message( "processing getThing method from test" ) ;
}
EvaluatedMethodDeclaration result = null ;
try {
result = DeclarationFactory.emdecl(
cdecl, mdecl.getModifiers(),
evaluateType( mdecl.getGenericReturnType() ),
mdecl.getName(), eptypes, mdecl ) ;
if (mdecl.isAnnotationPresent(ForceTypelibError.class )) {
throw new StackOverflowError(
"Simulating stack overflow in test") ;
}
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType visitTypeVariable( TypeVariable tvar ) {
EvaluatedType result = null ;
try {
result = lookup( tvar ) ;
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType visitGenericArrayType( GenericArrayType at ) {
EvaluatedType result = null ;
try {
result = DeclarationFactory.egat(
evaluateType( at.getGenericComponentType() ) ) ;
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType visitWildcardType( WildcardType wt ) {
EvaluatedType result = null ;
try {
List<Type> ub = Arrays.asList( wt.getUpperBounds() ) ;
if (ub.size() > 0) {
if (ub.size() > 1) {
throw Exceptions.self.multipleUpperBoundsNotSupported(
wt) ;
}
result = evaluateType( ub.get(0) ) ;
} else {
result = EvaluatedType.EOBJECT ;
}
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType lookup( TypeVariable tvar ) {
EvaluatedType result = null ;
try {
result = display.lookup( tvar.getName() ) ;
if (result == null) {
Type[] bounds = tvar.getBounds() ;
if (bounds.length > 0) {
if (bounds.length > 1) {
throw Exceptions.self
.multipleUpperBoundsNotSupported( tvar ) ;
}
result = evaluateType( bounds[0] ) ;
} else {
result = EvaluatedType.EOBJECT ;
}
}
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private EvaluatedType getCorrectDeclaration(
OrderedResult<String,EvaluatedType> bindings,
Class decl, EvaluatedClassDeclaration newDecl ) {
EvaluatedType result = null ;
try {
List<EvaluatedType> blist = bindings.getList() ;
EvalMapKey key = new EvalMapKey( decl, blist ) ;
if (blist.size() > 0) {
newDecl.instantiations( blist ) ;
}
result = evalClassMap.get( key ) ;
if (result == null) {
message( "No result in evalClassMap" ) ;
evalClassMap.put( key, newDecl ) ;
processClass( newDecl, bindings.getMap(), decl ) ;
result = newDecl ;
} else {
message( "Found result in evalClassMap" ) ;
}
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
@TraceTypelib
private void processClass( final EvaluatedClassDeclaration newDecl,
final Map<String,EvaluatedType> bindings, final Class decl ) {
display.enterScope() ;
display.bind( bindings ) ;
try {
List<EvaluatedClassDeclaration> inheritance =
Algorithms.map( getInheritance( decl ),
new UnaryFunction<Type,EvaluatedClassDeclaration>() {
public EvaluatedClassDeclaration evaluate( Type pt ) {
return (EvaluatedClassDeclaration)evaluateType( pt ) ;
} } ) ;
describe( "inheritance", inheritance ) ;
newDecl.inheritance( inheritance ) ;
List<EvaluatedFieldDeclaration> newFields = Algorithms.map(
getDeclaredFields( decl ),
new UnaryFunction<Field,EvaluatedFieldDeclaration>() {
public EvaluatedFieldDeclaration evaluate( Field fld ) {
return visitFieldDeclaration( newDecl, fld ) ;
} } ) ;
newDecl.fields( newFields ) ;
List<EvaluatedMethodDeclaration> newMethods = Algorithms.map(
getDeclaredMethods( decl ),
new UnaryFunction<Method,EvaluatedMethodDeclaration>() {
public EvaluatedMethodDeclaration evaluate(
Method md ) {
return visitMethodDeclaration( newDecl, md ) ;
} } ) ;
newDecl.methods( newMethods ) ;
newDecl.freeze() ;
describe( "newDecl", newDecl ) ;
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
} finally {
display.exitScope() ;
}
}
@TraceTypelib
private List<Type> getInheritance( Class cls ) {
List<Type> result = new ArrayList<Type>(0) ;
try {
result.add( cls.getGenericSuperclass() ) ;
result.addAll( Arrays.asList( cls.getGenericInterfaces() ) ) ;
} catch (Error err) {
OperationTracer.freeze() ;
throw err ;
}
return result ;
}
private OrderedResult<String,EvaluatedType> getBindings( Class decl ) {
OrderedResult<String,EvaluatedType> result = new
OrderedResult<String,EvaluatedType>() ;
for (TypeVariable tv : decl.getTypeParameters()) {
EvaluatedType res = lookup( tv ) ;
result.add( tv.getName(), res ) ;
}
return result ;
}
private OrderedResult<String,EvaluatedType> getBindings( ParameterizedType pt ) {
OrderedResult<String,EvaluatedType> result = new
OrderedResult<String,EvaluatedType>() ;
Iterator<Type> types =
Arrays.asList(pt.getActualTypeArguments()).iterator() ;
Iterator<TypeVariable> tvars =
Arrays.asList(((Class)pt.getRawType()).getTypeParameters()).iterator() ;
while (types.hasNext() && tvars.hasNext()) {
Type type = types.next() ;
TypeVariable tvar = tvars.next() ;
result.add( tvar.getName(), evaluateType( type ) ) ;
}
if (types.hasNext() != tvars.hasNext()) {
throw Exceptions.self.listsNotTheSameLengthInParamType(pt) ;
}
return result ;
}
public static class OrderedResult<K,V> {
private List<V> list = new ArrayList<V>(0) ;
private Map<K,V> map = new HashMap<K,V>() ;
public List<V> getList() { return list ; }
public Map<K,V> getMap() { return map ; }
public void add( K key, V value ) {
list.add( value ) ;
map.put( key, value ) ;
}
}
}
}