1 21 package org.lobobrowser.js; 22 23 import org.mozilla.javascript.*; 24 import java.lang.reflect.*; 25 import java.util.logging.*; 26 import java.util.*; 27 import org.lobobrowser.util.*; 28 29 public class JavaFunctionObject extends ScriptableObject implements Function { 30 private static final Logger logger = Logger.getLogger(JavaFunctionObject.class.getName()); 31 private static final boolean loggableInfo = logger.isLoggable(Level.INFO); 32 private final String className; 33 private final ArrayList methods = new ArrayList(); 34 35 public JavaFunctionObject(String name) { 36 super(); 37 this.className = name; 38 } 39 40 public void addMethod(Method m) { 41 this.methods.add(m); 42 } 43 44 public String getClassName() { 45 return this.className; 46 } 47 48 private String getTypeName(Object object) { 49 return object == null ? "[null]" : object.getClass().getName(); 50 } 51 52 private Method getBestMethod(Object [] args) { 53 ArrayList methods = this.methods; 54 int size = methods.size(); 55 int matchingNumParams = 0; 56 Method matchingMethod = null; 57 for(int i = 0; i < size; i++) { 58 Method m = (Method) methods.get(i); 59 Class [] parameterTypes = m.getParameterTypes(); 60 if(args == null) { 61 if(parameterTypes == null || parameterTypes.length == 0) { 62 return m; 63 } 64 } 65 else if(parameterTypes != null && args.length >= parameterTypes.length) { 66 if(Objects.areAssignableTo(args, parameterTypes)) { 67 return m; 68 } 69 if(matchingMethod == null || parameterTypes.length > matchingNumParams) { 70 matchingNumParams = parameterTypes.length; 71 matchingMethod = m; 72 } 73 } 74 } 75 if(size == 0) { 76 throw new IllegalStateException ("zero methods"); 77 } 78 return matchingMethod; 79 } 80 81 public Object call(Context cx, Scriptable scope, Scriptable thisObj, 82 Object [] args) { 83 JavaObjectWrapper jcw = (JavaObjectWrapper) thisObj; 84 Method method = this.getBestMethod(args); 85 if(method == null) { 86 throw new EvaluatorException("No method matching " + this.className + " with " + (args == null ? 0 : args.length) + " arguments."); 87 } 88 Class [] actualArgTypes = method.getParameterTypes(); 89 int numParams = actualArgTypes.length; 90 Object [] actualArgs = args == null ? new Object [0] : new Object [numParams]; 91 boolean linfo = loggableInfo; 92 if(linfo) { 93 Object javaObject = jcw.getJavaObject(); 94 logger.info("call(): Calling method " + method.getName() + " on object " + javaObject + " of type " + this.getTypeName(javaObject)); 95 } 96 JavaScript manager = JavaScript.getInstance(); 97 for(int i = 0; i < numParams; i++) { 98 Object arg = args[i]; 99 Object actualArg = manager.getJavaObject(arg, actualArgTypes[i]); 100 if(linfo) { 101 logger.info("call(): For method=" + method.getName() + ": Converted arg=" + arg + " (type=" + this.getTypeName(arg) + ") into actualArg=" + actualArg + ". Type expected by method is " + actualArgTypes[i].getName() + "."); 102 } 103 actualArgs[i] = actualArg; 104 } 105 try { 106 Object raw = method.invoke(jcw.getJavaObject(), actualArgs); 107 return manager.getJavascriptObject(raw, scope); 108 } catch(IllegalAccessException iae) { 109 throw new IllegalStateException ("Unable to call " + this.className + ".", iae); 110 } catch(InvocationTargetException ite) { 111 throw new WrappedException(new InvocationTargetException(ite.getCause(), "Unable to call " + this.className + " on " + jcw.getJavaObject() + ".")); 112 } catch(IllegalArgumentException iae) { 113 StringBuffer argTypes = new StringBuffer (); 114 for(int i = 0; i < actualArgs.length; i++) { 115 if(i > 0) { 116 argTypes.append(", "); 117 } 118 argTypes.append(actualArgs[i] == null ? "<null>" : actualArgs[i].getClass().getName()); 119 } 120 throw new WrappedException(new IllegalArgumentException ("Unable to call " + this.className + ". Argument types: " + argTypes + ".", iae)); 121 } 122 } 123 124 public java.lang.Object getDefaultValue(java.lang.Class hint) { 125 if(loggableInfo) { 126 logger.info("getDefaultValue(): hint=" + hint + ",this=" + this); 127 } 128 if(hint == null || String .class.equals(hint)) { 129 return "function " + this.className; 130 } 131 else { 132 return super.getDefaultValue(hint); 133 } 134 } 135 136 public Scriptable construct(Context cx, Scriptable scope, Object [] args) { 137 throw new UnsupportedOperationException (); 138 } 139 } 140 | Popular Tags |