/** @param jsContext the Context */ public Value makeValueFromJsval(Context jsContext, Object value) { if (value == Undefined.instance) { return new Value(); } if (value instanceof JavaObject) { Value returnVal = new Value(); int refId = ((JavaObject) value).getRefId(); returnVal.setJavaObject(new JavaObjectRef(refId)); return returnVal; } if (value instanceof Scriptable) { if (value instanceof ScriptableObject) { /* * HACK: check for native types like NativeString. NativeString is * package-protected. What other types do we need to check? */ ScriptableObject scriptableValue = (ScriptableObject) value; String className = scriptableValue.getClassName(); if (className.equals("String")) { return new Value(scriptableValue.toString()); } } Integer refId = jsObjectToRef.get(value); if (refId == null) { refId = nextRefId++; jsObjectToRef.put((Scriptable) value, refId); refToJsObject.put(refId, (Scriptable) value); } Value returnVal = new Value(); returnVal.setJsObject(new JsObjectRef(refId)); return returnVal; } return new Value(value); }
/* * Returning java objects works. No need to return NativeNumber, NativeString, * NativeBoolean, or Undefined. */ Object makeJsvalFromValue(Context jsContext, Value value) { switch (value.getType()) { case NULL: return null; case BOOLEAN: if (value.getBoolean()) { return Boolean.TRUE; } return Boolean.FALSE; case BYTE: return new Byte(value.getByte()); case CHAR: return new Character(value.getChar()); case SHORT: return new Short(value.getShort()); case INT: return new Integer(value.getInt()); case FLOAT: return new Float(value.getFloat()); case DOUBLE: return new Double(value.getDouble()); case STRING: return value.getString(); case JAVA_OBJECT: JavaObjectRef javaRef = value.getJavaObject(); return JavaObject.getOrCreateJavaObject(javaRef, sessionData, jsContext); case JS_OBJECT: Scriptable scriptable = refToJsObject.get(value.getJsObject().getRefid()); assert scriptable != null; return scriptable; case UNDEFINED: return Undefined.instance; } return null; }
@SuppressWarnings("unchecked") @Override public ExceptionOrReturnValue invoke( BrowserChannelClient channel, Value thisObj, String methodName, Value[] args) { if (logger.isLoggable(TreeLogger.DEBUG)) { logger.log( TreeLogger.DEBUG, "INVOKE: thisObj: " + thisObj + ", methodName: " + methodName + ", args: " + args); } /* * 1. lookup functions by name. 2. Find context and scope. 3. Convert * thisObject to ScriptableObject 4. Convert args 5. Get return value */ Context jsContext = Context.getCurrentContext(); ScriptableObject jsThis = null; if (thisObj.getType() == ValueType.NULL) { jsThis = window; } else { Object obj = makeJsvalFromValue(jsContext, thisObj); if (obj instanceof ScriptableObject) { jsThis = (ScriptableObject) obj; } else if (obj instanceof SimpleScriptableProxy<?>) { jsThis = ((SimpleScriptableProxy<SimpleScriptable>) obj).getDelegee(); } else { logger.log( TreeLogger.ERROR, "Unable to convert " + obj + " to either " + " ScriptableObject or SimpleScriptableProxy"); return new ExceptionOrReturnValue(true, new Value(null)); } } Object functionObject = ScriptableObject.getProperty(window, methodName); if (functionObject == ScriptableObject.NOT_FOUND) { logger.log( TreeLogger.ERROR, "function " + methodName + " NOT FOUND, thisObj: " + jsThis + ", methodName: " + methodName); // TODO: see if this maps to QUIT return new ExceptionOrReturnValue(true, new Value(null)); } Function jsFunction = (Function) functionObject; if (logger.isLoggable(TreeLogger.SPAM)) { logger.log(TreeLogger.SPAM, "INVOKE: jsFunction: " + jsFunction); } Object jsArgs[] = new Object[args.length]; for (int i = 0; i < args.length; i++) { jsArgs[i] = makeJsvalFromValue(jsContext, args[i]); } Object result = null; try { if (args.length == 1 && methodName.indexOf(REPLACE_METHOD_SIGNATURE) != -1) { // getUrl() is not visible String currentUrl = window.jsxGet_location().toString(); currentUrl = getUrlBeforeHash(currentUrl); String newUrl = getUrlBeforeHash((String) args[0].getValue()); if (!newUrl.equals(currentUrl)) { WebWindow webWindow = window.getWebWindow(); do { webWindow.getJobManager().removeAllJobs(); webWindow = webWindow.getParentWindow(); } while (webWindow != webWindow.getTopWindow()); } } result = jsEngine.callFunction(htmlPage, jsFunction, jsContext, window, jsThis, jsArgs); } catch (JavaScriptException ex) { if (logger.isLoggable(TreeLogger.INFO)) { logger.log( TreeLogger.INFO, "INVOKE: JavaScriptException " + ex + ", message: " + ex.getMessage() + " when invoking " + methodName); } return new ExceptionOrReturnValue(true, makeValueFromJsval(jsContext, ex.getValue())); } catch (Exception ex) { if (logger.isLoggable(TreeLogger.INFO)) { logger.log( TreeLogger.INFO, "INVOKE: exception " + ex + ", message: " + ex.getMessage() + " when invoking " + methodName); } return new ExceptionOrReturnValue(true, makeValueFromJsval(jsContext, Undefined.instance)); } if (logger.isLoggable(TreeLogger.INFO)) { logger.log(TreeLogger.INFO, "INVOKE: result: " + result + " of jsFunction: " + jsFunction); } return new ExceptionOrReturnValue(false, makeValueFromJsval(jsContext, result)); }