/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jef.script.javascript; import javax.script.Invocable; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.RhinoException; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.mozilla.javascript.Wrapper; /** * This class implements Rhino-like JavaAdapter to help implement a Java * interface in JavaScript. We support this using Invocable.getInterface. Using * this JavaAdapter, script author could write: * * var r = new java.lang.Runnable() { run: function() { script... } }; * * r.run(); new java.lang.Thread(r).start(); * * Note that Rhino's JavaAdapter support allows extending a Java class and/or * implementing one or more interfaces. This JavaAdapter implementation does not * support these. * * @version 1.0 * @author A. Sundararajan * @since 1.6 */ final class JavaAdapter extends ScriptableObject implements Function { private static final long serialVersionUID = 1L; private JavaAdapter(Invocable engine) { this.engine = engine; } static void init(Context cx, Scriptable scope, boolean sealed) throws RhinoException { RhinoTopLevel topLevel = (RhinoTopLevel) scope; Invocable engine = topLevel.getScriptEngine(); JavaAdapter obj = new JavaAdapter(engine); obj.setParentScope(scope); obj.setPrototype(getFunctionPrototype(scope)); /* * Note that we can't use defineProperty. A property of this name is * already defined in Context.initStandardObjects. We simply overwrite * the property value! */ ScriptableObject.putProperty(topLevel, "JavaAdapter", obj); } public String getClassName() { return "JavaAdapter"; } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) throws RhinoException { return construct(cx, scope, args); } @SuppressWarnings({ "unchecked", "rawtypes" }) public Scriptable construct(Context cx, Scriptable scope, Object[] args) throws RhinoException { if (args.length == 2) { Class clazz = null; Object obj1 = args[0]; if (obj1 instanceof Wrapper) { Object o = ((Wrapper) obj1).unwrap(); if (o instanceof Class && ((Class) o).isInterface()) { clazz = (Class) o; } } else if (obj1 instanceof Class) { if (((Class) obj1).isInterface()) { clazz = (Class) obj1; } } if (clazz == null) { throw Context.reportRuntimeError("JavaAdapter: first arg should be interface Class"); } Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); return Context.toObject(engine.getInterface(args[1], clazz), topLevel); } else { throw Context.reportRuntimeError("JavaAdapter requires two arguments"); } } private Invocable engine; }