/*
* $Id: Reflection.java,v 1.10 2002/09/16 08:05:03 jkl Exp $
*
* Copyright (c) 2002 Njet Communications Ltd. All Rights Reserved.
*
* Use is subject to license terms, as defined in
* Anvil Sofware License, Version 1.1. See LICENSE
* file, or http://njet.org/license-1.1.txt
*/
package anvil.core.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Constructor;
import java.util.Enumeration;
import anvil.core.Any;
import anvil.core.AnyClass;
import anvil.core.AnyAbstractClass;
import anvil.core.ObjectPool;
import anvil.core.Register;
import anvil.java.util.Hashlist;
import anvil.java.util.BindingEnumeration;
import anvil.script.Context;
import anvil.script.Type;
import anvil.script.ClassDispatcher;
import anvil.script.ClassType;
import anvil.script.InterfaceType;
import anvil.script.InterfaceRef;
import anvil.script.ClassRef;
import anvil.script.ConstantVariableType;
import anvil.script.StaticVariableType;
import anvil.script.VariableType;
import anvil.script.Scope;
import anvil.script.ScriptException;
import anvil.script.ReflectedJava;
import anvil.script.CompilableFunction;
import anvil.script.compiler.ResolvedClassRef;
import anvil.script.compiler.ResolvedInterfaceRef;
import anvil.doc.Doc;
public class Reflection
extends AnyAbstractClass
implements ClassType, InterfaceType, ParameterTypes, ReflectedJava
{
private PackageReflection _parent;
private ClassRef _superref = null;
private Reflection _super = null;
private String _name;
private Class _class;
private int _arraytype = -1;
private InterfaceRef[] _interfaces;
private InterfaceRef[] _bases;
private ConstructorTree _ctor = null;
private Hashlist _declarations = new Hashlist();
private Hashlist _methods = new Hashlist();
public Reflection()
{
}
public Reflection(Class cls)
{
initialize(cls);
}
public void initialize(Class cls)
{
_name = cls.getName();
_class = cls;
_parent = ObjectPool.createReflection(cls.getPackage());
_parent.addClass(this);
if (cls.isArray()) {
Class elemtype = cls.getComponentType();
if (elemtype == Boolean.TYPE) {
_arraytype = BOOLEAN;
} else if (elemtype == Byte.TYPE) {
_arraytype = BYTE;
} else if (elemtype == Short.TYPE) {
_arraytype = SHORT;
} else if (elemtype == Integer.TYPE) {
_arraytype = INT;
} else if (elemtype == Long.TYPE) {
_arraytype = LONG;
} else if (elemtype == Float.TYPE) {
_arraytype = FLOAT;
} else if (elemtype == Double.TYPE) {
_arraytype = DOUBLE;
} else if (Any.class.isAssignableFrom(elemtype)) {
_arraytype = ANVIL_CORE_ANY;
} else {
_arraytype = JAVA_LANG_OBJECT;
}
}
Class supercls = cls.getSuperclass();
if (supercls != null) {
_super = ObjectPool.createReflection(supercls);
_superref = new ResolvedClassRef(_super);
}
if (Modifier.isPublic(cls.getModifiers())) {
Method[] methods = cls.getDeclaredMethods();
int n = methods.length;
for(int i=0; i<n; i++) {
insertMethod(methods[i]);
}
Constructor[] ctors = cls.getDeclaredConstructors();
n = ctors.length;
for(int i=0; i<n; i++) {
insertConstructor(ctors[i]);
}
Field[] fields = cls.getDeclaredFields();
for(int i=0; i<fields.length; i++) {
Field field = fields[i];
int modifier = field.getModifiers();
if (Modifier.isPublic(modifier)) {
String name = field.getName();
if (Modifier.isStatic(modifier)) {
if (Modifier.isFinal(modifier)) {
addDeclaration(field.getName(),
new ReflectedConstantVariable(this, name, field, null));
} else {
addDeclaration(field.getName(), new AdaptiveClassVariable(name, field, this));
}
} else {
addDeclaration(field.getName(), new AdaptiveMemberVariable(name, field, this));
}
}
}
Class[] classes = cls.getDeclaredClasses();
n = classes.length;
for(int i=0; i<n; i++) {
Class innercls = classes[i];
if (Modifier.isPublic(innercls.getModifiers())) {
Reflection ref = ObjectPool.createReflection(innercls);
String name = innercls.getName().substring(_name.length()+1);
addDeclaration(name, ref);
}
}
Class[] interfaces = cls.getInterfaces();
n = interfaces.length;
_interfaces = new ResolvedInterfaceRef[n];
for(int i=0; i<n; i++) {
Class iface = interfaces[i];
if (Modifier.isPublic(iface.getModifiers())) {
_interfaces[i] = new ResolvedInterfaceRef(ObjectPool.createReflection(iface));
}
}
}
Reflection ref = _super;
while(ref != null) {
Enumeration enum = ref.getDeclarations();
while(enum.hasMoreElements()) {
Type type = (Type)enum.nextElement();
String name = type.getName();
addDeclaration(name, type);
if (type.getType() == METHOD) {
addMethod(name, type);
}
}
ref = ref._super;
}
}
private void addDeclaration(String name, Type type)
{
if (!_declarations.containsKey(name)) {
_declarations.put(name, type);
}
}
private void addMethod(String name, Type type)
{
if (!_methods.containsKey(name)) {
_methods.put(name, type);
_methods.put(new Integer(Register.register(name)), type);
}
}
private void insertMethod(Method method)
{
if (Modifier.isPublic(method.getModifiers())) {
String name = method.getName();
MethodTree tree = (MethodTree)_methods.get(name);
if (tree == null) {
tree = new MethodTree(this, name);
addDeclaration(name, tree);
addMethod(name, tree);
}
tree.insert(method, method.getParameterTypes());
}
}
private void insertConstructor(Constructor ctor)
{
if (Modifier.isPublic(ctor.getModifiers())) {
if (_ctor == null) {
_ctor = new ConstructorTree(this, _name);
}
_ctor.insert(ctor, ctor.getParameterTypes());
}
}
public String getSignature()
{
return _class.getName().replace('.', '/');
}
public Class getJavaClass()
{
return _class;
}
public anvil.script.ClassType classOf()
{
return this;
}
public boolean isInstanceOf(Type ofType)
{
if (ofType instanceof Reflection) {
Reflection reflection = (Reflection)ofType;
return reflection._class.isAssignableFrom(_class);
}
return false;
}
public String toString()
{
return "class " + _class.getName();
}
public Object toObject()
{
return _class;
}
public String getName()
{
return _name;
}
public String getQualifiedName()
{
return _name;
}
public int getType()
{
return _class.isInterface() ? INTERFACE : CLASS;
}
public Scope getParent()
{
return _parent;
}
public ClassType[] getEnclosingClasses()
{
return new ClassType[0];
}
public String getPathinfo()
{
return "";
}
public BindingEnumeration getMembers(AnyClass instance)
{
return BindingEnumeration.EMPTY;
}
public Doc getDocument()
{
return Doc.EMPTY_DOC;
}
public Enumeration getDeclarations()
{
return _declarations.elements();
}
public Type lookupDeclaration(String name)
{
return (Type)_declarations.get(name);
}
public ClassRef getBase()
{
return _superref;
}
public ClassType getBaseClass()
{
return _super;
}
public Type lookupInheritedDeclaration(String name)
{
if (_super != null) {
return _super.lookupDeclaration(name);
}
return null;
}
public InterfaceRef[] getInterfaces()
{
return _interfaces;
}
public InterfaceRef[] getBases()
{
return _interfaces;
}
public CompilableFunction getConstructor()
{
if (_ctor == null) {
return _super.getConstructor();
}
return _ctor;
}
public AnyClass newInstance()
{
return null;
}
public boolean hasMethod(String name)
{
if (_methods.containsKey(name)) {
return true;
}
if (_super != null) {
return _super.has(name);
}
return false;
}
public Any getAttribute(Context context, String attribute)
{
Type type = (Type)_declarations.get(attribute);
if (type != null) {
switch(type.getType()) {
case Type.STATIC_VARIABLE:
case Type.CONSTANT_VARIABLE:
return ((StaticVariableType)type).getValue();
case Type.CLASS:
case Type.INTERFACE:
return (Reflection)type;
}
}
return Any.UNDEFINED;
}
public Any checkAttribute(Context context, String attribute)
{
return getAttribute(context, attribute);
}
public Any setAttribute(Context context, String attribute, Any value)
{
Type type = (Type)_declarations.get(attribute);
if (type != null) {
if (type.getType() == Type.STATIC_VARIABLE) {
return ((VariableType)type).setValue(value);
}
}
return value;
}
public Any getReference(Context context, Any index)
{
if (index.isInt()) {
return Any.create(Array.newInstance(_class, index.toInt()));
} else if (index.isTuple()) {
int n = index.sizeOf();
Any[] list = index.toTuple();
int dims[] = new int[n];
for(int i=0; i<n; i++) {
dims[i] = list[i].toInt();
}
return Any.create(Array.newInstance(_class, dims));
} else {
Type type = (Type)_declarations.get(index.toString());
if (type != null) {
switch(type.getType()) {
case Type.STATIC_VARIABLE:
case Type.CONSTANT_VARIABLE:
return ((VariableType)type).getValue();
case Type.CLASS:
case Type.INTERFACE:
return (Reflection)type;
}
}
}
return Any.UNDEFINED;
}
public Any checkReference(Context context, Any index)
{
return getReference(context, index);
}
public Any setReference(Context context, Any index, Any value)
{
Type type = (Type)_declarations.get(index.toString());
if (type != null) {
if (type.getType() == Type.STATIC_VARIABLE) {
return ((StaticVariableType)type).setValue(value);
}
}
return value;
}
public Any invoke(Context context, Object instance, int methodIndex, Any[] parameters)
{
ParameterTree tree = (ParameterTree)_methods.get(ObjectPool.createInteger(methodIndex));
if (tree != null) {
return tree.invoke(context, instance, parameters);
} else {
throw context.NoSuchMethod(_name, methodIndex);
}
}
public Any invoke(Context context, Object instance, String methodName, Any[] parameters)
{
ParameterTree tree = (ParameterTree)_methods.get(methodName);
if (tree != null) {
return tree.invoke(context, instance, parameters);
} else {
throw context.NoSuchMethod(_name + '.' + methodName);
}
}
public Any invoke(Context context, int methodIndex, Any[] parameters)
{
return invoke(context, null, methodIndex, parameters);
}
public Any invoke(Context context, int methodIndex)
{
return invoke(context, null, methodIndex, Any.ARRAY0);
}
public Any invoke(Context context, int methodIndex, Any param1)
{
return invoke(context, null, methodIndex, new Any[] { param1 });
}
public Any invoke(Context context, int methodIndex, Any param1, Any param2)
{
return invoke(context, null, methodIndex, new Any[] { param1, param2 });
}
public Any invoke(Context context, int methodIndex, Any param1, Any param2, Any param3)
{
return invoke(context, null, methodIndex, new Any[] { param1, param2, param3 });
}
public Any invoke(Context context, int methodIndex, Any param1, Any param2, Any param3, Any param4)
{
return invoke(context, null, methodIndex, new Any[] { param1, param2, param3, param4 });
}
public Any invoke(Context context, String methodName, Any[] parameters)
{
return invoke(context, null, methodName, parameters);
}
public Any invoke(Context context, String methodName)
{
return invoke(context, null, methodName, Any.ARRAY0);
}
public Any invoke(Context context, String methodName, Any param1)
{
return invoke(context, null, methodName, new Any[] { param1 });
}
public Any invoke(Context context, String methodName, Any param1, Any param2)
{
return invoke(context, null, methodName, new Any[] { param1, param2 });
}
public Any invoke(Context context, String methodName, Any param1, Any param2, Any param3)
{
return invoke(context, null, methodName, new Any[] { param1, param2, param3 });
}
public Any invoke(Context context, String methodName, Any param1, Any param2, Any param3, Any param4)
{
return invoke(context, null, methodName, new Any[] { param1, param2, param3, param4 });
}
public ClassDispatcher getDispatcher(Context context)
{
return null;
}
public Any execute(Context context, Any[] parameters)
{
if (_ctor != null) {
return _ctor.invoke(context, null, parameters);
} else {
return UNDEFINED;
}
}
public Any execute(Context context)
{
if (_ctor != null) {
return _ctor.invoke(context, null, Any.ARRAY0);
} else {
return UNDEFINED;
}
}
public Any execute(Context context, Any param1)
{
if (_ctor != null) {
return _ctor.invoke(context, null, new Any[] { param1 });
} else {
return UNDEFINED;
}
}
public Any execute(Context context, Any param1, Any param2)
{
if (_ctor != null) {
return _ctor.invoke(context, null, new Any[] { param1, param2 });
} else {
return UNDEFINED;
}
}
public Any execute(Context context, Any param1, Any param2, Any param3)
{
if (_ctor != null) {
return _ctor.invoke(context, null, new Any[] { param1, param2, param3 });
} else {
return UNDEFINED;
}
}
public Any execute(Context context, Any param1, Any param2, Any param3, Any param4)
{
if (_ctor != null) {
return _ctor.invoke(context, null, new Any[] { param1, param2, param3, param4 });
} else {
return UNDEFINED;
}
}
public String getDescriptor()
{
return null;
}
public int getTypeRef(anvil.codec.ConstantPool pool)
{
return 0;
}
public int getConstructorReference(anvil.codec.ConstantPool pool)
{
return 0;
}
public Any arrayGet(Object array, int index)
{
switch(_arraytype) {
case BOOLEAN:
return Array.getBoolean(array, index) ? TRUE : FALSE;
case BYTE:
return Any.create(Array.getByte(array, index));
case CHAR:
return Any.create(Array.getChar(array, index));
case SHORT:
return Any.create(Array.getShort(array, index));
case INT:
return Any.create(Array.getInt(array, index));
case LONG:
return Any.create(Array.getLong(array, index));
case FLOAT:
return Any.create(Array.getFloat(array, index));
case DOUBLE:
return Any.create(Array.getDouble(array, index));
case JAVA_LANG_OBJECT:
return Any.create(Array.get(array, index));
case ANVIL_CORE_ANY:
return (Any)Array.get(array, index);
default:
return UNDEFINED;
}
}
public void arraySet(Object array, int index, Any value)
{
switch(_arraytype) {
case BOOLEAN:
Array.setBoolean(array, index, value.toBoolean());
return;
case BYTE:
Array.setByte(array, index, (byte)value.toInt());
return;
case CHAR:
Array.setChar(array, index, value.toChar());
return;
case SHORT:
Array.setShort(array, index, (short)value.toInt());
return;
case INT:
Array.setInt(array, index, value.toInt());
return;
case LONG:
Array.setLong(array, index, value.toLong());
return;
case FLOAT:
Array.setFloat(array, index, (float)value.toDouble());
return;
case DOUBLE:
Array.setDouble(array, index, value.toDouble());
return;
case JAVA_LANG_OBJECT:
Array.set(array, index, value.toObject());
return;
case ANVIL_CORE_ANY:
Array.set(array, index, value);
return;
}
}
public boolean isArray()
{
return _class.isArray();
}
public int arrayLength(Object array)
{
if (_class.isArray()) {
return ((Object[])array).length;
}
return 0;
}
}