diff --git a/app/src/main/java/io/legado/app/constant/AppConst.kt b/app/src/main/java/io/legado/app/constant/AppConst.kt index 155a58411..c66c168f9 100644 --- a/app/src/main/java/io/legado/app/constant/AppConst.kt +++ b/app/src/main/java/io/legado/app/constant/AppConst.kt @@ -5,6 +5,7 @@ import android.content.pm.PackageManager import android.provider.Settings import androidx.annotation.Keep import com.script.rhino.RhinoScriptEngine + import io.legado.app.BuildConfig import io.legado.app.utils.channel import splitties.init.appCtx diff --git a/book/build.gradle b/book/build.gradle index 0b075fdda..199d0094b 100644 --- a/book/build.gradle +++ b/book/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.library' + id 'org.jetbrains.kotlin.android' } android { diff --git a/rhino/build.gradle b/rhino/build.gradle index 983f9719b..f973b7437 100644 --- a/rhino/build.gradle +++ b/rhino/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.library' + id 'org.jetbrains.kotlin.android' } android { @@ -22,8 +23,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 } lint { checkDependencies true diff --git a/rhino/src/main/java/com/script/rhino/ExternalScriptable.kt b/rhino/src/main/java/com/script/rhino/ExternalScriptable.kt index 808aa62f0..70a8e4c9a 100644 --- a/rhino/src/main/java/com/script/rhino/ExternalScriptable.kt +++ b/rhino/src/main/java/com/script/rhino/ExternalScriptable.kt @@ -22,24 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import com.script.Bindings; -import com.script.ScriptContext; - -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.NativeJavaClass; -import org.mozilla.javascript.ScriptRuntime; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.Wrapper; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - +import com.script.ScriptContext +import org.mozilla.javascript.* +import org.mozilla.javascript.Function /** * ExternalScriptable is an implementation of Scriptable @@ -49,430 +36,252 @@ import java.util.Map; * @author A. Sundararajan * @since 1.6 */ +internal class ExternalScriptable @JvmOverloads constructor( + context: ScriptContext?, + indexedProps: MutableMap = HashMap() +) : Scriptable { + val context: ScriptContext + private val indexedProps: MutableMap + private var prototype: Scriptable? = null + private var parent: Scriptable? = null -final class ExternalScriptable implements Scriptable { - /* Underlying ScriptContext that we use to store - * named variables of this scope. - */ - private ScriptContext context; - - /* JavaScript allows variables to be named as numbers (indexed - * properties). This way arrays, objects (scopes) are treated uniformly. - * Note that JSR 223 API supports only String named variables and - * so we can't store these in Bindings. Also, JavaScript allows name - * of the property name to be even empty String! Again, JSR 223 API - * does not support empty name. So, we use the following fallback map - * to store such variables of this scope. This map is not exposed to - * JSR 223 API. We can just script objects "as is" and need not convert. - */ - private Map indexedProps; - - // my prototype - private Scriptable prototype; - // my parent scope, if any - private Scriptable parent; - - ExternalScriptable(ScriptContext context) { - this(context, new HashMap()); - } - - ExternalScriptable(ScriptContext context, Map indexedProps) { + init { if (context == null) { - throw new NullPointerException("context is null"); - } - this.context = context; - this.indexedProps = indexedProps; - } - - ScriptContext getContext() { - return context; - } - - private boolean isEmpty(String name) { - return name.equals(""); - } - - /** - * Return the name of the class. - */ - public String getClassName() { - return "Global"; - } - - /** - * Returns the value of the named property or NOT_FOUND. - * - * If the property was created using defineProperty, the - * appropriate getter method is called. - * - * @param name the name of the property - * @param start the object in which the lookup began - * @return the value of the property (may be null), or NOT_FOUND - */ - public synchronized Object get(String name, Scriptable start) { - if (isEmpty(name)) { - if (indexedProps.containsKey(name)) { - return indexedProps.get(name); - } else { - return NOT_FOUND; - } + throw NullPointerException("context is null") } else { - synchronized (context) { - int scope = context.getAttributesScope(name); - if (scope != -1) { - Object value = context.getAttribute(name, scope); - return Context.javaToJS(value, this); + this.context = context + this.indexedProps = indexedProps + } + } + + private fun isEmpty(name: String): Boolean { + return name == "" + } + + override fun getClassName(): String { + return "Global" + } + + @Synchronized + override fun get(name: String, start: Scriptable): Any { + return if (this.isEmpty(name)) { + indexedProps.getOrElse(name) { Scriptable.NOT_FOUND } + } else { + synchronized(context) { + val scope = context.getAttributesScope(name) + return if (scope != -1) { + val value = context.getAttribute(name, scope) + Context.javaToJS(value, this) } else { - return NOT_FOUND; + Scriptable.NOT_FOUND } } } } - /** - * Returns the value of the indexed property or NOT_FOUND. - * - * @param index the numeric index for the property - * @param start the object in which the lookup began - * @return the value of the property (may be null), or NOT_FOUND - */ - public synchronized Object get(int index, Scriptable start) { - if (indexedProps.containsKey(index)) { - return indexedProps.get(index); + @Synchronized + override fun get(index: Int, start: Scriptable): Any { + return indexedProps.getOrElse(index) { Scriptable.NOT_FOUND } + } + + @Synchronized + override fun has(name: String, start: Scriptable): Boolean { + return if (this.isEmpty(name)) { + indexedProps.containsKey(name) } else { - return NOT_FOUND; + synchronized(context) { return context.getAttributesScope(name) != -1 } } } - /** - * Returns true if the named property is defined. - * - * @param name the name of the property - * @param start the object in which the lookup began - * @return true if and only if the property was found in the object - */ - public synchronized boolean has(String name, Scriptable start) { - if (isEmpty(name)) { - return indexedProps.containsKey(name); - } else { - synchronized (context) { - return context.getAttributesScope(name) != -1; - } - } + @Synchronized + override fun has(index: Int, start: Scriptable): Boolean { + return indexedProps.containsKey(index) } - /** - * Returns true if the property index is defined. - * - * @param index the numeric index for the property - * @param start the object in which the lookup began - * @return true if and only if the property was found in the object - */ - public synchronized boolean has(int index, Scriptable start) { - return indexedProps.containsKey(index); - } - - /** - * Sets the value of the named property, creating it if need be. - * - * @param name the name of the property - * @param start the object whose property is being set - * @param value value to set the property to - */ - public void put(String name, Scriptable start, Object value) { - if (start == this) { - synchronized (this) { - if (isEmpty(name)) { - indexedProps.put(name, value); + override fun put(name: String, start: Scriptable, value: Any) { + if (start === this) { + synchronized(this) { + if (this.isEmpty(name)) { + indexedProps.put(name, value) } else { - synchronized (context) { - int scope = context.getAttributesScope(name); + synchronized(context) { + var scope = context.getAttributesScope(name) if (scope == -1) { - scope = ScriptContext.ENGINE_SCOPE; + scope = 100 } - context.setAttribute(name, jsToJava(value), scope); + context.setAttribute(name, jsToJava(value), scope) } } } } else { - start.put(name, start, value); + start.put(name, start, value) } } - /** - * Sets the value of the indexed property, creating it if need be. - * - * @param index the numeric index for the property - * @param start the object whose property is being set - * @param value value to set the property to - */ - public void put(int index, Scriptable start, Object value) { - if (start == this) { - synchronized (this) { - indexedProps.put(index, value); - } + override fun put(index: Int, start: Scriptable, value: Any) { + if (start === this) { + synchronized(this) { indexedProps.put(index, value) } } else { - start.put(index, start, value); + start.put(index, start, value) } } - /** - * Removes a named property from the object. - * - * If the property is not found, no action is taken. - * - * @param name the name of the property - */ - public synchronized void delete(String name) { - if (isEmpty(name)) { - indexedProps.remove(name); + @Synchronized + override fun delete(name: String) { + if (this.isEmpty(name)) { + indexedProps.remove(name) } else { - synchronized (context) { - int scope = context.getAttributesScope(name); + synchronized(context) { + val scope = context.getAttributesScope(name) if (scope != -1) { - context.removeAttribute(name, scope); + context.removeAttribute(name, scope) } } } } - /** - * Removes the indexed property from the object. - * - * If the property is not found, no action is taken. - * - * @param index the numeric index for the property - */ - public void delete(int index) { - indexedProps.remove(index); + override fun delete(index: Int) { + indexedProps.remove(index) } - /** - * Get the prototype of the object. - * @return the prototype - */ - public Scriptable getPrototype() { - return prototype; + override fun getPrototype(): Scriptable? { + return prototype } - /** - * Set the prototype of the object. - * @param prototype the prototype to set - */ - public void setPrototype(Scriptable prototype) { - this.prototype = prototype; + override fun setPrototype(prototype: Scriptable?) { + this.prototype = prototype } - /** - * Get the parent scope of the object. - * @return the parent scope - */ - public Scriptable getParentScope() { - return parent; + override fun getParentScope(): Scriptable? { + return parent } - /** - * Set the parent scope of the object. - * @param parent the parent scope to set - */ - public void setParentScope(Scriptable parent) { - this.parent = parent; + override fun setParentScope(parent: Scriptable?) { + this.parent = parent } - /** - * Get an array of property ids. - * - * Not all property ids need be returned. Those properties - * whose ids are not returned are considered non-enumerable. - * - * @return an array of Objects. Each entry in the array is either - * a java.lang.String or a java.lang.Number - */ - public synchronized Object[] getIds() { - String[] keys = getAllKeys(); - int size = keys.length + indexedProps.size(); - Object[] res = new Object[size]; - System.arraycopy(keys, 0, res, 0, keys.length); - int i = keys.length; - // now add all indexed properties - for (Object index : indexedProps.keySet()) { - res[i++] = index; + @Synchronized + override fun getIds(): Array { + val keys = allKeys + val size = keys.size + indexedProps.size + val res = arrayOfNulls(size) + System.arraycopy(keys, 0, res, 0, keys.size) + var i = keys.size + var index: Any + val var5: Iterator<*> = indexedProps.keys.iterator() + while (var5.hasNext()) { + index = var5.next()!! + res[i++] = index } - return res; + @Suppress("UNCHECKED_CAST") + return res as Array } - /** - * Get the default value of the object with a given hint. - * The hints are String.class for type String, Number.class for type - * Number, Scriptable.class for type Object, and Boolean.class for - * type Boolean.

- * - * A hint of null means "no hint". - * - * See ECMA 8.6.2.6. - * - * @param typeHint the type hint - * @return the default value - */ - public Object getDefaultValue(Class typeHint) { - for (int i=0; i < 2; i++) { - boolean tryToString; - if (typeHint == ScriptRuntime.StringClass) { - tryToString = (i == 0); - } else { - tryToString = (i == 1); - } - - String methodName; - Object[] args; - if (tryToString) { - methodName = "toString"; - args = ScriptRuntime.emptyArgs; - } else { - methodName = "valueOf"; - args = new Object[1]; - String hint; - if (typeHint == null) { - hint = "undefined"; - } else if (typeHint == ScriptRuntime.StringClass) { - hint = "string"; - } else if (typeHint == ScriptRuntime.ScriptableClass) { - hint = "object"; - } else if (typeHint == ScriptRuntime.FunctionClass) { - hint = "function"; - } else if (typeHint == ScriptRuntime.BooleanClass - || typeHint == Boolean.TYPE) - { - hint = "boolean"; - } else if (typeHint == ScriptRuntime.NumberClass || - typeHint == ScriptRuntime.ByteClass || - typeHint == Byte.TYPE || - typeHint == ScriptRuntime.ShortClass || - typeHint == Short.TYPE || - typeHint == ScriptRuntime.IntegerClass || - typeHint == Integer.TYPE || - typeHint == ScriptRuntime.FloatClass || - typeHint == Float.TYPE || - typeHint == ScriptRuntime.DoubleClass || - typeHint == Double.TYPE) - { - hint = "number"; + override fun getDefaultValue(typeHint: Class<*>?): Any { + for (i in 0..1) { + val tryToString: Boolean = + if (typeHint == ScriptRuntime.StringClass) { + i == 0 } else { - throw Context.reportRuntimeError( - "Invalid JavaScript value of type " + - typeHint); + i == 1 } - args[0] = hint; + var methodName: String + var args: Array + if (tryToString) { + methodName = "toString" + args = ScriptRuntime.emptyArgs + } else { + methodName = "valueOf" + args = arrayOfNulls(1) + val hint: String = if (typeHint == null) { + "undefined" + } else if (typeHint == ScriptRuntime.StringClass) { + "string" + } else if (typeHint == ScriptRuntime.ScriptableClass) { + "object" + } else if (typeHint == ScriptRuntime.FunctionClass) { + "function" + } else if (typeHint != ScriptRuntime.BooleanClass && typeHint != java.lang.Boolean.TYPE) { + if (typeHint != ScriptRuntime.NumberClass && typeHint != ScriptRuntime.ByteClass && typeHint != java.lang.Byte.TYPE && typeHint != ScriptRuntime.ShortClass && typeHint != java.lang.Short.TYPE && typeHint != ScriptRuntime.IntegerClass && typeHint != Integer.TYPE && typeHint != ScriptRuntime.FloatClass && typeHint != java.lang.Float.TYPE && typeHint != ScriptRuntime.DoubleClass && typeHint != java.lang.Double.TYPE) { + throw Context.reportRuntimeError("Invalid JavaScript value of type $typeHint") + } + "number" + } else { + "boolean" + } + args[0] = hint } - Object v = ScriptableObject.getProperty(this, methodName); - if (!(v instanceof Function)) - continue; - Function fun = (Function) v; - Context cx = RhinoScriptEngine.enterContext(); - try { - v = fun.call(cx, fun.getParentScope(), this, args); - } finally { - cx.exit(); - } - if (v != null) { - if (!(v instanceof Scriptable)) { - return v; + var v = ScriptableObject.getProperty(this, methodName) + if (v is Function) { + val `fun` = v + val cx = Context.enter() + v = try { + `fun`.call(cx, `fun`.parentScope, this, args) + } finally { + Context.exit() } - if (typeHint == ScriptRuntime.ScriptableClass - || typeHint == ScriptRuntime.FunctionClass) - { - return v; - } - if (tryToString && v instanceof Wrapper) { - // Let a wrapped java.lang.String pass for a primitive - // string. - Object u = ((Wrapper)v).unwrap(); - if (u instanceof String) - return u; - } - } - } - // fall through to error - String arg = (typeHint == null) ? "undefined" : typeHint.getName(); - throw Context.reportRuntimeError( - "Cannot find default value for object " + arg); - } - - /** - * Implements the instanceof operator. - * - * @param instance The value that appeared on the LHS of the instanceof - * operator - * @return true if "this" appears in value's prototype chain - * - */ - public boolean hasInstance(Scriptable instance) { - // Default for JS objects (other than Function) is to do prototype - // chasing. - Scriptable proto = instance.getPrototype(); - while (proto != null) { - if (proto.equals(this)) return true; - proto = proto.getPrototype(); - } - return false; - } - - private String[] getAllKeys() { - ArrayList list = new ArrayList(); - synchronized (context) { - for (int scope : context.getScopes()) { - Bindings bindings = context.getBindings(scope); - if (bindings != null) { - list.ensureCapacity(bindings.size()); - for (String key : bindings.keySet()) { - list.add(key); + if (v != null) { + if (v !is Scriptable) { + return v + } + if (typeHint == ScriptRuntime.ScriptableClass || typeHint == ScriptRuntime.FunctionClass) { + return v + } + if (tryToString && v is Wrapper) { + val u = (v as Wrapper).unwrap() + if (u is String) { + return u + } } } } } - String[] res = new String[list.size()]; - list.toArray(res); - return res; + val arg = if (typeHint == null) "undefined" else typeHint.name + throw Context.reportRuntimeError("找不到对象的默认值 $arg") } - /** - * We convert script values to the nearest Java value. - * We unwrap wrapped Java objects so that access from - * Bindings.get() would return "workable" value for Java. - * But, at the same time, we need to make few special cases - * and hence the following function is used. - */ - private Object jsToJava(Object jsObj) { - if (jsObj instanceof Wrapper) { - Wrapper njb = (Wrapper) jsObj; - /* importClass feature of ImporterTopLevel puts - * NativeJavaClass in global scope. If we unwrap - * it, importClass won't work. - */ - if (njb instanceof NativeJavaClass) { - return njb; + override fun hasInstance(instance: Scriptable): Boolean { + var proto = instance.prototype + while (proto != null) { + if (proto == this) { + return true } + proto = proto.prototype + } + return false + } - /* script may use Java primitive wrapper type objects - * (such as java.lang.Integer, java.lang.Boolean etc) - * explicitly. If we unwrap, then these script objects - * will become script primitive types. For example, - * - * var x = new java.lang.Double(3.0); print(typeof x); - * - * will print 'number'. We don't want that to happen. - */ - Object obj = njb.unwrap(); - if (obj instanceof Number || obj instanceof String || - obj instanceof Boolean || obj instanceof Character) { - // special type wrapped -- we just leave it as is. - return njb; - } else { - // return unwrapped object for any other object. - return obj; + private val allKeys: Array + get() { + val list = ArrayList() + synchronized(context) { + val var3: Iterator<*> = context.scopes.iterator() + while (var3.hasNext()) { + val scope = var3.next() as Int + val bindings = context.getBindings(scope) + if (bindings != null) { + list.ensureCapacity(bindings.size) + val var6: Iterator<*> = bindings.keys.iterator() + while (var6.hasNext()) { + val key = var6.next() as String + list.add(key) + } + } + } } - } else { // not-a-Java-wrapper - return jsObj; + return list.toTypedArray() + } + + private fun jsToJava(jsObj: Any): Any { + return if (jsObj is Wrapper) { + if (jsObj is NativeJavaClass) { + jsObj + } else { + val obj = jsObj.unwrap() + if (obj !is Number && obj !is String && obj !is Boolean && obj !is Char) obj else jsObj + } + } else { + jsObj } } -} +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/InterfaceImplementor.kt b/rhino/src/main/java/com/script/rhino/InterfaceImplementor.kt index adba80372..624f012ed 100644 --- a/rhino/src/main/java/com/script/rhino/InterfaceImplementor.kt +++ b/rhino/src/main/java/com/script/rhino/InterfaceImplementor.kt @@ -22,97 +22,75 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; +import com.script.Invocable +import com.script.ScriptException +import java.lang.reflect.InvocationHandler +import java.lang.reflect.Method +import java.lang.reflect.Proxy +import java.security.AccessControlContext +import java.security.AccessController +import java.security.PrivilegedExceptionAction -import com.script.Invocable; -import com.script.ScriptException; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.PrivilegedExceptionAction; - - -/* +/** * java.lang.reflect.Proxy based interface implementor. This is meant * to be used to implement Invocable.getInterface. * * @author Mike Grogan * @since 1.6 */ -public class InterfaceImplementor { - - private Invocable engine; - - /** Creates a new instance of Invocable */ - public InterfaceImplementor(Invocable engine) { - this.engine = engine; - } - - private final class InterfaceImplementorInvocationHandler - implements InvocationHandler { - private Object thiz; - private AccessControlContext accCtxt; - - public InterfaceImplementorInvocationHandler(Object thiz, - AccessControlContext accCtxt) { - this.thiz = thiz; - this.accCtxt = accCtxt; - } - - public Object invoke(Object proxy , Method method, Object[] args) - throws java.lang.Throwable { - // give chance to convert input args - args = convertArguments(method, args); - Object result; - final Method m = method; - final Object[] a = args; - result = AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - if (thiz == null) { - return engine.invokeFunction(m.getName(), a); - } else { - return engine.invokeMethod(thiz, m.getName(), a); - } - } - }, accCtxt); - // give chance to convert the method result - return convertResult(method, result); +open class InterfaceImplementor(private val engine: Invocable) { + @Throws(ScriptException::class) + fun getInterface(thiz: Any?, iface: Class?): T? { + return if (iface != null && iface.isInterface) { + if (!isImplemented(thiz, iface)) { + null + } else { + val accCtxt = AccessController.getContext() + iface.cast( + Proxy.newProxyInstance( + iface.classLoader, + arrayOf>(iface), + InterfaceImplementorInvocationHandler(thiz, accCtxt) + ) + ) + } + } else { + throw IllegalArgumentException("interface Class expected") } } - public T getInterface(Object thiz, Class iface) - throws ScriptException { - if (iface == null || !iface.isInterface()) { - throw new IllegalArgumentException("interface Class expected"); + protected open fun isImplemented(thiz: Any?, iface: Class<*>): Boolean { + return true + } + + @Throws(ScriptException::class) + protected open fun convertResult(method: Method?, res: Any): Any { + return res + } + + @Throws(ScriptException::class) + protected fun convertArguments(method: Method?, args: Array): Array { + return args + } + + private inner class InterfaceImplementorInvocationHandler( + private val thiz: Any?, + private val accCtxt: AccessControlContext + ) : InvocationHandler { + @Throws(Throwable::class) + override fun invoke(proxy: Any, method: Method, args: Array): Any { + val finalArgs = convertArguments(method, args) + val result = AccessController.doPrivileged(PrivilegedExceptionAction { + if (thiz == null) engine.invokeFunction( + method.name, + *finalArgs + ) else engine.invokeMethod( + thiz, method.name, *finalArgs + ) + } as PrivilegedExceptionAction, accCtxt) + return convertResult(method, result) } - if (! isImplemented(thiz, iface)) { - return null; - } - AccessControlContext accCtxt = AccessController.getContext(); - return iface.cast(Proxy.newProxyInstance(iface.getClassLoader(), - new Class[]{iface}, - new InterfaceImplementorInvocationHandler(thiz, accCtxt))); - } - - protected boolean isImplemented(Object thiz, Class iface) { - return true; - } - - // called to convert method result after invoke - protected Object convertResult(Method method, Object res) - throws ScriptException { - // default is identity conversion - return res; - } - - // called to convert method arguments before invoke - protected Object[] convertArguments(Method method, Object[] args) - throws ScriptException { - // default is identity conversion - return args; } } \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/JSAdapter.kt b/rhino/src/main/java/com/script/rhino/JSAdapter.kt index 5c1955ba4..3930e34c5 100644 --- a/rhino/src/main/java/com/script/rhino/JSAdapter.kt +++ b/rhino/src/main/java/com/script/rhino/JSAdapter.kt @@ -22,16 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.NativeArray; -import org.mozilla.javascript.NativeJavaArray; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.* +import org.mozilla.javascript.Function /** * JSAdapter is java.lang.reflect.Proxy equivalent for JavaScript. JSAdapter @@ -40,21 +34,21 @@ import org.mozilla.javascript.ScriptableObject; * * Example: * - * var y = { - * __get__ : function (name) { ... } - * __has__ : function (name) { ... } - * __put__ : function (name, value) {...} - * __delete__ : function (name) { ... } - * __getIds__ : function () { ... } - * }; + * var y = { + * __get__ : function (name) { ... } + * __has__ : function (name) { ... } + * __put__ : function (name, value) {...} + * __delete__ : function (name) { ... } + * __getIds__ : function () { ... } + * }; * - * var x = new JSAdapter(y); + * var x = new JSAdapter(y); * - * x.i; // calls y.__get__ - * i in x; // calls y.__has__ - * x.p = 10; // calls y.__put__ - * delete x.p; // calls y.__delete__ - * for (i in x) { print(i); } // calls y.__getIds__ + * x.i; // calls y.__get__ + * i in x; // calls y.__has__ + * x.p = 10; // calls y.__put__ + * delete x.p; // calls y.__delete__ + * for (i in x) { print(i); } // calls y.__getIds__ * * If a special JavaScript method is not found in the adaptee, then JSAdapter * forwards the property access to the adaptee itself. @@ -74,270 +68,239 @@ import org.mozilla.javascript.ScriptableObject; * @author A. Sundararajan * @since 1.6 */ -public final class JSAdapter implements Scriptable, Function { - private JSAdapter(Scriptable obj) { - setAdaptee(obj); +class JSAdapter private constructor(val adaptee: Scriptable) : Scriptable, Function { + private var prototype: Scriptable? = null + private var parent: Scriptable? = null + private var isPrototype = false + + override fun getClassName(): String { + return "JSAdapter" } - // initializer to setup JSAdapter prototype in the given scope - public static void init(Context cx, Scriptable scope, boolean sealed) - throws RhinoException { - JSAdapter obj = new JSAdapter(cx.newObject(scope)); - obj.setParentScope(scope); - obj.setPrototype(getFunctionPrototype(scope)); - obj.isPrototype = true; - ScriptableObject.defineProperty(scope, "JSAdapter", obj, - ScriptableObject.DONTENUM); - } - - public String getClassName() { - return "JSAdapter"; - } - - public Object get(String name, Scriptable start) { - Function func = getAdapteeFunction(GET_PROP); - if (func != null) { - return call(func, new Object[] { name }); + override fun get(name: String, start: Scriptable): Any { + val func = getAdapteeFunction(GET_PROP) + return if (func != null) { + this.call(func, arrayOf(name)) } else { - start = getAdaptee(); - return start.get(name, start); + adaptee[name, adaptee] } } - public Object get(int index, Scriptable start) { - Function func = getAdapteeFunction(GET_PROP); - if (func != null) { - return call(func, new Object[] {index}); + override fun get(index: Int, start: Scriptable): Any { + val func = getAdapteeFunction(GET_PROP) + return if (func != null) { + this.call(func, arrayOf(index)) } else { - start = getAdaptee(); - return start.get(index, start); + adaptee[index, adaptee] } } - public boolean has(String name, Scriptable start) { - Function func = getAdapteeFunction(HAS_PROP); - if (func != null) { - Object res = call(func, new Object[] { name }); - return Context.toBoolean(res); + override fun has(name: String, start: Scriptable): Boolean { + val func = getAdapteeFunction(HAS_PROP) + return if (func != null) { + val res = this.call(func, arrayOf(name)) + Context.toBoolean(res) } else { - start = getAdaptee(); - return start.has(name, start); + adaptee.has(name, adaptee) } } - public boolean has(int index, Scriptable start) { - Function func = getAdapteeFunction(HAS_PROP); - if (func != null) { - Object res = call(func, new Object[] {index}); - return Context.toBoolean(res); + override fun has(index: Int, start: Scriptable): Boolean { + val func = getAdapteeFunction(HAS_PROP) + return if (func != null) { + val res = this.call(func, arrayOf(index)) + Context.toBoolean(res) } else { - start = getAdaptee(); - return start.has(index, start); + adaptee.has(index, adaptee) } } - public void put(String name, Scriptable start, Object value) { - if (start == this) { - Function func = getAdapteeFunction(PUT_PROP); + override fun put(name: String, start: Scriptable, value: Any) { + if (start === this) { + val func = getAdapteeFunction(PUT_PROP) if (func != null) { - call(func, new Object[] { name, value }); + this.call(func, arrayOf(name, value)) } else { - start = getAdaptee(); - start.put(name, start, value); + adaptee.put(name, adaptee, value) } } else { - start.put(name, start, value); + start.put(name, start, value) } } - public void put(int index, Scriptable start, Object value) { - if (start == this) { - Function func = getAdapteeFunction(PUT_PROP); - if( func != null) { - call(func, new Object[] {index, value }); + override fun put(index: Int, start: Scriptable, value: Any) { + if (start === this) { + val func = getAdapteeFunction(PUT_PROP) + if (func != null) { + this.call(func, arrayOf(index, value)) } else { - start = getAdaptee(); - start.put(index, start, value); + adaptee.put(index, adaptee, value) } } else { - start.put(index, start, value); + start.put(index, start, value) } } - public void delete(String name) { - Function func = getAdapteeFunction(DEL_PROP); + override fun delete(name: String) { + val func = getAdapteeFunction(DEL_PROP) if (func != null) { - call(func, new Object[] { name }); + this.call(func, arrayOf(name)) } else { - getAdaptee().delete(name); + adaptee.delete(name) } } - public void delete(int index) { - Function func = getAdapteeFunction(DEL_PROP); + override fun delete(index: Int) { + val func = getAdapteeFunction(DEL_PROP) if (func != null) { - call(func, new Object[] {index}); + this.call(func, arrayOf(index)) } else { - getAdaptee().delete(index); + adaptee.delete(index) } } - public Scriptable getPrototype() { - return prototype; + override fun getPrototype(): Scriptable? { + return prototype } - public void setPrototype(Scriptable prototype) { - this.prototype = prototype; + override fun setPrototype(prototype: Scriptable?) { + this.prototype = prototype } - public Scriptable getParentScope() { - return parent; + override fun getParentScope(): Scriptable? { + return parent } - public void setParentScope(Scriptable parent) { - this.parent = parent; + override fun setParentScope(parent: Scriptable?) { + this.parent = parent } - public Object[] getIds() { - Function func = getAdapteeFunction(GET_PROPIDS); - if (func != null) { - Object val = call(func, new Object[0]); - // in most cases, adaptee would return native JS array - if (val instanceof NativeArray) { - NativeArray array = (NativeArray) val; - Object[] res = new Object[(int)array.getLength()]; - for (int index = 0; index < res.length; index++) { - res[index] = mapToId(array.get(index, array)); - } - return res; - } else if (val instanceof NativeJavaArray) { - // may be attempt wrapped Java array - Object tmp = ((NativeJavaArray)val).unwrap(); - Object[] res; - if (tmp.getClass() == Object[].class) { - Object[] array = (Object[]) tmp; - res = new Object[array.length]; - for (int index = 0; index < array.length; index++) { - res[index] = mapToId(array[index]); + override fun getIds(): Array { + val func = getAdapteeFunction(GET_PROPIDS) + return if (func == null) { + adaptee.ids + } else { + val val1 = this.call(func, arrayOfNulls(0)) + val res: Array + when (val1) { + is NativeArray -> { + res = arrayOfNulls(val1.length.toInt()) + for (index in res.indices) { + res[index] = mapToId(val1[index, val1]) } - } else { - // just return an empty array - res = Context.emptyArgs; + res + } + !is NativeJavaArray -> { + Context.emptyArgs + } + else -> { + val tmp = val1.unwrap() + if (tmp.javaClass == Array::class.java) { + val array = tmp as Array<*> + res = arrayOfNulls(array.size) + for (index in array.indices) { + res[index] = mapToId(array[index]) + } + } else { + res = Context.emptyArgs + } + res } - return res; - } else { - // some other return type, just return empty array - return Context.emptyArgs; } - } else { - return getAdaptee().getIds(); } } - public boolean hasInstance(Scriptable scriptable) { - if (scriptable instanceof JSAdapter) { - return true; + override fun hasInstance(scriptable: Scriptable): Boolean { + return if (scriptable is JSAdapter) { + true } else { - Scriptable proto = scriptable.getPrototype(); + var proto = scriptable.prototype while (proto != null) { - if (proto.equals(this)) return true; - proto = proto.getPrototype(); + if (proto == this) { + return true + } + proto = proto.prototype } - return false; + false } } - public Object getDefaultValue(Class hint) { - return getAdaptee().getDefaultValue(hint); + override fun getDefaultValue(hint: Class<*>?): Any { + return adaptee.getDefaultValue(hint) } - public Object call(Context cx, Scriptable scope, Scriptable thisObj, - Object[] args) - throws RhinoException { - if (isPrototype) { - return construct(cx, scope, args); + @Throws(RhinoException::class) + override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array): Any { + return if (isPrototype) { + construct(cx, scope, args) } else { - Scriptable tmp = getAdaptee(); - if (tmp instanceof Function) { - return ((Function)tmp).call(cx, scope, tmp, args); + val tmp = adaptee + if (tmp is Function) { + tmp.call(cx, scope, tmp, args) } else { - throw Context.reportRuntimeError("TypeError: not a function"); + throw Context.reportRuntimeError("TypeError: not a function") } } } - public Scriptable construct(Context cx, Scriptable scope, Object[] args) - throws RhinoException { - if (isPrototype) { - Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); - JSAdapter newObj; - if (args.length > 0) { - newObj = new JSAdapter(Context.toObject(args[0], topLevel)); + @Throws(RhinoException::class) + override fun construct(cx: Context, scope: Scriptable, args: Array): Scriptable { + val tmp: Scriptable? + return if (isPrototype) { + tmp = ScriptableObject.getTopLevelScope(scope) + if (args.size > 0) { + JSAdapter(Context.toObject(args[0], tmp)) } else { - throw Context.reportRuntimeError("JSAdapter requires adaptee"); + throw Context.reportRuntimeError("JSAdapter requires adaptee") } - return newObj; } else { - Scriptable tmp = getAdaptee(); - if (tmp instanceof Function) { - return ((Function)tmp).construct(cx, scope, args); + tmp = adaptee + if (tmp is Function) { + tmp.construct(cx, scope, args) } else { - throw Context.reportRuntimeError("TypeError: not a constructor"); + throw Context.reportRuntimeError("TypeError: not a constructor") } } } - public Scriptable getAdaptee() { - return adaptee; + private fun mapToId(tmp: Any?): Any { + return if (tmp is Double) tmp.toInt() else Context.toString(tmp) } - public void setAdaptee(Scriptable adaptee) { - if (adaptee == null) { - throw new NullPointerException("adaptee can not be null"); - } - this.adaptee = adaptee; + private fun getAdapteeFunction(name: String): Function? { + val o = ScriptableObject.getProperty(adaptee, name) + return if (o is Function) o else null } - //-- internals only below this point - - // map a property id. Property id can only be an Integer or String - private Object mapToId(Object tmp) { - if (tmp instanceof Double) { - return ((Double) tmp).intValue(); - } else { - return Context.toString(tmp); + private fun call(func: Function, args: Array): Any { + val cx = Context.getCurrentContext() + val thisObj = adaptee + val scope = func.parentScope + return try { + func.call(cx, scope, thisObj, args) + } catch (var7: RhinoException) { + throw Context.reportRuntimeError(var7.message) } } - private static Scriptable getFunctionPrototype(Scriptable scope) { - return ScriptableObject.getFunctionPrototype(scope); - } + companion object { + private const val GET_PROP = "__get__" + private const val HAS_PROP = "__has__" + private const val PUT_PROP = "__put__" + private const val DEL_PROP = "__delete__" + private const val GET_PROPIDS = "__getIds__" - private Function getAdapteeFunction(String name) { - Object o = ScriptableObject.getProperty(getAdaptee(), name); - return (o instanceof Function)? (Function)o : null; - } + @Throws(RhinoException::class) + fun init(cx: Context, scope: Scriptable, sealed: Boolean) { + val obj = JSAdapter(cx.newObject(scope)) + obj.parentScope = scope + obj.setPrototype(getFunctionPrototype(scope)) + obj.isPrototype = true + ScriptableObject.defineProperty(scope, "JSAdapter", obj, 2) + } - private Object call(Function func, Object[] args) { - Context cx = Context.getCurrentContext(); - Scriptable thisObj = getAdaptee(); - Scriptable scope = func.getParentScope(); - try { - return func.call(cx, scope, thisObj, args); - } catch (RhinoException re) { - throw Context.reportRuntimeError(re.getMessage()); + private fun getFunctionPrototype(scope: Scriptable): Scriptable { + return ScriptableObject.getFunctionPrototype(scope) } } - - private Scriptable prototype; - private Scriptable parent; - private Scriptable adaptee; - private boolean isPrototype; - - // names of adaptee JavaScript functions - private static final String GET_PROP = "__get__"; - private static final String HAS_PROP = "__has__"; - private static final String PUT_PROP = "__put__"; - private static final String DEL_PROP = "__delete__"; - private static final String GET_PROPIDS = "__getIds__"; -} +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/JavaAdapter.kt b/rhino/src/main/java/com/script/rhino/JavaAdapter.kt index ecda70aef..548710594 100644 --- a/rhino/src/main/java/com/script/rhino/JavaAdapter.kt +++ b/rhino/src/main/java/com/script/rhino/JavaAdapter.kt @@ -22,31 +22,26 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import com.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; - - +import com.script.Invocable +import org.mozilla.javascript.* +import org.mozilla.javascript.Function /** * 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(); + * 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 @@ -55,60 +50,54 @@ import org.mozilla.javascript.Wrapper; * @author A. Sundararajan * @since 1.6 */ -final class JavaAdapter extends ScriptableObject implements Function { - private JavaAdapter(Invocable engine) { - this.engine = engine; +internal class JavaAdapter private constructor(private val engine: Invocable) : ScriptableObject(), + Function { + override fun getClassName(): String { + return "JavaAdapter" } - 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); + @Throws(RhinoException::class) + override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array): Any { + return construct(cx, scope, args) } - public String getClassName() { - return "JavaAdapter"; - } - - public Object call(Context cx, Scriptable scope, Scriptable thisObj, - Object[] args) throws RhinoException { - return construct(cx, scope, args); - } - - 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; + @Throws(RhinoException::class) + override fun construct(cx: Context, scope: Scriptable, args: Array): Scriptable { + return if (args.size == 2) { + var clazz: Class<*>? = null + val obj1 = args[0] + if (obj1 is Wrapper) { + val o = obj1.unwrap() + if (o is Class<*> && o.isInterface) { + clazz = o } + } else if (obj1 is Class<*> && obj1.isInterface) { + clazz = obj1 } if (clazz == null) { - throw Context.reportRuntimeError("JavaAdapter: first arg should be interface Class"); + throw Context.reportRuntimeError("JavaAdapter: first arg should be interface Class") + } else { + val topLevel = getTopLevelScope(scope) + Context.toObject( + engine.getInterface(args[1], clazz), + topLevel + ) } - - Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); - return cx.toObject(engine.getInterface(args[1], clazz), topLevel); } else { - throw Context.reportRuntimeError("JavaAdapter requires two arguments"); + throw Context.reportRuntimeError("JavaAdapter requires two arguments") } } - private Invocable engine; -} + companion object { + @JvmStatic + @Throws(RhinoException::class) + fun init(cx: Context?, scope: Scriptable, sealed: Boolean) { + val topLevel = scope as RhinoTopLevel + val engine: Invocable = topLevel.scriptEngine + val obj = JavaAdapter(engine) + obj.parentScope = scope + obj.prototype = getFunctionPrototype(scope) + putProperty(topLevel, "JavaAdapter", obj) + } + } +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/RhinoClassShutter.kt b/rhino/src/main/java/com/script/rhino/RhinoClassShutter.kt index 7d9e3bce9..b4463c7e6 100644 --- a/rhino/src/main/java/com/script/rhino/RhinoClassShutter.kt +++ b/rhino/src/main/java/com/script/rhino/RhinoClassShutter.kt @@ -22,13 +22,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import org.mozilla.javascript.ClassShutter; - -import java.util.HashMap; -import java.util.Map; +import org.mozilla.javascript.ClassShutter /** * This class prevents script access to certain sensitive classes. @@ -38,43 +34,38 @@ import java.util.Map; * @author A. Sundararajan * @since 1.6 */ -final class RhinoClassShutter implements ClassShutter { - private static Map protectedClasses; - private static RhinoClassShutter theInstance; - - private RhinoClassShutter() { - } - - static synchronized ClassShutter getInstance() { - if (theInstance == null) { - theInstance = new RhinoClassShutter(); - protectedClasses = new HashMap(); - - // For now, we just have AccessController. Allowing scripts - // to this class will allow it to execute doPrivileged in - // bootstrap context. We can add more classes for other reasons. - protectedClasses.put("java.lang.Class", Boolean.TRUE); - protectedClasses.put("java.lang.Runtime", Boolean.TRUE); - protectedClasses.put("java.io.File", Boolean.TRUE); - protectedClasses.put("java.security.AccessController", Boolean.TRUE); - } - return theInstance; - } - - public boolean visibleToScripts(String fullClassName) { - // first do the security check. - SecurityManager sm = System.getSecurityManager(); +internal class RhinoClassShutter private constructor() : ClassShutter { + override fun visibleToScripts(fullClassName: String): Boolean { + val sm = System.getSecurityManager() if (sm != null) { - int i = fullClassName.lastIndexOf("."); + val i = fullClassName.lastIndexOf(".") if (i != -1) { try { - sm.checkPackageAccess(fullClassName.substring(0, i)); - } catch (SecurityException se) { - return false; + sm.checkPackageAccess(fullClassName.substring(0, i)) + } catch (var5: SecurityException) { + return false } } } - // now, check is it a protected class. - return protectedClasses.get(fullClassName) == null; + return protectedClasses[fullClassName] == null } -} + + companion object { + + @JvmStatic + val protectedClasses by lazy { + val protectedClasses = HashMap() + protectedClasses["java.lang.Runtime"] = java.lang.Boolean.TRUE + protectedClasses["java.io.File"] = java.lang.Boolean.TRUE + protectedClasses["java.security.AccessController"] = java.lang.Boolean.TRUE + protectedClasses + } + + @JvmStatic + val instance: ClassShutter by lazy { + val theInstance = RhinoClassShutter() + theInstance + } + + } +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt b/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt index 0d3e9c759..8d7d87e2c 100644 --- a/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt +++ b/rhino/src/main/java/com/script/rhino/RhinoCompiledScript.kt @@ -22,20 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import com.script.CompiledScript; -import com.script.ScriptContext; -import com.script.ScriptEngine; -import com.script.ScriptException; - -import org.mozilla.javascript.Context; -import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Script; -import org.mozilla.javascript.Scriptable; - +import com.script.CompiledScript +import com.script.ScriptContext +import com.script.ScriptEngine +import com.script.ScriptException +import org.mozilla.javascript.* /** * Represents compiled JavaScript code. @@ -43,46 +36,36 @@ import org.mozilla.javascript.Scriptable; * @author Mike Grogan * @since 1.6 */ -final class RhinoCompiledScript extends CompiledScript { +internal class RhinoCompiledScript( + private val engine: RhinoScriptEngine, + private val script: Script +) : CompiledScript() { - private com.script.rhino.RhinoScriptEngine engine; - private Script script; - - - RhinoCompiledScript(com.script.rhino.RhinoScriptEngine engine, Script script) { - this.engine = engine; - this.script = script; - } - - public Object eval(ScriptContext context) throws ScriptException { - - Object result = null; - Context cx = RhinoScriptEngine.enterContext(); + @Throws(ScriptException::class) + override fun eval(context: ScriptContext): Any? { + val cx = Context.enter() + val result: Any? try { - - Scriptable scope = engine.getRuntimeScope(context); - Object ret = script.exec(cx, scope); - result = engine.unwrapReturnValue(ret); - } catch (RhinoException re) { - int line = (line = re.lineNumber()) == 0 ? -1 : line; - String msg; - if (re instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException)re).getValue()); + val scope = engine.getRuntimeScope(context) + val ret = script.exec(cx, scope) + result = engine.unwrapReturnValue(ret) + } catch (re: RhinoException) { + val line = if (re.lineNumber() == 0) -1 else re.lineNumber() + val msg: String = if (re is JavaScriptException) { + re.value.toString() } else { - msg = re.toString(); + re.toString() } - ScriptException se = new ScriptException(msg, re.sourceName(), line); - se.initCause(re); - throw se; + val se = ScriptException(msg, re.sourceName(), line) + se.initCause(re) + throw se } finally { - Context.exit(); + Context.exit() } - - return result; + return result } - public ScriptEngine getEngine() { - return engine; + override fun getEngine(): ScriptEngine { + return engine } - -} +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt b/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt index 0f110e7a1..14066983d 100644 --- a/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt +++ b/rhino/src/main/java/com/script/rhino/RhinoScriptEngine.kt @@ -22,440 +22,358 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - - -import com.script.AbstractScriptEngine; -import com.script.Bindings; -import com.script.Compilable; -import com.script.CompiledScript; -import com.script.Invocable; -import com.script.ScriptContext; -import com.script.ScriptEngine; -import com.script.ScriptException; -import com.script.SimpleBindings; - -import org.mozilla.javascript.Callable; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.ContextFactory; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.JavaScriptException; -import org.mozilla.javascript.RhinoException; -import org.mozilla.javascript.Script; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.Undefined; -import org.mozilla.javascript.Wrapper; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.lang.reflect.Method; -import java.security.AccessControlContext; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.AllPermission; -import java.security.PrivilegedAction; -import java.util.HashMap; -import java.util.Map; - +import com.script.* +import com.script.rhino.RhinoClassShutter.Companion.instance +import org.intellij.lang.annotations.Language +import org.mozilla.javascript.* +import org.mozilla.javascript.Function +import java.io.IOException +import java.io.Reader +import java.io.StringReader +import java.lang.reflect.Method +import java.security.* /** - * Implementation of ScriptEngine using the Mozilla Rhino + * Implementation of `ScriptEngine` using the Mozilla Rhino * interpreter. * * @author Mike Grogan * @author A. Sundararajan * @since 1.6 */ -public final class RhinoScriptEngine extends AbstractScriptEngine - implements Invocable, Compilable { +class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { + var accessContext: AccessControlContext? = null + private var topLevel: RhinoTopLevel? = null + private val indexedProps: MutableMap + private val implementor: InterfaceImplementor - private static final boolean DEBUG = false; - - private AccessControlContext accCtxt; - - /* Scope where standard JavaScript objects and our - * extensions to it are stored. Note that these are not - * user defined engine level global variables. These are - * variables have to be there on all compliant ECMAScript - * scopes. We put these standard objects in this top level. - */ - private com.script.rhino.RhinoTopLevel topLevel; - - /* map used to store indexed properties in engine scope - * refer to comment on 'indexedProps' in ExternalScriptable.java. - */ - private Map indexedProps; - - private InterfaceImplementor implementor; - - private static final int languageVersion = getLanguageVersion(); - private static final int optimizationLevel = getOptimizationLevel(); - - static { - ContextFactory.initGlobal(new ContextFactory() { - /** - * Create new Context instance to be associated with the current thread. - */ - @Override - protected Context makeContext() { - Context cx = super.makeContext(); - cx.setLanguageVersion(languageVersion); - cx.setOptimizationLevel(optimizationLevel); - cx.setClassShutter(com.script.rhino.RhinoClassShutter.getInstance()); - cx.setWrapFactory(com.script.rhino.RhinoWrapFactory.getInstance()); - return cx; - } - - /** - * Execute top call to script or function. When the runtime is about to - * execute a script or function that will create the first stack frame - * with scriptable code, it calls this method to perform the real call. - * In this way execution of any script happens inside this function. - */ - @Override - protected Object doTopCall(final Callable callable, - final Context cx, final Scriptable scope, - final Scriptable thisObj, final Object[] args) { - AccessControlContext accCtxt = null; - Scriptable global = ScriptableObject.getTopLevelScope(scope); - Scriptable globalProto = global.getPrototype(); - if (globalProto instanceof com.script.rhino.RhinoTopLevel) { - accCtxt = ((com.script.rhino.RhinoTopLevel) globalProto).getAccessContext(); - } - - if (accCtxt != null) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return superDoTopCall(callable, cx, scope, thisObj, args); - } - }, accCtxt); - } else { - return superDoTopCall(callable, cx, scope, thisObj, args); - } - } - - private Object superDoTopCall(Callable callable, - Context cx, Scriptable scope, - Scriptable thisObj, Object[] args) { - return super.doTopCall(callable, cx, scope, thisObj, args); - } - }); - } - - private static final String RHINO_JS_VERSION = "rhino.js.version"; - - private static int getLanguageVersion() { - return Context.VERSION_1_8; - } - - private static final String RHINO_OPT_LEVEL = "rhino.opt.level"; - - private static int getOptimizationLevel() { - int optLevel = -1; - // disable optimizer under security manager, for now. - if (System.getSecurityManager() == null) { - optLevel = Integer.getInteger(RHINO_OPT_LEVEL, -1); - } - return optLevel; - } - - /** - * Creates a new instance of RhinoScriptEngine - */ - public RhinoScriptEngine() { - if (System.getSecurityManager() != null) { - try { - AccessController.checkPermission(new AllPermission()); - } catch (AccessControlException ace) { - accCtxt = AccessController.getContext(); - } - } - - Context cx = enterContext(); + @Throws(ScriptException::class) + override fun eval(reader: Reader, ctxt: ScriptContext): Any { + val cx = Context.enter() + val ret: Any try { - topLevel = new RhinoTopLevel(cx, this); - } finally { - cx.exit(); - } - - indexedProps = new HashMap(); - - //construct object used to implement getInterface - implementor = new InterfaceImplementor(this) { - protected boolean isImplemented(Object thiz, Class iface) { - Context cx = enterContext(); - try { - if (thiz != null && !(thiz instanceof Scriptable)) { - thiz = cx.toObject(thiz, topLevel); - } - Scriptable engineScope = getRuntimeScope(context); - Scriptable localScope = (thiz != null) ? (Scriptable) thiz : - engineScope; - for (Method method : iface.getMethods()) { - // ignore methods of java.lang.Object class - if (method.getDeclaringClass() == Object.class) { - continue; - } - Object obj = ScriptableObject.getProperty(localScope, method.getName()); - if (!(obj instanceof Function)) { - return false; - } - } - return true; - } finally { - cx.exit(); - } - } - - protected Object convertResult(Method method, Object res) - throws ScriptException { - Class desiredType = method.getReturnType(); - if (desiredType == Void.TYPE) { - return null; - } else { - return Context.jsToJava(res, desiredType); - } - } - }; - } - - public Object eval(Reader reader, ScriptContext ctxt) - throws ScriptException { - Object ret; - - Context cx = enterContext(); - try { - Scriptable scope = getRuntimeScope(ctxt); - String filename = (String) get(ScriptEngine.FILENAME); - filename = filename == null ? "" : filename; - - ret = cx.evaluateReader(scope, reader, filename, 1, null); - } catch (RhinoException re) { - if (DEBUG) re.printStackTrace(); - int line = (line = re.lineNumber()) == 0 ? -1 : line; - String msg; - if (re instanceof JavaScriptException) { - msg = String.valueOf(((JavaScriptException) re).getValue()); + val scope = getRuntimeScope(ctxt) + var filename = this["javax.script.filename"] as? String + filename = filename ?: "" + ret = cx.evaluateReader(scope, reader, filename, 1, null as Any?) + } catch (re: RhinoException) { + val line = if (re.lineNumber() == 0) -1 else re.lineNumber() + val msg: String = if (re is JavaScriptException) { + re.value.toString() } else { - msg = re.toString(); + re.toString() } - ScriptException se = new ScriptException(msg, re.sourceName(), line); - se.initCause(re); - throw se; - } catch (IOException ee) { - throw new ScriptException(ee); + val se = ScriptException(msg, re.sourceName(), line) + se.initCause(re) + throw se + } catch (var14: IOException) { + throw ScriptException(var14) } finally { - cx.exit(); + Context.exit() } - - return unwrapReturnValue(ret); + return unwrapReturnValue(ret)!! } - public Object eval(String script, ScriptContext ctxt) throws ScriptException { - if (script == null) { - throw new NullPointerException("null script"); + @Throws(ScriptException::class) + override fun eval(script: String?, ctxt: ScriptContext): Any { + return if (script == null) { + throw NullPointerException("null script") + } else { + this.eval(StringReader(script) as Reader, ctxt) } - return eval(new StringReader(script), ctxt); } - public Bindings createBindings() { - return new SimpleBindings(); + override fun createBindings(): Bindings { + return SimpleBindings() } - //Invocable methods - public Object invokeFunction(String name, Object... args) - throws ScriptException, NoSuchMethodException { - return invoke(null, name, args); + @Throws(ScriptException::class, NoSuchMethodException::class) + override fun invokeFunction(name: String, vararg args: Any): Any { + return this.invoke(null as Any?, name, *args) } - public Object invokeMethod(Object thiz, String name, Object... args) - throws ScriptException, NoSuchMethodException { - if (thiz == null) { - throw new IllegalArgumentException("script object can not be null"); + @Throws(ScriptException::class, NoSuchMethodException::class) + override fun invokeMethod(thiz: Any?, name: String, vararg args: Any): Any { + return if (thiz == null) { + throw IllegalArgumentException("脚本对象不能为空") + } else { + this.invoke(thiz, name, *args) } - return invoke(thiz, name, args); } - private Object invoke(Object thiz, String name, Object... args) - throws ScriptException, NoSuchMethodException { - Context cx = enterContext(); + @Suppress("UNCHECKED_CAST") + @Throws(ScriptException::class, NoSuchMethodException::class) + private operator fun invoke(thiz: Any?, name: String?, vararg args: Any?): Any { + var thiz1 = thiz + val cx = Context.enter() + val var11: Any try { if (name == null) { - throw new NullPointerException("method name is null"); + throw NullPointerException("方法名为空") } - - if (thiz != null && !(thiz instanceof Scriptable)) { - thiz = cx.toObject(thiz, topLevel); + if (thiz1 != null && thiz1 !is Scriptable) { + thiz1 = Context.toObject(thiz1, topLevel) } - - Scriptable engineScope = getRuntimeScope(context); - Scriptable localScope = (thiz != null) ? (Scriptable) thiz : - engineScope; - Object obj = ScriptableObject.getProperty(localScope, name); - if (!(obj instanceof Function)) { - throw new NoSuchMethodException("no such method: " + name); - } - - Function func = (Function) obj; - Scriptable scope = func.getParentScope(); + val engineScope = getRuntimeScope(context) + val localScope = if (thiz1 != null) thiz1 as Scriptable else engineScope + val obj = ScriptableObject.getProperty(localScope, name) as? Function + ?: throw NoSuchMethodException("no such method: $name") + val func = obj + var scope = func.parentScope if (scope == null) { - scope = engineScope; + scope = engineScope } - Object result = func.call(cx, scope, localScope, - wrapArguments(args)); - return unwrapReturnValue(result); - } catch (RhinoException re) { - if (DEBUG) re.printStackTrace(); - int line = (line = re.lineNumber()) == 0 ? -1 : line; - ScriptException se = new ScriptException(re.toString(), re.sourceName(), line); - se.initCause(re); - throw se; + val result = func.call(cx, scope, localScope, wrapArguments(args as? Array)) + var11 = unwrapReturnValue(result)!! + } catch (re: RhinoException) { + val line = if (re.lineNumber() == 0) -1 else re.lineNumber() + val se = ScriptException(re.toString(), re.sourceName(), line) + se.initCause(re) + throw se } finally { - cx.exit(); + Context.exit() + } + return var11 + } + + override fun getInterface(clasz: Class): T? { + return try { + implementor.getInterface(null as Any?, clasz) + } catch (var3: ScriptException) { + null } } - public T getInterface(Class clasz) { + override fun getInterface(thiz: Any?, clasz: Class): T? { + return if (thiz == null) { + throw IllegalArgumentException("脚本对象不能为空") + } else { + try { + implementor.getInterface(thiz, clasz) + } catch (var4: ScriptException) { + null + } + } + } + + fun getRuntimeScope(ctxt: ScriptContext?): Scriptable { + return if (ctxt == null) { + throw NullPointerException("脚本context为空") + } else { + val newScope: Scriptable = ExternalScriptable(ctxt, indexedProps) + newScope.prototype = topLevel + newScope.put("context", newScope, ctxt) + val cx = Context.enter() + try { + @Language("js") + val js = """ + function print(str, newline) { + if (typeof(str) == 'undefined') { + str = 'undefined'; + } else if (str == null) { + str = 'null'; + } + var out = context.getWriter(); + if (!(out instanceof java.io.PrintWriter)) + out = new java.io.PrintWriter(out); + out.print(String(str)); + if (newline) out.print('\\n'); + out.flush(); + } + function println(str) { + print(str, true); + } + """.trimIndent() + cx.evaluateString( + newScope, + js, + "print", + 1, + null as Any? + ) + } finally { + Context.exit() + } + newScope + } + } + + @Throws(ScriptException::class) + override fun compile(script: String): CompiledScript { + return this.compile(StringReader(script) as Reader) + } + + @Throws(ScriptException::class) + override fun compile(script: Reader): CompiledScript { + val cx = Context.enter() + val ret: RhinoCompiledScript try { - return implementor.getInterface(null, clasz); - } catch (ScriptException e) { - return null; - } - } - - public T getInterface(Object thiz, Class clasz) { - if (thiz == null) { - throw new IllegalArgumentException("script object can not be null"); - } - - try { - return implementor.getInterface(thiz, clasz); - } catch (ScriptException e) { - return null; - } - } - - private static final String printSource = - "function print(str, newline) { \n" + - " if (typeof(str) == 'undefined') { \n" + - " str = 'undefined'; \n" + - " } else if (str == null) { \n" + - " str = 'null'; \n" + - " } \n" + - " var out = context.getWriter(); \n" + - " if (!(out instanceof java.io.PrintWriter))\n" + - " out = new java.io.PrintWriter(out); \n" + - " out.print(String(str)); \n" + - " if (newline) out.print('\\n'); \n" + - " out.flush(); \n" + - "}\n" + - "function println(str) { \n" + - " print(str, true); \n" + - "}"; - - Scriptable getRuntimeScope(ScriptContext ctxt) { - if (ctxt == null) { - throw new NullPointerException("null script context"); - } - - // we create a scope for the given ScriptContext - Scriptable newScope = new com.script.rhino.ExternalScriptable(ctxt, indexedProps); - - // Set the prototype of newScope to be 'topLevel' so that - // JavaScript standard objects are visible from the scope. - newScope.setPrototype(topLevel); - - // define "context" variable in the new scope - newScope.put("context", newScope, ctxt); - - // define "print", "println" functions in the new scope - Context cx = enterContext(); - try { - cx.evaluateString(newScope, printSource, "print", 1, null); - } finally { - cx.exit(); - } - return newScope; - } - - - //Compilable methods - public CompiledScript compile(String script) throws ScriptException { - return compile(new StringReader(script)); - } - - public CompiledScript compile(java.io.Reader script) throws ScriptException { - CompiledScript ret = null; - Context cx = enterContext(); - - try { - String fileName = (String) get(ScriptEngine.FILENAME); + var fileName = this["javax.script.filename"] as? String if (fileName == null) { - fileName = ""; + fileName = "" + } + val scr = cx.compileReader(script, fileName, 1, null as Any?) + ret = RhinoCompiledScript(this, scr) + } catch (var9: Exception) { + throw ScriptException(var9) + } finally { + Context.exit() + } + return ret + } + + fun wrapArguments(args: Array?): Array { + return if (args == null) { + Context.emptyArgs + } else { + val res = arrayOfNulls(args.size) + for (i in res.indices) { + res[i] = Context.javaToJS(args[i], topLevel) + } + res + } + } + + fun unwrapReturnValue(result: Any?): Any? { + var result1 = result + if (result1 is Wrapper) { + result1 = result1.unwrap() + } + return if (result1 is Undefined) null else result1 + } + + init { + if (System.getSecurityManager() != null) { + try { + AccessController.checkPermission(AllPermission()) + } catch (var6: AccessControlException) { + accessContext = AccessController.getContext() + } + } + val cx = Context.enter() + try { + topLevel = RhinoTopLevel(cx, this) + } finally { + Context.exit() + } + indexedProps = HashMap() + implementor = object : InterfaceImplementor(this) { + override fun isImplemented(thiz: Any?, iface: Class<*>): Boolean { + var thiz1 = thiz + return try { + if (thiz1 != null && thiz1 !is Scriptable) { + thiz1 = Context.toObject( + thiz1, + topLevel + ) + } + val engineScope = + getRuntimeScope(context) + val localScope = + if (thiz1 != null) thiz1 as Scriptable else engineScope + val var5 = iface.methods + val var6 = var5.size + for (var7 in 0 until var6) { + val method = var5[var7] + if (method.declaringClass != Any::class.java) { + val obj = + ScriptableObject.getProperty(localScope, method.name) as? Function + obj ?: return false + } + } + true + } finally { + Context.exit() + } } - Scriptable scope = getRuntimeScope(context); - @SuppressWarnings("deprecation") - Script scr = cx.compileReader(scope, script, fileName, 1, null); - ret = new RhinoCompiledScript(this, scr); - } catch (Exception e) { - if (DEBUG) e.printStackTrace(); - throw new ScriptException(e); - } finally { - cx.exit(); + override fun convertResult(method: Method?, res: Any): Any { + val desiredType = method!!.returnType + return (if (desiredType == Void.TYPE) null else Context.jsToJava( + res, + desiredType + ))!! + } } - return ret; } + companion object { + private const val DEBUG = false - //package-private helpers + @Language("js") + private val printSource = """ + function print(str, newline) { + if (typeof str == "undefined") { + str = "undefined"; + } else if (str == null) { + str = "null"; + } + var out = context.getWriter(); + if (!(out instanceof java.io.PrintWriter)) + out = new java.io.PrintWriter(out); + out.print(String(str)); + if (newline) out.print("\\n"); + out.flush(); + } + function println(str) { + print(str, true); + } + """.trimIndent() - static Context enterContext() { - // call this always so that initializer of this class runs - // and initializes custom wrap factory and class shutter. - return Context.enter(); - } + init { + ContextFactory.initGlobal(object : ContextFactory() { + override fun makeContext(): Context { + val cx = super.makeContext() + cx.languageVersion = 200 + cx.optimizationLevel = -1 + cx.setClassShutter(instance) + cx.wrapFactory = RhinoWrapFactory.instance + return cx + } - AccessControlContext getAccessContext() { - return accCtxt; - } + override fun doTopCall( + callable: Callable, + cx: Context, + scope: Scriptable, + thisObj: Scriptable, + args: Array + ): Any { + var accCtxt: AccessControlContext? = null + val global = ScriptableObject.getTopLevelScope(scope) + val globalProto = global.prototype + if (globalProto is RhinoTopLevel) { + accCtxt = globalProto.accessContext + } + return if (accCtxt != null) AccessController.doPrivileged( + PrivilegedAction { + superDoTopCall( + callable, + cx, + scope, + thisObj, + args + ) + } as PrivilegedAction, accCtxt) else superDoTopCall( + callable, + cx, + scope, + thisObj, + args + ) + } - Object[] wrapArguments(Object[] args) { - if (args == null) { - return Context.emptyArgs; + private fun superDoTopCall( + callable: Callable, + cx: Context, + scope: Scriptable, + thisObj: Scriptable, + args: Array + ): Any { + return super.doTopCall(callable, cx, scope, thisObj, args) + } + }) } - Object[] res = new Object[args.length]; - for (int i = 0; i < res.length; i++) { - res[i] = Context.javaToJS(args[i], topLevel); - } - return res; } - - Object unwrapReturnValue(Object result) { - if (result instanceof Wrapper) { - result = ((Wrapper) result).unwrap(); - } - - return result instanceof Undefined ? null : result; - } - - /* - public static void main(String[] args) throws Exception { - if (args.length == 0) { - System.out.println("No file specified"); - return; - } - - InputStreamReader r = new InputStreamReader(new FileInputStream(args[0])); - ScriptEngine engine = new RhinoScriptEngine(); - - engine.put("x", "y"); - engine.put(ScriptEngine.FILENAME, args[0]); - engine.eval(r); - System.out.println(engine.get("x")); - } - */ -} +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/RhinoTopLevel.kt b/rhino/src/main/java/com/script/rhino/RhinoTopLevel.kt index c09eb71dd..378dd326e 100644 --- a/rhino/src/main/java/com/script/rhino/RhinoTopLevel.kt +++ b/rhino/src/main/java/com/script/rhino/RhinoTopLevel.kt @@ -22,24 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import com.script.Bindings; -import com.script.ScriptContext; -import com.script.SimpleScriptContext; - -import org.mozilla.javascript.Context; -import org.mozilla.javascript.Function; -import org.mozilla.javascript.ImporterTopLevel; -import org.mozilla.javascript.LazilyLoadedCtor; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.ScriptableObject; -import org.mozilla.javascript.Synchronizer; -import org.mozilla.javascript.Wrapper; - -import java.security.AccessControlContext; - +import com.script.Bindings +import com.script.ScriptContext +import com.script.SimpleScriptContext +import org.mozilla.javascript.* +import org.mozilla.javascript.Function +import java.security.AccessControlContext /** * This class serves as top level scope for Rhino. This class adds @@ -49,129 +39,69 @@ import java.security.AccessControlContext; * @author A. Sundararajan * @since 1.6 */ -public final class RhinoTopLevel extends ImporterTopLevel { - RhinoTopLevel(Context cx, RhinoScriptEngine engine) { - // second boolean parameter to super constructor tells whether - // to seal standard JavaScript objects or not. If security manager - // is present, we seal the standard objects. - super(cx, System.getSecurityManager() != null); - this.engine = engine; +@Suppress("UNUSED_PARAMETER") +class RhinoTopLevel internal constructor(cx: Context?, val scriptEngine: RhinoScriptEngine) : + ImporterTopLevel(cx, System.getSecurityManager() != null) { - // initialize JSAdapter lazily. Reduces footprint & startup time. - new LazilyLoadedCtor(this, "JSAdapter", - "com.sun.script.javascript.JSAdapter", - false); - - /* - * initialize JavaAdapter. We can't lazy initialize this because - * lazy initializer attempts to define a new property. But, JavaAdapter - * is an exisiting property that we overwrite. - */ - com.script.rhino.JavaAdapter.init(cx, this, false); - - // add top level functions - String names[] = { "bindings", "scope", "sync" }; - defineFunctionProperties(names, RhinoTopLevel.class, - ScriptableObject.DONTENUM); + init { + LazilyLoadedCtor(this, "JSAdapter", "com.sun.script.javascript.JSAdapter", false) + JavaAdapter.init(cx, this, false) + val names = arrayOf("bindings", "scope", "sync") + defineFunctionProperties(names, RhinoTopLevel::class.java, 2) } - /** - * The bindings function takes a JavaScript scope object - * of type ExternalScriptable and returns the underlying Bindings - * instance. - * - * var page = scope(pageBindings); - * with (page) { - * // code that uses page scope - * } - * var b = bindings(page); - * // operate on bindings here. - */ - public static Object bindings(Context cx, Scriptable thisObj, Object[] args, - Function funObj) { - if (args.length == 1) { - Object arg = args[0]; - if (arg instanceof Wrapper) { - arg = ((Wrapper)arg).unwrap(); + val accessContext: AccessControlContext? + get() = scriptEngine.accessContext + + companion object { + + @JvmStatic + fun bindings( + cx: Context?, + thisObj: Scriptable?, + args: Array, + funObj: Function? + ): Any { + if (args.size == 1) { + var arg = args[0] + if (arg is Wrapper) { + arg = arg.unwrap() + } + if (arg is ExternalScriptable) { + val ctx = arg.context + val bind = ctx.getBindings(100) + return Context.javaToJS(bind, getTopLevelScope(thisObj)) + } } - if (arg instanceof com.script.rhino.ExternalScriptable) { - ScriptContext ctx = ((com.script.rhino.ExternalScriptable)arg).getContext(); - Bindings bind = ctx.getBindings(ScriptContext.ENGINE_SCOPE); - return Context.javaToJS(bind, - ScriptableObject.getTopLevelScope(thisObj)); + return Context.getUndefinedValue() + } + + @JvmStatic + fun scope(cx: Context?, thisObj: Scriptable?, args: Array, funObj: Function?): Any { + if (args.size == 1) { + var arg = args[0] + if (arg is Wrapper) { + arg = arg.unwrap() + } + if (arg is Bindings) { + val ctx: ScriptContext = SimpleScriptContext() + ctx.setBindings(arg as Bindings?, 100) + val res: Scriptable = ExternalScriptable(ctx) + res.prototype = getObjectPrototype(thisObj) + res.parentScope = getTopLevelScope(thisObj) + return res + } + } + return Context.getUndefinedValue() + } + + @JvmStatic + fun sync(cx: Context?, thisObj: Scriptable?, args: Array, funObj: Function?): Any { + return if (args.size == 1 && args[0] is Function) { + Synchronizer(args[0] as Function?) + } else { + throw Context.reportRuntimeError("wrong argument(s) for sync") } } - return cx.getUndefinedValue(); } - - /** - * The scope function creates a new JavaScript scope object - * with given Bindings object as backing store. This can be used - * to create a script scope based on arbitrary Bindings instance. - * For example, in webapp scenario, a 'page' level Bindings instance - * may be wrapped as a scope and code can be run in JavaScripe 'with' - * statement: - * - * var page = scope(pageBindings); - * with (page) { - * // code that uses page scope - * } - */ - public static Object scope(Context cx, Scriptable thisObj, Object[] args, - Function funObj) { - if (args.length == 1) { - Object arg = args[0]; - if (arg instanceof Wrapper) { - arg = ((Wrapper)arg).unwrap(); - } - if (arg instanceof Bindings) { - ScriptContext ctx = new SimpleScriptContext(); - ctx.setBindings((Bindings)arg, ScriptContext.ENGINE_SCOPE); - Scriptable res = new com.script.rhino.ExternalScriptable(ctx); - res.setPrototype(ScriptableObject.getObjectPrototype(thisObj)); - res.setParentScope(ScriptableObject.getTopLevelScope(thisObj)); - return res; - } - } - return cx.getUndefinedValue(); - } - - /** - * The sync function creates a synchronized function (in the sense - * of a Java synchronized method) from an existing function. The - * new function synchronizes on the this object of - * its invocation. - * {@code - * js> var o = { f : sync(function(x) { - * print("entry"); - * Packages.java.lang.Thread.sleep(x*1000); - * print("exit"); - * })}; - * js> thread(function() {o.f(5);}); - * entry - * js> thread(function() {o.f(5);}); - * js> - * exit - * entry - * exit - * } - */ - public static Object sync(Context cx, Scriptable thisObj, Object[] args, - Function funObj) { - if (args.length == 1 && args[0] instanceof Function) { - return new Synchronizer((Function)args[0]); - } else { - throw Context.reportRuntimeError("wrong argument(s) for sync"); - } - } - - RhinoScriptEngine getScriptEngine() { - return engine; - } - - AccessControlContext getAccessContext() { - return engine.getAccessContext(); - } - - private RhinoScriptEngine engine; -} +} \ No newline at end of file diff --git a/rhino/src/main/java/com/script/rhino/RhinoWrapFactory.kt b/rhino/src/main/java/com/script/rhino/RhinoWrapFactory.kt index 5e0e7b358..17d3d6602 100644 --- a/rhino/src/main/java/com/script/rhino/RhinoWrapFactory.kt +++ b/rhino/src/main/java/com/script/rhino/RhinoWrapFactory.kt @@ -22,18 +22,14 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ +package com.script.rhino -package com.script.rhino; - -import org.mozilla.javascript.ClassShutter; -import org.mozilla.javascript.Context; -import org.mozilla.javascript.NativeJavaObject; -import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.WrapFactory; - -import java.lang.reflect.Member; -import java.lang.reflect.Modifier; - +import org.mozilla.javascript.Context +import org.mozilla.javascript.NativeJavaObject +import org.mozilla.javascript.Scriptable +import org.mozilla.javascript.WrapFactory +import java.lang.reflect.Member +import java.lang.reflect.Modifier /** * This wrap factory is used for security reasons. JSR 223 script @@ -48,118 +44,88 @@ import java.lang.reflect.Modifier; * @author A. Sundararajan * @since 1.6 */ -final class RhinoWrapFactory extends WrapFactory { - private RhinoWrapFactory() {} - private static RhinoWrapFactory theInstance; +internal class RhinoWrapFactory private constructor() : WrapFactory() { - static synchronized WrapFactory getInstance() { - if (theInstance == null) { - theInstance = new RhinoWrapFactory(); - } - return theInstance; - } - - // We use instance of this class to wrap security sensitive - // Java object. Please refer below. - private static class RhinoJavaObject extends NativeJavaObject { - RhinoJavaObject(Scriptable scope, Object obj, Class type) { - // we pass 'null' to object. NativeJavaObject uses - // passed 'type' to reflect fields and methods when - // object is null. - super(scope, null, type); - - // Now, we set actual object. 'javaObject' is protected - // field of NativeJavaObject. - javaObject = obj; - } - - @Override - public Object get(String name, Scriptable start) { - if (name.equals("getClass") || name.equals("exec")) { - return NOT_FOUND; - } - return super.get(name, start); - } - } - - public Scriptable wrapAsJavaObject(Context cx, Scriptable scope, - Object javaObject, Class staticType) { - if (scope != null) { - scope.delete("Packages"); - } - SecurityManager sm = System.getSecurityManager(); - ClassShutter classShutter = RhinoClassShutter.getInstance(); - if (javaObject instanceof ClassLoader) { - // Check with Security Manager whether we can expose a - // ClassLoader... - if (sm != null) { - sm.checkPermission(new RuntimePermission("getClassLoader")); - } - // if we fall through here, check permission succeeded. - return super.wrapAsJavaObject(cx, scope, javaObject, staticType); + override fun wrapAsJavaObject( + cx: Context, + scope: Scriptable?, + javaObject: Any, + staticType: Class<*>? + ): Scriptable? { + scope?.delete("Packages") + val sm = System.getSecurityManager() + val classShutter = RhinoClassShutter.instance + return if (javaObject is ClassLoader) { + sm?.checkPermission(RuntimePermission("getClassLoader")) + super.wrapAsJavaObject(cx, scope, javaObject, staticType) } else { - String name = null; - if (javaObject instanceof Class) { - name = ((Class)javaObject).getName(); - } else if (javaObject instanceof Member) { - Member member = (Member) javaObject; - // Check member access. Don't allow reflective access to - // non-public members. Note that we can't call checkMemberAccess - // because that expects exact stack depth! - if (sm != null && !Modifier.isPublic(member.getModifiers())) { - return null; + var name: String? = null + if (javaObject is Class<*>) { + name = javaObject.name + } else if (javaObject is Member) { + if (sm != null && !Modifier.isPublic(javaObject.modifiers)) { + return null } - name = member.getDeclaringClass().getName(); + name = javaObject.declaringClass.name } - // Now, make sure that no ClassShutter prevented Class or Member - // of it is accessed reflectively. Note that ClassShutter may - // prevent access to a class, even though SecurityManager permit. if (name != null) { - if (!classShutter.visibleToScripts(name)) { - return null; - } else { - return super.wrapAsJavaObject(cx, scope, javaObject, staticType); - } - } - } - - // we have got some non-reflective object. - Class dynamicType = javaObject.getClass(); - String name = dynamicType.getName(); - if (!classShutter.visibleToScripts(name)) { - // Object of some sensitive class (such as sun.net.www.* - // objects returned from public method of java.net.URL class. - // We expose this object as though it is an object of some - // super class that is safe for access. - - Class type = null; - - // Whenever a Java Object is wrapped, we are passed with a - // staticType which is the type found from environment. For - // example, method return type known from signature. The dynamic - // type would be the actual Class of the actual returned object. - // If the staticType is an interface, we just use that type. - if (staticType != null && staticType.isInterface()) { - type = staticType; + if (!classShutter.visibleToScripts(name)) null else super.wrapAsJavaObject( + cx, + scope, + javaObject, + staticType + ) } else { - // dynamicType is always a class type and never an interface. - // find an accessible super class of the dynamic type. - while (dynamicType != null) { - dynamicType = dynamicType.getSuperclass(); - name = dynamicType.getName(); - if (classShutter.visibleToScripts(name)) { - type = dynamicType; break; + var dynamicType: Class<*>? = javaObject.javaClass + name = dynamicType!!.name + if (classShutter.visibleToScripts(name)) { + super.wrapAsJavaObject(cx, scope, javaObject, staticType) + } else { + var type: Class<*>? = null + if (staticType != null && staticType.isInterface) { + type = staticType + } else { + while (dynamicType != null) { + dynamicType = dynamicType.superclass + name = dynamicType.name + if (classShutter.visibleToScripts(name)) { + type = dynamicType + break + } + } + assert(type != null) { "java.lang.Object 不可访问" } } + RhinoJavaObject(scope, javaObject, type) } - // atleast java.lang.Object has to be accessible. So, when - // we reach here, type variable should not be null. - assert type != null: - "even java.lang.Object is not accessible?"; } - // create custom wrapper with the 'safe' type. - return new RhinoJavaObject(scope, javaObject, type); - } else { - return super.wrapAsJavaObject(cx, scope, javaObject, staticType); } } -} + + private class RhinoJavaObject( + scope: Scriptable?, + obj: Any?, + type: Class<*>? + ) : NativeJavaObject(scope, null as Any?, type) { + init { + javaObject = obj + } + + override fun get(name: String, start: Scriptable): Any { + return if (name != "getClass" && name != "exec") super.get(name, start) else NOT_FOUND + } + } + + companion object { + private var theInstance: RhinoWrapFactory? = null + + @JvmStatic + @get:Synchronized + val instance: WrapFactory? + get() { + if (theInstance == null) { + theInstance = RhinoWrapFactory() + } + return theInstance + } + } +} \ No newline at end of file