001: package jsint;
002:
003: import java.lang.reflect.Method;
004: import java.util.Hashtable;
005:
006: /** This class allows you to call any Java method, just by naming it,
007: * and doing the dispatch at runtime.
008: * @author Peter Norvig, Copyright 1998, peter@norvig.com, <a href="license.txt">license</a>
009: * subsequently modified by Jscheme project members
010: * licensed under zlib licence (see license.txt)
011: **/
012:
013: public class JavaMethod extends Reflector {
014:
015: public static final Object[] ZERO_ARGS = new Object[0];
016:
017: private String methodClass;
018: /** Parameter/method table for a specific method. **/
019: private transient Object[] methodTable;
020: private boolean isStatic;
021: /** Do we know the Class that this method applies to? **/
022: private boolean isSpecific;
023: /** Class -> methodTable map. **/
024: private transient Hashtable classMethodTable;
025:
026: public boolean isStatic() {
027: return this .isStatic;
028: }
029:
030: /**
031:
032: If the method is static then Class c is not null. For instance
033: methods, if Class c is not null, then it is used at construction
034: time to create a method table. Otherwise, the class of the
035: method is determined at call time from the target, and the method
036: table is constructed then and cached. Examples (see DynamicVariable.java):
037:
038: <pre>
039: new JavaMethod("getProperties", System.class, true) - static method
040: new JavaMethod("put", Hashtable.class,false) - specific instance method.
041: new JavaMethod("put", null, false) - unspecified instance method
042: </pre>
043: **/
044:
045: public JavaMethod(String name, Class c, boolean isStatic,
046: boolean isPrivileged) {
047: this .name = name;
048: if (c != null)
049: this .methodClass = c.getName();
050: this .isStatic = isStatic;
051: this .isSpecific = (c != null);
052: this .minArgs = isStatic ? 0 : 1;
053: this .isPrivileged = isPrivileged;
054: reset();
055: }
056:
057: public JavaMethod(String name, Class c, boolean isStatic) {
058: this (name, c, isStatic, false);
059: }
060:
061: public JavaMethod(String name, Class c) {
062: this (name, c, (c != null));
063: }
064:
065: protected synchronized void reset() {
066: if (isSpecific) {
067: methodTable = Invoke.methodTable0(Import
068: .classNamed(methodClass), name, isStatic,
069: isPrivileged);
070: if (methodTable.length == 0) {
071: methodTable = null;
072: E.warn("No such "
073: + (isStatic ? " static " : " instance ")
074: + " method \""
075: + name
076: + (isSpecific ? ("\" in class " + methodClass)
077: : ""));
078: }
079: } else
080: classMethodTable = new Hashtable(5);
081: }
082:
083: public Object[] instanceMethodTable(Class c) {
084: Object[] ms = ((Object[]) classMethodTable.get(c));
085: if (ms != null)
086: return ms;
087: ms = Invoke.methodTable0(c, name, isStatic, isPrivileged);
088: if (ms != null && ms.length > 0) {
089: classMethodTable.put(c, ms);
090: return ms;
091: } else
092: return (Object[]) E.error(c + " has no methods for "
093: + this .name);
094: }
095:
096: /**
097: For a static method, args is an Object[] of arguments.
098: For an instance method, args is (vector target (vector arguments));
099: **/
100: public Object apply(Object[] args) {
101: if (!(isSpecific)) {
102: Object[] methodTable = instanceMethodTable(args[0]
103: .getClass());
104: Object[] as = (Object[]) args[1];
105: Method m = (Method) Invoke.findMethod(methodTable, as);
106: return Invoke.invokeRawMethod(m, args[0], as);
107: } else {
108: if (methodTable == null)
109: return E.error(this + " has no methods");
110: if (isStatic) {
111: Method m = (Method) Invoke
112: .findMethod(methodTable, args);
113: return Invoke.invokeRawMethod(m, null, args);
114: } else {
115: Object[] as = (Object[]) args[1];
116: Method m = (Method) Invoke.findMethod(methodTable, as);
117: return Invoke.invokeRawMethod(m, args[0], as);
118: }
119: }
120: }
121:
122: public Object[] makeArgArray(Object[] code, Evaluator eval,
123: LexicalEnvironment lexenv) {
124: if (isStatic) {
125: int L = code.length - 1;
126: if (L == 0)
127: return ZERO_ARGS;
128:
129: Object[] args = new Object[L];
130: for (int i = 0; i < L; i++)
131: args[i] = eval.execute(code[i + 1], lexenv);
132: return args;
133: } else {
134: int L = code.length - 2;
135: if (L < 0)
136: return ((Object[]) E
137: .error("Wrong number of arguments in application: "
138: + U.stringify(code)));
139: Object target = eval.execute(code[1], lexenv);
140: if (L == 0)
141: return new Object[] { target, ZERO_ARGS };
142:
143: Object[] args = new Object[L];
144: for (int i = 0; i < L; i++)
145: args[i] = eval.execute(code[i + 2], lexenv);
146: return new Object[] { target, args };
147: }
148: }
149:
150: public Object[] makeArgArray(Pair args) {
151: if (isStatic)
152: return U.listToVector(args);
153: else
154: return new Object[] { args.first, U.listToVector(args.rest) };
155: }
156: }
|