mirror of
https://github.com/gedoor/legado.git
synced 2024-08-30 09:23:26 +08:00
优化
This commit is contained in:
parent
f53eca326b
commit
add9fddfbd
@ -5,6 +5,7 @@ import android.content.pm.PackageManager
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import com.script.rhino.RhinoScriptEngine
|
import com.script.rhino.RhinoScriptEngine
|
||||||
|
|
||||||
import io.legado.app.BuildConfig
|
import io.legado.app.BuildConfig
|
||||||
import io.legado.app.utils.channel
|
import io.legado.app.utils.channel
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.library'
|
id 'com.android.library'
|
||||||
|
id 'org.jetbrains.kotlin.android'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.library'
|
id 'com.android.library'
|
||||||
|
id 'org.jetbrains.kotlin.android'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -22,8 +23,8 @@ android {
|
|||||||
|
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
}
|
}
|
||||||
lint {
|
lint {
|
||||||
checkDependencies true
|
checkDependencies true
|
||||||
|
@ -22,24 +22,11 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import com.script.ScriptContext
|
||||||
|
import org.mozilla.javascript.*
|
||||||
import com.script.Bindings;
|
import org.mozilla.javascript.Function
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExternalScriptable is an implementation of Scriptable
|
* ExternalScriptable is an implementation of Scriptable
|
||||||
@ -49,430 +36,252 @@ import java.util.Map;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
|
internal class ExternalScriptable @JvmOverloads constructor(
|
||||||
|
context: ScriptContext?,
|
||||||
|
indexedProps: MutableMap<Any, Any> = HashMap()
|
||||||
|
) : Scriptable {
|
||||||
|
val context: ScriptContext
|
||||||
|
private val indexedProps: MutableMap<Any, Any>
|
||||||
|
private var prototype: Scriptable? = null
|
||||||
|
private var parent: Scriptable? = null
|
||||||
|
|
||||||
final class ExternalScriptable implements Scriptable {
|
init {
|
||||||
/* 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<Object, Object> indexedProps;
|
|
||||||
|
|
||||||
// my prototype
|
|
||||||
private Scriptable prototype;
|
|
||||||
// my parent scope, if any
|
|
||||||
private Scriptable parent;
|
|
||||||
|
|
||||||
ExternalScriptable(ScriptContext context) {
|
|
||||||
this(context, new HashMap<Object, Object>());
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternalScriptable(ScriptContext context, Map<Object, Object> indexedProps) {
|
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
throw new NullPointerException("context is null");
|
throw 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;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (context) {
|
this.context = context
|
||||||
int scope = context.getAttributesScope(name);
|
this.indexedProps = indexedProps
|
||||||
if (scope != -1) {
|
}
|
||||||
Object value = context.getAttribute(name, scope);
|
}
|
||||||
return Context.javaToJS(value, this);
|
|
||||||
|
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 {
|
} else {
|
||||||
return NOT_FOUND;
|
Scriptable.NOT_FOUND
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Synchronized
|
||||||
* Returns the value of the indexed property or NOT_FOUND.
|
override fun get(index: Int, start: Scriptable): Any {
|
||||||
*
|
return indexedProps.getOrElse(index) { Scriptable.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
|
@Synchronized
|
||||||
*/
|
override fun has(name: String, start: Scriptable): Boolean {
|
||||||
public synchronized Object get(int index, Scriptable start) {
|
return if (this.isEmpty(name)) {
|
||||||
if (indexedProps.containsKey(index)) {
|
indexedProps.containsKey(name)
|
||||||
return indexedProps.get(index);
|
|
||||||
} else {
|
} else {
|
||||||
return NOT_FOUND;
|
synchronized(context) { return context.getAttributesScope(name) != -1 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Synchronized
|
||||||
* Returns true if the named property is defined.
|
override fun has(index: Int, start: Scriptable): Boolean {
|
||||||
*
|
return indexedProps.containsKey(index)
|
||||||
* @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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun put(name: String, start: Scriptable, value: Any) {
|
||||||
* Returns true if the property index is defined.
|
if (start === this) {
|
||||||
*
|
synchronized(this) {
|
||||||
* @param index the numeric index for the property
|
if (this.isEmpty(name)) {
|
||||||
* @param start the object in which the lookup began
|
indexedProps.put(name, value)
|
||||||
* @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);
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (context) {
|
synchronized(context) {
|
||||||
int scope = context.getAttributesScope(name);
|
var scope = context.getAttributesScope(name)
|
||||||
if (scope == -1) {
|
if (scope == -1) {
|
||||||
scope = ScriptContext.ENGINE_SCOPE;
|
scope = 100
|
||||||
}
|
}
|
||||||
context.setAttribute(name, jsToJava(value), scope);
|
context.setAttribute(name, jsToJava(value), scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
start.put(name, start, value);
|
start.put(name, start, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun put(index: Int, start: Scriptable, value: Any) {
|
||||||
* Sets the value of the indexed property, creating it if need be.
|
if (start === this) {
|
||||||
*
|
synchronized(this) { indexedProps.put(index, value) }
|
||||||
* @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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
start.put(index, start, value);
|
start.put(index, start, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Synchronized
|
||||||
* Removes a named property from the object.
|
override fun delete(name: String) {
|
||||||
*
|
if (this.isEmpty(name)) {
|
||||||
* If the property is not found, no action is taken.
|
indexedProps.remove(name)
|
||||||
*
|
|
||||||
* @param name the name of the property
|
|
||||||
*/
|
|
||||||
public synchronized void delete(String name) {
|
|
||||||
if (isEmpty(name)) {
|
|
||||||
indexedProps.remove(name);
|
|
||||||
} else {
|
} else {
|
||||||
synchronized (context) {
|
synchronized(context) {
|
||||||
int scope = context.getAttributesScope(name);
|
val scope = context.getAttributesScope(name)
|
||||||
if (scope != -1) {
|
if (scope != -1) {
|
||||||
context.removeAttribute(name, scope);
|
context.removeAttribute(name, scope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun delete(index: Int) {
|
||||||
* Removes the indexed property from the object.
|
indexedProps.remove(index)
|
||||||
*
|
|
||||||
* 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 getPrototype(): Scriptable? {
|
||||||
* Get the prototype of the object.
|
return prototype
|
||||||
* @return the prototype
|
|
||||||
*/
|
|
||||||
public Scriptable getPrototype() {
|
|
||||||
return prototype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun setPrototype(prototype: Scriptable?) {
|
||||||
* Set the prototype of the object.
|
this.prototype = prototype
|
||||||
* @param prototype the prototype to set
|
|
||||||
*/
|
|
||||||
public void setPrototype(Scriptable prototype) {
|
|
||||||
this.prototype = prototype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun getParentScope(): Scriptable? {
|
||||||
* Get the parent scope of the object.
|
return parent
|
||||||
* @return the parent scope
|
|
||||||
*/
|
|
||||||
public Scriptable getParentScope() {
|
|
||||||
return parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun setParentScope(parent: Scriptable?) {
|
||||||
* Set the parent scope of the object.
|
this.parent = parent
|
||||||
* @param parent the parent scope to set
|
|
||||||
*/
|
|
||||||
public void setParentScope(Scriptable parent) {
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Synchronized
|
||||||
* Get an array of property ids.
|
override fun getIds(): Array<Any> {
|
||||||
*
|
val keys = allKeys
|
||||||
* Not all property ids need be returned. Those properties
|
val size = keys.size + indexedProps.size
|
||||||
* whose ids are not returned are considered non-enumerable.
|
val res = arrayOfNulls<Any>(size)
|
||||||
*
|
System.arraycopy(keys, 0, res, 0, keys.size)
|
||||||
* @return an array of Objects. Each entry in the array is either
|
var i = keys.size
|
||||||
* a java.lang.String or a java.lang.Number
|
var index: Any
|
||||||
*/
|
val var5: Iterator<*> = indexedProps.keys.iterator()
|
||||||
public synchronized Object[] getIds() {
|
while (var5.hasNext()) {
|
||||||
String[] keys = getAllKeys();
|
index = var5.next()!!
|
||||||
int size = keys.length + indexedProps.size();
|
res[i++] = index
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return res;
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return res as Array<Any>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun getDefaultValue(typeHint: Class<*>?): Any {
|
||||||
* Get the default value of the object with a given hint.
|
for (i in 0..1) {
|
||||||
* The hints are String.class for type String, Number.class for type
|
val tryToString: Boolean =
|
||||||
* Number, Scriptable.class for type Object, and Boolean.class for
|
if (typeHint == ScriptRuntime.StringClass) {
|
||||||
* type Boolean. <p>
|
i == 0
|
||||||
*
|
|
||||||
* A <code>hint</code> 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";
|
|
||||||
} else {
|
} else {
|
||||||
throw Context.reportRuntimeError(
|
i == 1
|
||||||
"Invalid JavaScript value of type " +
|
|
||||||
typeHint);
|
|
||||||
}
|
}
|
||||||
args[0] = hint;
|
var methodName: String
|
||||||
|
var args: Array<Any?>
|
||||||
|
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);
|
var v = ScriptableObject.getProperty(this, methodName)
|
||||||
if (!(v instanceof Function))
|
if (v is Function) {
|
||||||
continue;
|
val `fun` = v
|
||||||
Function fun = (Function) v;
|
val cx = Context.enter()
|
||||||
Context cx = RhinoScriptEngine.enterContext();
|
v = try {
|
||||||
try {
|
`fun`.call(cx, `fun`.parentScope, this, args)
|
||||||
v = fun.call(cx, fun.getParentScope(), this, args);
|
} finally {
|
||||||
} finally {
|
Context.exit()
|
||||||
cx.exit();
|
|
||||||
}
|
|
||||||
if (v != null) {
|
|
||||||
if (!(v instanceof Scriptable)) {
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
if (typeHint == ScriptRuntime.ScriptableClass
|
if (v != null) {
|
||||||
|| typeHint == ScriptRuntime.FunctionClass)
|
if (v !is Scriptable) {
|
||||||
{
|
return v
|
||||||
return v;
|
}
|
||||||
}
|
if (typeHint == ScriptRuntime.ScriptableClass || typeHint == ScriptRuntime.FunctionClass) {
|
||||||
if (tryToString && v instanceof Wrapper) {
|
return v
|
||||||
// Let a wrapped java.lang.String pass for a primitive
|
}
|
||||||
// string.
|
if (tryToString && v is Wrapper) {
|
||||||
Object u = ((Wrapper)v).unwrap();
|
val u = (v as Wrapper).unwrap()
|
||||||
if (u instanceof String)
|
if (u is String) {
|
||||||
return u;
|
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<String> list = new ArrayList<String>();
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String[] res = new String[list.size()];
|
val arg = if (typeHint == null) "undefined" else typeHint.name
|
||||||
list.toArray(res);
|
throw Context.reportRuntimeError("找不到对象的默认值 $arg")
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun hasInstance(instance: Scriptable): Boolean {
|
||||||
* We convert script values to the nearest Java value.
|
var proto = instance.prototype
|
||||||
* We unwrap wrapped Java objects so that access from
|
while (proto != null) {
|
||||||
* Bindings.get() would return "workable" value for Java.
|
if (proto == this) {
|
||||||
* But, at the same time, we need to make few special cases
|
return true
|
||||||
* 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;
|
|
||||||
}
|
}
|
||||||
|
proto = proto.prototype
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
/* script may use Java primitive wrapper type objects
|
private val allKeys: Array<String>
|
||||||
* (such as java.lang.Integer, java.lang.Boolean etc)
|
get() {
|
||||||
* explicitly. If we unwrap, then these script objects
|
val list = ArrayList<String>()
|
||||||
* will become script primitive types. For example,
|
synchronized(context) {
|
||||||
*
|
val var3: Iterator<*> = context.scopes.iterator()
|
||||||
* var x = new java.lang.Double(3.0); print(typeof x);
|
while (var3.hasNext()) {
|
||||||
*
|
val scope = var3.next() as Int
|
||||||
* will print 'number'. We don't want that to happen.
|
val bindings = context.getBindings(scope)
|
||||||
*/
|
if (bindings != null) {
|
||||||
Object obj = njb.unwrap();
|
list.ensureCapacity(bindings.size)
|
||||||
if (obj instanceof Number || obj instanceof String ||
|
val var6: Iterator<*> = bindings.keys.iterator()
|
||||||
obj instanceof Boolean || obj instanceof Character) {
|
while (var6.hasNext()) {
|
||||||
// special type wrapped -- we just leave it as is.
|
val key = var6.next() as String
|
||||||
return njb;
|
list.add(key)
|
||||||
} else {
|
}
|
||||||
// return unwrapped object for any other object.
|
}
|
||||||
return obj;
|
}
|
||||||
}
|
}
|
||||||
} else { // not-a-Java-wrapper
|
return list.toTypedArray()
|
||||||
return jsObj;
|
}
|
||||||
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,97 +22,75 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* 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
|
* java.lang.reflect.Proxy based interface implementor. This is meant
|
||||||
* to be used to implement Invocable.getInterface.
|
* to be used to implement Invocable.getInterface.
|
||||||
*
|
*
|
||||||
* @author Mike Grogan
|
* @author Mike Grogan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public class InterfaceImplementor {
|
open class InterfaceImplementor(private val engine: Invocable) {
|
||||||
|
@Throws(ScriptException::class)
|
||||||
private Invocable engine;
|
fun <T> getInterface(thiz: Any?, iface: Class<T>?): T? {
|
||||||
|
return if (iface != null && iface.isInterface) {
|
||||||
/** Creates a new instance of Invocable */
|
if (!isImplemented(thiz, iface)) {
|
||||||
public InterfaceImplementor(Invocable engine) {
|
null
|
||||||
this.engine = engine;
|
} else {
|
||||||
}
|
val accCtxt = AccessController.getContext()
|
||||||
|
iface.cast(
|
||||||
private final class InterfaceImplementorInvocationHandler
|
Proxy.newProxyInstance(
|
||||||
implements InvocationHandler {
|
iface.classLoader,
|
||||||
private Object thiz;
|
arrayOf<Class<*>>(iface),
|
||||||
private AccessControlContext accCtxt;
|
InterfaceImplementorInvocationHandler(thiz, accCtxt)
|
||||||
|
)
|
||||||
public InterfaceImplementorInvocationHandler(Object thiz,
|
)
|
||||||
AccessControlContext accCtxt) {
|
}
|
||||||
this.thiz = thiz;
|
} else {
|
||||||
this.accCtxt = accCtxt;
|
throw IllegalArgumentException("interface Class expected")
|
||||||
}
|
|
||||||
|
|
||||||
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<Object>() {
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getInterface(Object thiz, Class<T> iface)
|
protected open fun isImplemented(thiz: Any?, iface: Class<*>): Boolean {
|
||||||
throws ScriptException {
|
return true
|
||||||
if (iface == null || !iface.isInterface()) {
|
}
|
||||||
throw new IllegalArgumentException("interface Class expected");
|
|
||||||
|
@Throws(ScriptException::class)
|
||||||
|
protected open fun convertResult(method: Method?, res: Any): Any {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(ScriptException::class)
|
||||||
|
protected fun convertArguments(method: Method?, args: Array<Any>): Array<Any> {
|
||||||
|
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>): 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<Any>, 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -22,16 +22,10 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import org.mozilla.javascript.*
|
||||||
|
import org.mozilla.javascript.Function
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JSAdapter is java.lang.reflect.Proxy equivalent for JavaScript. JSAdapter
|
* JSAdapter is java.lang.reflect.Proxy equivalent for JavaScript. JSAdapter
|
||||||
@ -40,21 +34,21 @@ import org.mozilla.javascript.ScriptableObject;
|
|||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* var y = {
|
* var y = {
|
||||||
* __get__ : function (name) { ... }
|
* __get__ : function (name) { ... }
|
||||||
* __has__ : function (name) { ... }
|
* __has__ : function (name) { ... }
|
||||||
* __put__ : function (name, value) {...}
|
* __put__ : function (name, value) {...}
|
||||||
* __delete__ : function (name) { ... }
|
* __delete__ : function (name) { ... }
|
||||||
* __getIds__ : function () { ... }
|
* __getIds__ : function () { ... }
|
||||||
* };
|
* };
|
||||||
*
|
*
|
||||||
* var x = new JSAdapter(y);
|
* var x = new JSAdapter(y);
|
||||||
*
|
*
|
||||||
* x.i; // calls y.__get__
|
* x.i; // calls y.__get__
|
||||||
* i in x; // calls y.__has__
|
* i in x; // calls y.__has__
|
||||||
* x.p = 10; // calls y.__put__
|
* x.p = 10; // calls y.__put__
|
||||||
* delete x.p; // calls y.__delete__
|
* delete x.p; // calls y.__delete__
|
||||||
* for (i in x) { print(i); } // calls y.__getIds__
|
* for (i in x) { print(i); } // calls y.__getIds__
|
||||||
*
|
*
|
||||||
* If a special JavaScript method is not found in the adaptee, then JSAdapter
|
* If a special JavaScript method is not found in the adaptee, then JSAdapter
|
||||||
* forwards the property access to the adaptee itself.
|
* forwards the property access to the adaptee itself.
|
||||||
@ -74,270 +68,239 @@ import org.mozilla.javascript.ScriptableObject;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public final class JSAdapter implements Scriptable, Function {
|
class JSAdapter private constructor(val adaptee: Scriptable) : Scriptable, Function {
|
||||||
private JSAdapter(Scriptable obj) {
|
private var prototype: Scriptable? = null
|
||||||
setAdaptee(obj);
|
private var parent: Scriptable? = null
|
||||||
|
private var isPrototype = false
|
||||||
|
|
||||||
|
override fun getClassName(): String {
|
||||||
|
return "JSAdapter"
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializer to setup JSAdapter prototype in the given scope
|
override fun get(name: String, start: Scriptable): Any {
|
||||||
public static void init(Context cx, Scriptable scope, boolean sealed)
|
val func = getAdapteeFunction(GET_PROP)
|
||||||
throws RhinoException {
|
return if (func != null) {
|
||||||
JSAdapter obj = new JSAdapter(cx.newObject(scope));
|
this.call(func, arrayOf(name))
|
||||||
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 });
|
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee[name, adaptee]
|
||||||
return start.get(name, start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(int index, Scriptable start) {
|
override fun get(index: Int, start: Scriptable): Any {
|
||||||
Function func = getAdapteeFunction(GET_PROP);
|
val func = getAdapteeFunction(GET_PROP)
|
||||||
if (func != null) {
|
return if (func != null) {
|
||||||
return call(func, new Object[] {index});
|
this.call(func, arrayOf(index))
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee[index, adaptee]
|
||||||
return start.get(index, start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean has(String name, Scriptable start) {
|
override fun has(name: String, start: Scriptable): Boolean {
|
||||||
Function func = getAdapteeFunction(HAS_PROP);
|
val func = getAdapteeFunction(HAS_PROP)
|
||||||
if (func != null) {
|
return if (func != null) {
|
||||||
Object res = call(func, new Object[] { name });
|
val res = this.call(func, arrayOf(name))
|
||||||
return Context.toBoolean(res);
|
Context.toBoolean(res)
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee.has(name, adaptee)
|
||||||
return start.has(name, start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean has(int index, Scriptable start) {
|
override fun has(index: Int, start: Scriptable): Boolean {
|
||||||
Function func = getAdapteeFunction(HAS_PROP);
|
val func = getAdapteeFunction(HAS_PROP)
|
||||||
if (func != null) {
|
return if (func != null) {
|
||||||
Object res = call(func, new Object[] {index});
|
val res = this.call(func, arrayOf(index))
|
||||||
return Context.toBoolean(res);
|
Context.toBoolean(res)
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee.has(index, adaptee)
|
||||||
return start.has(index, start);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(String name, Scriptable start, Object value) {
|
override fun put(name: String, start: Scriptable, value: Any) {
|
||||||
if (start == this) {
|
if (start === this) {
|
||||||
Function func = getAdapteeFunction(PUT_PROP);
|
val func = getAdapteeFunction(PUT_PROP)
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
call(func, new Object[] { name, value });
|
this.call(func, arrayOf(name, value))
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee.put(name, adaptee, value)
|
||||||
start.put(name, start, value);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
start.put(name, start, value);
|
start.put(name, start, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(int index, Scriptable start, Object value) {
|
override fun put(index: Int, start: Scriptable, value: Any) {
|
||||||
if (start == this) {
|
if (start === this) {
|
||||||
Function func = getAdapteeFunction(PUT_PROP);
|
val func = getAdapteeFunction(PUT_PROP)
|
||||||
if( func != null) {
|
if (func != null) {
|
||||||
call(func, new Object[] {index, value });
|
this.call(func, arrayOf(index, value))
|
||||||
} else {
|
} else {
|
||||||
start = getAdaptee();
|
adaptee.put(index, adaptee, value)
|
||||||
start.put(index, start, value);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
start.put(index, start, value);
|
start.put(index, start, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(String name) {
|
override fun delete(name: String) {
|
||||||
Function func = getAdapteeFunction(DEL_PROP);
|
val func = getAdapteeFunction(DEL_PROP)
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
call(func, new Object[] { name });
|
this.call(func, arrayOf(name))
|
||||||
} else {
|
} else {
|
||||||
getAdaptee().delete(name);
|
adaptee.delete(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void delete(int index) {
|
override fun delete(index: Int) {
|
||||||
Function func = getAdapteeFunction(DEL_PROP);
|
val func = getAdapteeFunction(DEL_PROP)
|
||||||
if (func != null) {
|
if (func != null) {
|
||||||
call(func, new Object[] {index});
|
this.call(func, arrayOf(index))
|
||||||
} else {
|
} else {
|
||||||
getAdaptee().delete(index);
|
adaptee.delete(index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scriptable getPrototype() {
|
override fun getPrototype(): Scriptable? {
|
||||||
return prototype;
|
return prototype
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPrototype(Scriptable prototype) {
|
override fun setPrototype(prototype: Scriptable?) {
|
||||||
this.prototype = prototype;
|
this.prototype = prototype
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scriptable getParentScope() {
|
override fun getParentScope(): Scriptable? {
|
||||||
return parent;
|
return parent
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParentScope(Scriptable parent) {
|
override fun setParentScope(parent: Scriptable?) {
|
||||||
this.parent = parent;
|
this.parent = parent
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object[] getIds() {
|
override fun getIds(): Array<Any?> {
|
||||||
Function func = getAdapteeFunction(GET_PROPIDS);
|
val func = getAdapteeFunction(GET_PROPIDS)
|
||||||
if (func != null) {
|
return if (func == null) {
|
||||||
Object val = call(func, new Object[0]);
|
adaptee.ids
|
||||||
// in most cases, adaptee would return native JS array
|
} else {
|
||||||
if (val instanceof NativeArray) {
|
val val1 = this.call(func, arrayOfNulls(0))
|
||||||
NativeArray array = (NativeArray) val;
|
val res: Array<Any?>
|
||||||
Object[] res = new Object[(int)array.getLength()];
|
when (val1) {
|
||||||
for (int index = 0; index < res.length; index++) {
|
is NativeArray -> {
|
||||||
res[index] = mapToId(array.get(index, array));
|
res = arrayOfNulls(val1.length.toInt())
|
||||||
}
|
for (index in res.indices) {
|
||||||
return res;
|
res[index] = mapToId(val1[index, val1])
|
||||||
} 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]);
|
|
||||||
}
|
}
|
||||||
} else {
|
res
|
||||||
// just return an empty array
|
}
|
||||||
res = Context.emptyArgs;
|
!is NativeJavaArray -> {
|
||||||
|
Context.emptyArgs
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val tmp = val1.unwrap()
|
||||||
|
if (tmp.javaClass == Array<Any>::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) {
|
override fun hasInstance(scriptable: Scriptable): Boolean {
|
||||||
if (scriptable instanceof JSAdapter) {
|
return if (scriptable is JSAdapter) {
|
||||||
return true;
|
true
|
||||||
} else {
|
} else {
|
||||||
Scriptable proto = scriptable.getPrototype();
|
var proto = scriptable.prototype
|
||||||
while (proto != null) {
|
while (proto != null) {
|
||||||
if (proto.equals(this)) return true;
|
if (proto == this) {
|
||||||
proto = proto.getPrototype();
|
return true
|
||||||
|
}
|
||||||
|
proto = proto.prototype
|
||||||
}
|
}
|
||||||
return false;
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getDefaultValue(Class hint) {
|
override fun getDefaultValue(hint: Class<*>?): Any {
|
||||||
return getAdaptee().getDefaultValue(hint);
|
return adaptee.getDefaultValue(hint)
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
|
@Throws(RhinoException::class)
|
||||||
Object[] args)
|
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any>): Any {
|
||||||
throws RhinoException {
|
return if (isPrototype) {
|
||||||
if (isPrototype) {
|
construct(cx, scope, args)
|
||||||
return construct(cx, scope, args);
|
|
||||||
} else {
|
} else {
|
||||||
Scriptable tmp = getAdaptee();
|
val tmp = adaptee
|
||||||
if (tmp instanceof Function) {
|
if (tmp is Function) {
|
||||||
return ((Function)tmp).call(cx, scope, tmp, args);
|
tmp.call(cx, scope, tmp, args)
|
||||||
} else {
|
} 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::class)
|
||||||
throws RhinoException {
|
override fun construct(cx: Context, scope: Scriptable, args: Array<Any>): Scriptable {
|
||||||
if (isPrototype) {
|
val tmp: Scriptable?
|
||||||
Scriptable topLevel = ScriptableObject.getTopLevelScope(scope);
|
return if (isPrototype) {
|
||||||
JSAdapter newObj;
|
tmp = ScriptableObject.getTopLevelScope(scope)
|
||||||
if (args.length > 0) {
|
if (args.size > 0) {
|
||||||
newObj = new JSAdapter(Context.toObject(args[0], topLevel));
|
JSAdapter(Context.toObject(args[0], tmp))
|
||||||
} else {
|
} else {
|
||||||
throw Context.reportRuntimeError("JSAdapter requires adaptee");
|
throw Context.reportRuntimeError("JSAdapter requires adaptee")
|
||||||
}
|
}
|
||||||
return newObj;
|
|
||||||
} else {
|
} else {
|
||||||
Scriptable tmp = getAdaptee();
|
tmp = adaptee
|
||||||
if (tmp instanceof Function) {
|
if (tmp is Function) {
|
||||||
return ((Function)tmp).construct(cx, scope, args);
|
tmp.construct(cx, scope, args)
|
||||||
} else {
|
} else {
|
||||||
throw Context.reportRuntimeError("TypeError: not a constructor");
|
throw Context.reportRuntimeError("TypeError: not a constructor")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Scriptable getAdaptee() {
|
private fun mapToId(tmp: Any?): Any {
|
||||||
return adaptee;
|
return if (tmp is Double) tmp.toInt() else Context.toString(tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAdaptee(Scriptable adaptee) {
|
private fun getAdapteeFunction(name: String): Function? {
|
||||||
if (adaptee == null) {
|
val o = ScriptableObject.getProperty(adaptee, name)
|
||||||
throw new NullPointerException("adaptee can not be null");
|
return if (o is Function) o else null
|
||||||
}
|
|
||||||
this.adaptee = adaptee;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//-- internals only below this point
|
private fun call(func: Function, args: Array<Any?>): Any {
|
||||||
|
val cx = Context.getCurrentContext()
|
||||||
// map a property id. Property id can only be an Integer or String
|
val thisObj = adaptee
|
||||||
private Object mapToId(Object tmp) {
|
val scope = func.parentScope
|
||||||
if (tmp instanceof Double) {
|
return try {
|
||||||
return ((Double) tmp).intValue();
|
func.call(cx, scope, thisObj, args)
|
||||||
} else {
|
} catch (var7: RhinoException) {
|
||||||
return Context.toString(tmp);
|
throw Context.reportRuntimeError(var7.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Scriptable getFunctionPrototype(Scriptable scope) {
|
companion object {
|
||||||
return ScriptableObject.getFunctionPrototype(scope);
|
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) {
|
@Throws(RhinoException::class)
|
||||||
Object o = ScriptableObject.getProperty(getAdaptee(), name);
|
fun init(cx: Context, scope: Scriptable, sealed: Boolean) {
|
||||||
return (o instanceof Function)? (Function)o : null;
|
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) {
|
private fun getFunctionPrototype(scope: Scriptable): Scriptable {
|
||||||
Context cx = Context.getCurrentContext();
|
return ScriptableObject.getFunctionPrototype(scope)
|
||||||
Scriptable thisObj = getAdaptee();
|
|
||||||
Scriptable scope = func.getParentScope();
|
|
||||||
try {
|
|
||||||
return func.call(cx, scope, thisObj, args);
|
|
||||||
} catch (RhinoException re) {
|
|
||||||
throw Context.reportRuntimeError(re.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
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__";
|
|
||||||
}
|
|
@ -22,31 +22,26 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import com.script.Invocable
|
||||||
|
import org.mozilla.javascript.*
|
||||||
import com.script.Invocable;
|
import org.mozilla.javascript.Function
|
||||||
|
|
||||||
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
|
* This class implements Rhino-like JavaAdapter to help implement a Java
|
||||||
* interface in JavaScript. We support this using Invocable.getInterface.
|
* interface in JavaScript. We support this using Invocable.getInterface.
|
||||||
* Using this JavaAdapter, script author could write:
|
* Using this JavaAdapter, script author could write:
|
||||||
*
|
*
|
||||||
* var r = new java.lang.Runnable() {
|
|
||||||
* run: function() { script... }
|
|
||||||
* };
|
|
||||||
*
|
*
|
||||||
* r.run();
|
* var r = new java.lang.Runnable() {
|
||||||
* new java.lang.Thread(r).start();
|
* run: function() { script... }
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* r.run();
|
||||||
|
* new java.lang.Thread(r).start();
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Note that Rhino's JavaAdapter support allows extending a Java class and/or
|
* Note that Rhino's JavaAdapter support allows extending a Java class and/or
|
||||||
* implementing one or more interfaces. This JavaAdapter implementation does
|
* implementing one or more interfaces. This JavaAdapter implementation does
|
||||||
@ -55,60 +50,54 @@ import org.mozilla.javascript.Wrapper;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
final class JavaAdapter extends ScriptableObject implements Function {
|
internal class JavaAdapter private constructor(private val engine: Invocable) : ScriptableObject(),
|
||||||
private JavaAdapter(Invocable engine) {
|
Function {
|
||||||
this.engine = engine;
|
override fun getClassName(): String {
|
||||||
|
return "JavaAdapter"
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init(Context cx, Scriptable scope, boolean sealed)
|
@Throws(RhinoException::class)
|
||||||
throws RhinoException {
|
override fun call(cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array<Any>): Any {
|
||||||
RhinoTopLevel topLevel = (RhinoTopLevel) scope;
|
return construct(cx, scope, args)
|
||||||
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() {
|
@Throws(RhinoException::class)
|
||||||
return "JavaAdapter";
|
override fun construct(cx: Context, scope: Scriptable, args: Array<Any>): Scriptable {
|
||||||
}
|
return if (args.size == 2) {
|
||||||
|
var clazz: Class<*>? = null
|
||||||
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
|
val obj1 = args[0]
|
||||||
Object[] args) throws RhinoException {
|
if (obj1 is Wrapper) {
|
||||||
return construct(cx, scope, args);
|
val o = obj1.unwrap()
|
||||||
}
|
if (o is Class<*> && o.isInterface) {
|
||||||
|
clazz = o
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
} else if (obj1 is Class<*> && obj1.isInterface) {
|
||||||
|
clazz = obj1
|
||||||
}
|
}
|
||||||
if (clazz == null) {
|
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 {
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,13 +22,9 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import org.mozilla.javascript.ClassShutter
|
||||||
|
|
||||||
import org.mozilla.javascript.ClassShutter;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class prevents script access to certain sensitive classes.
|
* This class prevents script access to certain sensitive classes.
|
||||||
@ -38,43 +34,38 @@ import java.util.Map;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
final class RhinoClassShutter implements ClassShutter {
|
internal class RhinoClassShutter private constructor() : ClassShutter {
|
||||||
private static Map<String, Boolean> protectedClasses;
|
override fun visibleToScripts(fullClassName: String): Boolean {
|
||||||
private static RhinoClassShutter theInstance;
|
val sm = System.getSecurityManager()
|
||||||
|
|
||||||
private RhinoClassShutter() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized ClassShutter getInstance() {
|
|
||||||
if (theInstance == null) {
|
|
||||||
theInstance = new RhinoClassShutter();
|
|
||||||
protectedClasses = new HashMap<String, Boolean>();
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
int i = fullClassName.lastIndexOf(".");
|
val i = fullClassName.lastIndexOf(".")
|
||||||
if (i != -1) {
|
if (i != -1) {
|
||||||
try {
|
try {
|
||||||
sm.checkPackageAccess(fullClassName.substring(0, i));
|
sm.checkPackageAccess(fullClassName.substring(0, i))
|
||||||
} catch (SecurityException se) {
|
} catch (var5: SecurityException) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// now, check is it a protected class.
|
return protectedClasses[fullClassName] == null
|
||||||
return protectedClasses.get(fullClassName) == null;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
val protectedClasses by lazy {
|
||||||
|
val protectedClasses = HashMap<Any, Any>()
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -22,20 +22,13 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import com.script.CompiledScript
|
||||||
|
import com.script.ScriptContext
|
||||||
import com.script.CompiledScript;
|
import com.script.ScriptEngine
|
||||||
import com.script.ScriptContext;
|
import com.script.ScriptException
|
||||||
import com.script.ScriptEngine;
|
import org.mozilla.javascript.*
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents compiled JavaScript code.
|
* Represents compiled JavaScript code.
|
||||||
@ -43,46 +36,36 @@ import org.mozilla.javascript.Scriptable;
|
|||||||
* @author Mike Grogan
|
* @author Mike Grogan
|
||||||
* @since 1.6
|
* @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;
|
@Throws(ScriptException::class)
|
||||||
private Script script;
|
override fun eval(context: ScriptContext): Any? {
|
||||||
|
val cx = Context.enter()
|
||||||
|
val result: Any?
|
||||||
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();
|
|
||||||
try {
|
try {
|
||||||
|
val scope = engine.getRuntimeScope(context)
|
||||||
Scriptable scope = engine.getRuntimeScope(context);
|
val ret = script.exec(cx, scope)
|
||||||
Object ret = script.exec(cx, scope);
|
result = engine.unwrapReturnValue(ret)
|
||||||
result = engine.unwrapReturnValue(ret);
|
} catch (re: RhinoException) {
|
||||||
} catch (RhinoException re) {
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
||||||
int line = (line = re.lineNumber()) == 0 ? -1 : line;
|
val msg: String = if (re is JavaScriptException) {
|
||||||
String msg;
|
re.value.toString()
|
||||||
if (re instanceof JavaScriptException) {
|
|
||||||
msg = String.valueOf(((JavaScriptException)re).getValue());
|
|
||||||
} else {
|
} else {
|
||||||
msg = re.toString();
|
re.toString()
|
||||||
}
|
}
|
||||||
ScriptException se = new ScriptException(msg, re.sourceName(), line);
|
val se = ScriptException(msg, re.sourceName(), line)
|
||||||
se.initCause(re);
|
se.initCause(re)
|
||||||
throw se;
|
throw se
|
||||||
} finally {
|
} finally {
|
||||||
Context.exit();
|
Context.exit()
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptEngine getEngine() {
|
override fun getEngine(): ScriptEngine {
|
||||||
return engine;
|
return engine
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
@ -22,440 +22,358 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import com.script.*
|
||||||
|
import com.script.rhino.RhinoClassShutter.Companion.instance
|
||||||
|
import org.intellij.lang.annotations.Language
|
||||||
import com.script.AbstractScriptEngine;
|
import org.mozilla.javascript.*
|
||||||
import com.script.Bindings;
|
import org.mozilla.javascript.Function
|
||||||
import com.script.Compilable;
|
import java.io.IOException
|
||||||
import com.script.CompiledScript;
|
import java.io.Reader
|
||||||
import com.script.Invocable;
|
import java.io.StringReader
|
||||||
import com.script.ScriptContext;
|
import java.lang.reflect.Method
|
||||||
import com.script.ScriptEngine;
|
import java.security.*
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of <code>ScriptEngine</code> using the Mozilla Rhino
|
* Implementation of `ScriptEngine` using the Mozilla Rhino
|
||||||
* interpreter.
|
* interpreter.
|
||||||
*
|
*
|
||||||
* @author Mike Grogan
|
* @author Mike Grogan
|
||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public final class RhinoScriptEngine extends AbstractScriptEngine
|
class RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
||||||
implements Invocable, Compilable {
|
var accessContext: AccessControlContext? = null
|
||||||
|
private var topLevel: RhinoTopLevel? = null
|
||||||
|
private val indexedProps: MutableMap<Any, Any>
|
||||||
|
private val implementor: InterfaceImplementor
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
@Throws(ScriptException::class)
|
||||||
|
override fun eval(reader: Reader, ctxt: ScriptContext): Any {
|
||||||
private AccessControlContext accCtxt;
|
val cx = Context.enter()
|
||||||
|
val ret: Any
|
||||||
/* 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<Object, Object> 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<Object>() {
|
|
||||||
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();
|
|
||||||
try {
|
try {
|
||||||
topLevel = new RhinoTopLevel(cx, this);
|
val scope = getRuntimeScope(ctxt)
|
||||||
} finally {
|
var filename = this["javax.script.filename"] as? String
|
||||||
cx.exit();
|
filename = filename ?: "<Unknown source>"
|
||||||
}
|
ret = cx.evaluateReader(scope, reader, filename, 1, null as Any?)
|
||||||
|
} catch (re: RhinoException) {
|
||||||
indexedProps = new HashMap<Object, Object>();
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
||||||
|
val msg: String = if (re is JavaScriptException) {
|
||||||
//construct object used to implement getInterface
|
re.value.toString()
|
||||||
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 ? "<Unknown source>" : 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());
|
|
||||||
} else {
|
} else {
|
||||||
msg = re.toString();
|
re.toString()
|
||||||
}
|
}
|
||||||
ScriptException se = new ScriptException(msg, re.sourceName(), line);
|
val se = ScriptException(msg, re.sourceName(), line)
|
||||||
se.initCause(re);
|
se.initCause(re)
|
||||||
throw se;
|
throw se
|
||||||
} catch (IOException ee) {
|
} catch (var14: IOException) {
|
||||||
throw new ScriptException(ee);
|
throw ScriptException(var14)
|
||||||
} finally {
|
} finally {
|
||||||
cx.exit();
|
Context.exit()
|
||||||
}
|
}
|
||||||
|
return unwrapReturnValue(ret)!!
|
||||||
return unwrapReturnValue(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object eval(String script, ScriptContext ctxt) throws ScriptException {
|
@Throws(ScriptException::class)
|
||||||
if (script == null) {
|
override fun eval(script: String?, ctxt: ScriptContext): Any {
|
||||||
throw new NullPointerException("null script");
|
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() {
|
override fun createBindings(): Bindings {
|
||||||
return new SimpleBindings();
|
return SimpleBindings()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Invocable methods
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
||||||
public Object invokeFunction(String name, Object... args)
|
override fun invokeFunction(name: String, vararg args: Any): Any {
|
||||||
throws ScriptException, NoSuchMethodException {
|
return this.invoke(null as Any?, name, *args)
|
||||||
return invoke(null, name, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object invokeMethod(Object thiz, String name, Object... args)
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
||||||
throws ScriptException, NoSuchMethodException {
|
override fun invokeMethod(thiz: Any?, name: String, vararg args: Any): Any {
|
||||||
if (thiz == null) {
|
return if (thiz == null) {
|
||||||
throw new IllegalArgumentException("script object can not be null");
|
throw IllegalArgumentException("脚本对象不能为空")
|
||||||
|
} else {
|
||||||
|
this.invoke(thiz, name, *args)
|
||||||
}
|
}
|
||||||
return invoke(thiz, name, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object invoke(Object thiz, String name, Object... args)
|
@Suppress("UNCHECKED_CAST")
|
||||||
throws ScriptException, NoSuchMethodException {
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
||||||
Context cx = enterContext();
|
private operator fun invoke(thiz: Any?, name: String?, vararg args: Any?): Any {
|
||||||
|
var thiz1 = thiz
|
||||||
|
val cx = Context.enter()
|
||||||
|
val var11: Any
|
||||||
try {
|
try {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
throw new NullPointerException("method name is null");
|
throw NullPointerException("方法名为空")
|
||||||
}
|
}
|
||||||
|
if (thiz1 != null && thiz1 !is Scriptable) {
|
||||||
if (thiz != null && !(thiz instanceof Scriptable)) {
|
thiz1 = Context.toObject(thiz1, topLevel)
|
||||||
thiz = cx.toObject(thiz, topLevel);
|
|
||||||
}
|
}
|
||||||
|
val engineScope = getRuntimeScope(context)
|
||||||
Scriptable engineScope = getRuntimeScope(context);
|
val localScope = if (thiz1 != null) thiz1 as Scriptable else engineScope
|
||||||
Scriptable localScope = (thiz != null) ? (Scriptable) thiz :
|
val obj = ScriptableObject.getProperty(localScope, name) as? Function
|
||||||
engineScope;
|
?: throw NoSuchMethodException("no such method: $name")
|
||||||
Object obj = ScriptableObject.getProperty(localScope, name);
|
val func = obj
|
||||||
if (!(obj instanceof Function)) {
|
var scope = func.parentScope
|
||||||
throw new NoSuchMethodException("no such method: " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
Function func = (Function) obj;
|
|
||||||
Scriptable scope = func.getParentScope();
|
|
||||||
if (scope == null) {
|
if (scope == null) {
|
||||||
scope = engineScope;
|
scope = engineScope
|
||||||
}
|
}
|
||||||
Object result = func.call(cx, scope, localScope,
|
val result = func.call(cx, scope, localScope, wrapArguments(args as? Array<Any?>))
|
||||||
wrapArguments(args));
|
var11 = unwrapReturnValue(result)!!
|
||||||
return unwrapReturnValue(result);
|
} catch (re: RhinoException) {
|
||||||
} catch (RhinoException re) {
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
||||||
if (DEBUG) re.printStackTrace();
|
val se = ScriptException(re.toString(), re.sourceName(), line)
|
||||||
int line = (line = re.lineNumber()) == 0 ? -1 : line;
|
se.initCause(re)
|
||||||
ScriptException se = new ScriptException(re.toString(), re.sourceName(), line);
|
throw se
|
||||||
se.initCause(re);
|
|
||||||
throw se;
|
|
||||||
} finally {
|
} finally {
|
||||||
cx.exit();
|
Context.exit()
|
||||||
|
}
|
||||||
|
return var11
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T> getInterface(clasz: Class<T>): T? {
|
||||||
|
return try {
|
||||||
|
implementor.getInterface(null as Any?, clasz)
|
||||||
|
} catch (var3: ScriptException) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T getInterface(Class<T> clasz) {
|
override fun <T> getInterface(thiz: Any?, clasz: Class<T>): 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 {
|
try {
|
||||||
return implementor.getInterface(null, clasz);
|
var fileName = this["javax.script.filename"] as? String
|
||||||
} catch (ScriptException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> T getInterface(Object thiz, Class<T> 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);
|
|
||||||
if (fileName == null) {
|
if (fileName == null) {
|
||||||
fileName = "<Unknown Source>";
|
fileName = "<Unknown Source>"
|
||||||
|
}
|
||||||
|
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<Any?>?): Array<Any?> {
|
||||||
|
return if (args == null) {
|
||||||
|
Context.emptyArgs
|
||||||
|
} else {
|
||||||
|
val res = arrayOfNulls<Any>(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);
|
override fun convertResult(method: Method?, res: Any): Any {
|
||||||
@SuppressWarnings("deprecation")
|
val desiredType = method!!.returnType
|
||||||
Script scr = cx.compileReader(scope, script, fileName, 1, null);
|
return (if (desiredType == Void.TYPE) null else Context.jsToJava(
|
||||||
ret = new RhinoCompiledScript(this, scr);
|
res,
|
||||||
} catch (Exception e) {
|
desiredType
|
||||||
if (DEBUG) e.printStackTrace();
|
))!!
|
||||||
throw new ScriptException(e);
|
}
|
||||||
} finally {
|
|
||||||
cx.exit();
|
|
||||||
}
|
}
|
||||||
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() {
|
init {
|
||||||
// call this always so that initializer of this class runs
|
ContextFactory.initGlobal(object : ContextFactory() {
|
||||||
// and initializes custom wrap factory and class shutter.
|
override fun makeContext(): Context {
|
||||||
return Context.enter();
|
val cx = super.makeContext()
|
||||||
}
|
cx.languageVersion = 200
|
||||||
|
cx.optimizationLevel = -1
|
||||||
|
cx.setClassShutter(instance)
|
||||||
|
cx.wrapFactory = RhinoWrapFactory.instance
|
||||||
|
return cx
|
||||||
|
}
|
||||||
|
|
||||||
AccessControlContext getAccessContext() {
|
override fun doTopCall(
|
||||||
return accCtxt;
|
callable: Callable,
|
||||||
}
|
cx: Context,
|
||||||
|
scope: Scriptable,
|
||||||
|
thisObj: Scriptable,
|
||||||
|
args: Array<Any>
|
||||||
|
): 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<Any>, accCtxt) else superDoTopCall(
|
||||||
|
callable,
|
||||||
|
cx,
|
||||||
|
scope,
|
||||||
|
thisObj,
|
||||||
|
args
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Object[] wrapArguments(Object[] args) {
|
private fun superDoTopCall(
|
||||||
if (args == null) {
|
callable: Callable,
|
||||||
return Context.emptyArgs;
|
cx: Context,
|
||||||
|
scope: Scriptable,
|
||||||
|
thisObj: Scriptable,
|
||||||
|
args: Array<Any>
|
||||||
|
): 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"));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
@ -22,24 +22,14 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import com.script.Bindings
|
||||||
|
import com.script.ScriptContext
|
||||||
import com.script.Bindings;
|
import com.script.SimpleScriptContext
|
||||||
import com.script.ScriptContext;
|
import org.mozilla.javascript.*
|
||||||
import com.script.SimpleScriptContext;
|
import org.mozilla.javascript.Function
|
||||||
|
import java.security.AccessControlContext
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class serves as top level scope for Rhino. This class adds
|
* This class serves as top level scope for Rhino. This class adds
|
||||||
@ -49,129 +39,69 @@ import java.security.AccessControlContext;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
public final class RhinoTopLevel extends ImporterTopLevel {
|
@Suppress("UNUSED_PARAMETER")
|
||||||
RhinoTopLevel(Context cx, RhinoScriptEngine engine) {
|
class RhinoTopLevel internal constructor(cx: Context?, val scriptEngine: RhinoScriptEngine) :
|
||||||
// second boolean parameter to super constructor tells whether
|
ImporterTopLevel(cx, System.getSecurityManager() != null) {
|
||||||
// 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;
|
|
||||||
|
|
||||||
// initialize JSAdapter lazily. Reduces footprint & startup time.
|
init {
|
||||||
new LazilyLoadedCtor(this, "JSAdapter",
|
LazilyLoadedCtor(this, "JSAdapter", "com.sun.script.javascript.JSAdapter", false)
|
||||||
"com.sun.script.javascript.JSAdapter",
|
JavaAdapter.init(cx, this, false)
|
||||||
false);
|
val names = arrayOf("bindings", "scope", "sync")
|
||||||
|
defineFunctionProperties(names, RhinoTopLevel::class.java, 2)
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
val accessContext: AccessControlContext?
|
||||||
* The bindings function takes a JavaScript scope object
|
get() = scriptEngine.accessContext
|
||||||
* of type ExternalScriptable and returns the underlying Bindings
|
|
||||||
* instance.
|
companion object {
|
||||||
*
|
|
||||||
* var page = scope(pageBindings);
|
@JvmStatic
|
||||||
* with (page) {
|
fun bindings(
|
||||||
* // code that uses page scope
|
cx: Context?,
|
||||||
* }
|
thisObj: Scriptable?,
|
||||||
* var b = bindings(page);
|
args: Array<Any?>,
|
||||||
* // operate on bindings here.
|
funObj: Function?
|
||||||
*/
|
): Any {
|
||||||
public static Object bindings(Context cx, Scriptable thisObj, Object[] args,
|
if (args.size == 1) {
|
||||||
Function funObj) {
|
var arg = args[0]
|
||||||
if (args.length == 1) {
|
if (arg is Wrapper) {
|
||||||
Object arg = args[0];
|
arg = arg.unwrap()
|
||||||
if (arg instanceof Wrapper) {
|
}
|
||||||
arg = ((Wrapper)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) {
|
return Context.getUndefinedValue()
|
||||||
ScriptContext ctx = ((com.script.rhino.ExternalScriptable)arg).getContext();
|
}
|
||||||
Bindings bind = ctx.getBindings(ScriptContext.ENGINE_SCOPE);
|
|
||||||
return Context.javaToJS(bind,
|
@JvmStatic
|
||||||
ScriptableObject.getTopLevelScope(thisObj));
|
fun scope(cx: Context?, thisObj: Scriptable?, args: Array<Any?>, 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<Any?>, 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 <code>this</code> 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;
|
|
||||||
}
|
|
@ -22,18 +22,14 @@
|
|||||||
* or visit www.oracle.com if you need additional information or have any
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
* questions.
|
* questions.
|
||||||
*/
|
*/
|
||||||
|
package com.script.rhino
|
||||||
|
|
||||||
package com.script.rhino;
|
import org.mozilla.javascript.Context
|
||||||
|
import org.mozilla.javascript.NativeJavaObject
|
||||||
import org.mozilla.javascript.ClassShutter;
|
import org.mozilla.javascript.Scriptable
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.WrapFactory
|
||||||
import org.mozilla.javascript.NativeJavaObject;
|
import java.lang.reflect.Member
|
||||||
import org.mozilla.javascript.Scriptable;
|
import java.lang.reflect.Modifier
|
||||||
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
|
* This wrap factory is used for security reasons. JSR 223 script
|
||||||
@ -48,118 +44,88 @@ import java.lang.reflect.Modifier;
|
|||||||
* @author A. Sundararajan
|
* @author A. Sundararajan
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
*/
|
*/
|
||||||
final class RhinoWrapFactory extends WrapFactory {
|
internal class RhinoWrapFactory private constructor() : WrapFactory() {
|
||||||
private RhinoWrapFactory() {}
|
|
||||||
private static RhinoWrapFactory theInstance;
|
|
||||||
|
|
||||||
static synchronized WrapFactory getInstance() {
|
override fun wrapAsJavaObject(
|
||||||
if (theInstance == null) {
|
cx: Context,
|
||||||
theInstance = new RhinoWrapFactory();
|
scope: Scriptable?,
|
||||||
}
|
javaObject: Any,
|
||||||
return theInstance;
|
staticType: Class<*>?
|
||||||
}
|
): Scriptable? {
|
||||||
|
scope?.delete("Packages")
|
||||||
// We use instance of this class to wrap security sensitive
|
val sm = System.getSecurityManager()
|
||||||
// Java object. Please refer below.
|
val classShutter = RhinoClassShutter.instance
|
||||||
private static class RhinoJavaObject extends NativeJavaObject {
|
return if (javaObject is ClassLoader) {
|
||||||
RhinoJavaObject(Scriptable scope, Object obj, Class type) {
|
sm?.checkPermission(RuntimePermission("getClassLoader"))
|
||||||
// we pass 'null' to object. NativeJavaObject uses
|
super.wrapAsJavaObject(cx, scope, javaObject, staticType)
|
||||||
// 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);
|
|
||||||
} else {
|
} else {
|
||||||
String name = null;
|
var name: String? = null
|
||||||
if (javaObject instanceof Class) {
|
if (javaObject is Class<*>) {
|
||||||
name = ((Class)javaObject).getName();
|
name = javaObject.name
|
||||||
} else if (javaObject instanceof Member) {
|
} else if (javaObject is Member) {
|
||||||
Member member = (Member) javaObject;
|
if (sm != null && !Modifier.isPublic(javaObject.modifiers)) {
|
||||||
// Check member access. Don't allow reflective access to
|
return null
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
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 (name != null) {
|
||||||
if (!classShutter.visibleToScripts(name)) {
|
if (!classShutter.visibleToScripts(name)) null else super.wrapAsJavaObject(
|
||||||
return null;
|
cx,
|
||||||
} else {
|
scope,
|
||||||
return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
|
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;
|
|
||||||
} else {
|
} else {
|
||||||
// dynamicType is always a class type and never an interface.
|
var dynamicType: Class<*>? = javaObject.javaClass
|
||||||
// find an accessible super class of the dynamic type.
|
name = dynamicType!!.name
|
||||||
while (dynamicType != null) {
|
if (classShutter.visibleToScripts(name)) {
|
||||||
dynamicType = dynamicType.getSuperclass();
|
super.wrapAsJavaObject(cx, scope, javaObject, staticType)
|
||||||
name = dynamicType.getName();
|
} else {
|
||||||
if (classShutter.visibleToScripts(name)) {
|
var type: Class<*>? = null
|
||||||
type = dynamicType; break;
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user