/* * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.script.rhino import com.script.* import org.mozilla.javascript.* import org.mozilla.javascript.Function import java.io.IOException import java.io.Reader import java.io.StringReader import java.lang.reflect.Method import java.security.* /** * Implementation of `ScriptEngine` using the Mozilla Rhino * interpreter. * * @author Mike Grogan * @author A. Sundararajan * @since 1.6 */ @Suppress("MemberVisibilityCanBePrivate") object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable { var accessContext: AccessControlContext? = null private var topLevel: RhinoTopLevel? = null private val indexedProps: MutableMap private val implementor: InterfaceImplementor fun eval(js: String, bindingsConfig: SimpleBindings.() -> Unit = {}): Any? { val bindings = SimpleBindings() bindings.apply(bindingsConfig) return eval(js, bindings) } @Throws(ScriptException::class) override fun eval(reader: Reader, scope: Scriptable): Any? { val cx = Context.enter() val ret: Any? try { var filename = this["javax.script.filename"] as? String filename = filename ?: "" ret = cx.evaluateReader(scope, reader, filename, 1, null) } catch (re: RhinoException) { val line = if (re.lineNumber() == 0) -1 else re.lineNumber() val msg: String = if (re is JavaScriptException) { re.value.toString() } else { re.toString() } val se = ScriptException(msg, re.sourceName(), line) se.initCause(re) throw se } catch (var14: IOException) { throw ScriptException(var14) } finally { Context.exit() } return unwrapReturnValue(ret) } override fun createBindings(): Bindings { return SimpleBindings() } @Throws(ScriptException::class, NoSuchMethodException::class) override fun invokeFunction(name: String, vararg args: Any): Any? { return this.invoke(null, name, *args) } @Throws(ScriptException::class, NoSuchMethodException::class) override fun invokeMethod(obj: Any?, name: String, vararg args: Any): Any? { return if (obj == null) { throw IllegalArgumentException("脚本对象不能为空") } else { this.invoke(obj, name, *args) } } @Suppress("UNCHECKED_CAST") @Throws(ScriptException::class, NoSuchMethodException::class) private operator fun invoke(thiz: Any?, name: String?, vararg args: Any?): Any? { var thiz1 = thiz val cx = Context.enter() val var11: Any? try { if (name == null) { throw NullPointerException("方法名为空") } 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 obj = ScriptableObject.getProperty(localScope, name) as? Function ?: throw NoSuchMethodException("no such method: $name") var scope = obj.parentScope if (scope == null) { scope = engineScope } val result = obj.call(cx, scope, localScope, wrapArguments(args as? Array)) var11 = unwrapReturnValue(result) } catch (re: RhinoException) { val line = if (re.lineNumber() == 0) -1 else re.lineNumber() val se = ScriptException(re.toString(), re.sourceName(), line) se.initCause(re) throw se } finally { Context.exit() } return var11 } override fun getInterface(clazz: Class): T? { return try { implementor.getInterface(null, clazz) } catch (var3: ScriptException) { null } } override fun getInterface(obj: Any?, paramClass: Class): T? { return if (obj == null) { throw IllegalArgumentException("脚本对象不能为空") } else { try { implementor.getInterface(obj, paramClass) } catch (var4: ScriptException) { null } } } override fun getRuntimeScope(context: ScriptContext): Scriptable { val newScope: Scriptable = ExternalScriptable(context, indexedProps) newScope.prototype = topLevel newScope.put("context", newScope, context) return 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 { var fileName = this["javax.script.filename"] as? String if (fileName == null) { fileName = "" } val scr = cx.compileReader(script, fileName, 1, null) ret = RhinoCompiledScript(this, scr) } catch (var9: Exception) { throw ScriptException(var9) } finally { Context.exit() } return ret } fun wrapArguments(args: Array?): Array { return if (args == null) { Context.emptyArgs } else { val res = arrayOfNulls(args.size) for (i in res.indices) { res[i] = Context.javaToJS(args[i], topLevel) } res } } fun unwrapReturnValue(result: Any?): Any? { var result1 = result if (result1 is Wrapper) { result1 = result1.unwrap() } return if (result1 is Undefined) null else result1 } init { ContextFactory.initGlobal(object : ContextFactory() { override fun makeContext(): Context { val cx = super.makeContext() cx.languageVersion = 200 cx.optimizationLevel = -1 cx.setClassShutter(RhinoClassShutter) cx.wrapFactory = RhinoWrapFactory return cx } override fun hasFeature(cx: Context, featureIndex: Int): Boolean { @Suppress("UNUSED_EXPRESSION") return when (featureIndex) { //Context.FEATURE_ENABLE_JAVA_MAP_ACCESS -> true else -> super.hasFeature(cx, featureIndex) } } override fun doTopCall( callable: Callable, cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array ): Any? { var accContext: AccessControlContext? = null val global = ScriptableObject.getTopLevelScope(scope) val globalProto = global.prototype if (globalProto is RhinoTopLevel) { accContext = globalProto.accessContext } return if (accContext != null) AccessController.doPrivileged( PrivilegedAction { superDoTopCall(callable, cx, scope, thisObj, args) }, accContext ) else superDoTopCall( callable, cx, scope, thisObj, args ) } private fun superDoTopCall( callable: Callable, cx: Context, scope: Scriptable, thisObj: Scriptable, args: Array ): Any? { return super.doTopCall(callable, cx, scope, thisObj, args) } }) 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(obj: Any?, clazz: Class<*>): Boolean { var obj1 = obj return try { if (obj1 != null && obj1 !is Scriptable) { obj1 = Context.toObject(obj1, topLevel) } val engineScope = getRuntimeScope(context) val localScope = if (obj1 != null) obj1 as Scriptable else engineScope val methods = clazz.methods val methodsSize = methods.size for (index in 0 until methodsSize) { val method = methods[index] if (method.declaringClass != Any::class.java) { if (ScriptableObject.getProperty( localScope, method.name ) !is Function ) { return false } } } true } finally { Context.exit() } } override fun convertResult(method: Method?, res: Any?): Any? { method ?: return null val desiredType = method.returnType if (desiredType == Void.TYPE) return null return Context.jsToJava(res, desiredType) } } } }