/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package visage.reflect;
import java.util.*;
/** A run-time representation of a Visage class.
* Corresponds to {@code java.lang.Class}.
*
* @author Per Bothner
* @profile desktop
*/
public abstract class VisageClassType extends VisageType implements VisageMember {
String name;
VisageContext context;
protected int modifiers;
protected static final int VISAGE_MIXIN = 1;
protected static final int VISAGE_CLASS = 2;
public static final String SEQUENCE_CLASSNAME =
"org.visage.runtime.sequence.Sequence";
public static final String OBJECT_VARIABLE_CLASSNAME =
"org.visage.runtime.location.ObjectVariable";
public static final String SEQUENCE_VARIABLE_CLASSNAME =
"org.visage.runtime.location.SequenceVariable";
public static final String FUNCTION_CLASSNAME_PREFIX =
"org.visage.functions.Function";
public static final String GETTER_PREFIX = "get$";
public static final String SETTER_PREFIX = "set$";
public static final String LOCATION_GETTER_PREFIX = "loc$";
protected VisageClassType(VisageContext context, int modifiers) {
this.context = context;
this.modifiers = modifiers;
}
public String getName() {
return name;
}
public String toString() {
String n = getName();
if (n == null)
n = "<anonymous>";
return "class "+n;
}
public boolean equals (VisageClassType other) {
return context.equals(other.context) && name.equals(other.name);
}
public int hashCode() {
return name.hashCode();
}
/** Get list of super-classes.
* Note we don't distinguish between classes and interfaces.
* @param all if true include all ancestor classes (including this class).
* @return the list of super-classes. It sorted by class name for
* convenience and consistency.
*/
public abstract List<VisageClassType> getSuperClasses(boolean all);
public boolean isMixin() {
return (modifiers & VISAGE_MIXIN) != 0;
}
@Override
public boolean isVisageType() {
return (modifiers & VISAGE_CLASS) != 0;
}
public boolean isAssignableFrom(VisageClassType cls) {
if (this.equals(cls))
return true;
List<VisageClassType> supers = cls.getSuperClasses(false);
for (VisageClassType s : supers) {
if (isAssignableFrom(s))
return true;
}
return false;
}
public List<VisageMember> getMembers(VisageMemberFilter filter, boolean all) {
SortedMemberArray<VisageMember> result = new SortedMemberArray<VisageMember>();
if (all) {
List<VisageClassType> supers = getSuperClasses(all);
for (VisageClassType cl : supers)
cl.getMembers(filter, result);
}
else
getMembers(filter, result);
return result;
}
public List<VisageMember> getMembers(boolean all) {
return getMembers(new VisageMemberFilter(), all);
}
protected void getMembers(VisageMemberFilter filter, SortedMemberArray<VisageMember> result) {
getVariables(filter, result);
getFunctions(filter, result);
}
public List<VisageFunctionMember> getFunctions(VisageMemberFilter filter, boolean all) {
SortedMemberArray<VisageFunctionMember> result = new SortedMemberArray<VisageFunctionMember>();
if (all) {
List<VisageClassType> supers = getSuperClasses(all);
for (VisageClassType cl : supers)
cl.getFunctions(filter, result);
}
else
getFunctions(filter, result);
return result;
}
public List<VisageFunctionMember> getFunctions(boolean all) {
return getFunctions(VisageMemberFilter.acceptMethods(), all);
}
protected abstract void getFunctions(VisageMemberFilter filter, SortedMemberArray<? super VisageFunctionMember> result);
public List<VisageVarMember> getVariables(VisageMemberFilter filter, boolean all) {
SortedMemberArray<VisageVarMember> result = new SortedMemberArray<VisageVarMember>();
if (all) {
List<VisageClassType> supers = getSuperClasses(all);
boolean isMixin = isMixin();
for (VisageClassType cl : supers) {
if (isMixin || !cl.isMixin())
cl.getVariables(filter, result);
}
}
else
getVariables(filter, result);
return result;
}
public List<VisageVarMember> getVariables(boolean all) {
return getVariables(VisageMemberFilter.acceptAttributes(), all);
}
protected abstract void getVariables(VisageMemberFilter filter, SortedMemberArray<? super VisageVarMember> result);
/** Get a member with the matching name and type - NOT IMPLEMENTED YET.
* (A method has a FunctionType.)
* (Unimplemented because it requires type matching.)
*/
public VisageMember getMember(String name, VisageType type) {
throw new UnsupportedOperationException("getMember not implemented yet.");
}
/** Get the attribute (field) of this class with a given name. */
public VisageVarMember getVariable(String name) {
VisageMemberFilter filter = new VisageMemberFilter();
filter.setAttributesAccepted(true);
filter.setRequiredName(name);
List<VisageVarMember> attrs = getVariables(filter, true);
return attrs.isEmpty() ? null : attrs.get(attrs.size() - 1);
}
/** Find the function that (best) matches the name and argument types. */
public abstract VisageFunctionMember getFunction(String name, VisageType... argType);
public VisageContext getReflectionContext() {
return context;
}
/** Return raw uninitialized object. */
public abstract VisageObjectValue allocate ();
/** Create a new initialized object.
* This is just {@code allocate}+{@code VisageObjectValue.initialize}.
*/
public VisageObjectValue newInstance() {
return allocate().initialize();
}
static class SortedMemberArray<T extends VisageMember> extends AbstractList<T> {
VisageMember[] buffer = new VisageMember[4];
int sz;
public T get(int index) {
if (index >= sz)
throw new IndexOutOfBoundsException();
return (T) buffer[index];
}
public int size() { return sz; }
// This is basically 'add' under a different non-public name.
boolean insert(T cl) {
String clname = cl.getName();
// We could use binary search, but the lack of a total order
// for ClassLoaders complicates that. Linear search should be ok.
int i = 0;
for (; i < sz; i++) {
VisageMember c = buffer[i];
// First compare by name.
int cmp = c.getName().compareToIgnoreCase(clname);
if (cmp == 0)
cmp = c.getName().compareTo(clname);
if (cmp > 0)
break;
if (cmp < 0)
continue;
// Next compare by owner. Inherited members go earlier.
VisageClassType clowner = cl.getDeclaringClass();
VisageClassType cowner = c.getDeclaringClass();
boolean clAssignableFromC = clowner.isAssignableFrom(cowner);
boolean cAssignableFromCl = cowner.isAssignableFrom(clowner);
if (clAssignableFromC && ! cAssignableFromCl)
break;
if (cAssignableFromCl && ! clAssignableFromC)
continue;
// Next compare by owner name.
String clownerName = clowner.getName();
String cownerName = cowner.getName();
cmp = cownerName.compareToIgnoreCase(clownerName);
if (cmp == 0)
cmp = cownerName.compareTo(clownerName);
if (cmp > 0)
break;
if (cmp < 0)
continue;
// Sort member classes before other members.
if (cl instanceof VisageClassType)
break;
if (c instanceof VisageClassType)
continue;
// Sort var after member classes, but before other members.
if (cl instanceof VisageVarMember)
break;
if (c instanceof VisageVarMember)
continue;
if (cl instanceof VisageFunctionMember && c instanceof VisageFunctionMember) {
String scl = ((VisageFunctionMember) cl).getType().toString();
String sc = ((VisageFunctionMember) c).getType().toString();
cmp = sc.compareToIgnoreCase(scl);
if (cmp == 0)
cmp = sc.compareTo(scl);
if (cmp < 0)
continue;
}
// Otherwise arbitrary order.
break;
}
if (sz == buffer.length) {
VisageMember[] tmp = new VisageMember[2*sz];
System.arraycopy(buffer, 0, tmp, 0, sz);
buffer = tmp;
}
System.arraycopy(buffer, i, buffer, i+1, sz-i);
buffer[i] = cl;
sz++;
return true;
}
}
}