下面列出了怎么用javax.script.ScriptContext的API类实例代码及写法,或者点击链接到github查看源代码。
@Test
/**
* Check that we can call invokeMethod on an object that we got by
* evaluating script with different Context set.
*/
public void invokeMethodDifferentContextTest() {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
try {
// define an object with method on it
final Object obj = e.eval("({ hello: function() { return 'Hello World!'; } })");
final ScriptContext ctxt = new SimpleScriptContext();
ctxt.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
e.setContext(ctxt);
// invoke 'func' on obj - but with current script context changed
final Object res = ((Invocable) e).invokeMethod(obj, "hello");
assertEquals(res, "Hello World!");
} catch (final Exception exp) {
exp.printStackTrace();
fail(exp.getMessage());
}
}
@Test
public void invokeFunctionInGlobalScopeTest() throws Exception {
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
final ScriptContext ctxt = engine.getContext();
// define a function called "func"
engine.eval("func = function() { return 42 }");
// move ENGINE_SCOPE Bindings to GLOBAL_SCOPE
ctxt.setBindings(ctxt.getBindings(ScriptContext.ENGINE_SCOPE), ScriptContext.GLOBAL_SCOPE);
// create a new Bindings and set as ENGINE_SCOPE
ctxt.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
// define new function that calls "func" now in GLOBAL_SCOPE
engine.eval("newfunc = function() { return func() }");
// call "newfunc" and check the return value
Object value = ((Invocable)engine).invokeFunction("newfunc");
assertTrue(((Number)value).intValue() == 42);
}
private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final ScriptObject ctxtGlobal) throws ScriptException {
if (script == null) {
return null;
}
final ScriptObject oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != ctxtGlobal);
try {
if (globalChanged) {
Context.setGlobal(ctxtGlobal);
}
// set ScriptContext variables if ctxt is non-null
if (ctxt != null) {
setContextVariables(ctxtGlobal, ctxt);
}
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} catch (final Exception e) {
throwAsScriptException(e);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {
Context.setGlobal(oldGlobal);
}
}
}
/**
* Evaluate a function against a write lock on the graph with commits or
* rollbacks handled automatically.
* <p>
* Note: This method will only work for Python scripts as it makes use of
* Python specific syntax.
*
* @param callback the function to evaluate.
* @throws ScriptException
* @throws InterruptedException
*/
public void withWritableGraph(final Object callback) throws ScriptException, InterruptedException {
final SWritableGraph writableGraph = writableGraph("Scripting View Context Manager");
LOGGER.log(Level.INFO, "creating context for {0}", writableGraph);
boolean ok = false;
try {
final ScriptContext context = engine.getContext();
context.setAttribute("__func", callback, ScriptContext.ENGINE_SCOPE);
context.setAttribute("__p1", writableGraph, ScriptContext.ENGINE_SCOPE);
engine.eval("__func(__p1)");
ok = true;
} catch (ScriptException ex) {
LOGGER.log(Level.WARNING, "exception in context: {0}", ex.toString());
writableGraph.rollback();
throw ex;
} finally {
LOGGER.log(Level.WARNING, "context successful = {0}", ok);
if (ok) {
writableGraph.commit();
LOGGER.log(Level.WARNING, "commiting {0}", writableGraph);
}
}
}
private Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
final Global oldGlobal = Context.getGlobal();
final boolean globalChanged = (oldGlobal != ctxtGlobal);
try {
if (globalChanged) {
Context.setGlobal(ctxtGlobal);
}
final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
ctxtGlobal.setScriptContext(ctxt);
try {
return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
} finally {
ctxtGlobal.setScriptContext(oldCtxt);
}
} catch (final Exception e) {
throwAsScriptException(e, ctxtGlobal);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {
Context.setGlobal(oldGlobal);
}
}
}
public ScriptMixin( @Structure PolygeneSPI spi,
@This Object thisComposite,
@State StateHolder state,
@Structure Layer layer,
@Structure Module module,
@Structure Application application )
{
descriptor = spi.compositeDescriptorFor( thisComposite );
engine = createNewEngine();
Bindings mixinBindings = engine.getBindings( ScriptContext.ENGINE_SCOPE );
mixinBindings.put( "Polygene", spi );
mixinBindings.put( "application", application );
mixinBindings.put( "layer", layer );
mixinBindings.put( "module", module );
mixinBindings.put( "This", thisComposite );
mixinBindings.put( "state", state );
mixinBindings.put( "objectFactory", module.objectFactory() );
mixinBindings.put( "unitOfWorkFactory", module.unitOfWorkFactory() );
mixinBindings.put( "valueBuilderFactory", module.valueBuilderFactory() );
mixinBindings.put( "transientBuilderFactory", module.transientBuilderFactory() );
mixinBindings.put( "serviceFinder", module.serviceFinder() );
mixinBindings.put( "typeLookup", module.typeLookup() );
}
@Test
public void contextAndBindings() {
ScriptContext context = engine.getContext();
assertThat(context, notNullValue());
assertThat(context, sameInstance(engine.getContext()));
Bindings globalScope = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
assertThat(globalScope, notNullValue());
assertThat(globalScope, sameInstance(engine.getBindings(ScriptContext.GLOBAL_SCOPE)));
assertThat(globalScope, sameInstance(context.getBindings(ScriptContext.GLOBAL_SCOPE)));
assertThat(globalScope, sameInstance(manager.getBindings()));
Bindings engineScope = engine.getBindings(ScriptContext.ENGINE_SCOPE);
assertThat(engineScope, notNullValue());
assertThat(engineScope, sameInstance(engine.getBindings(ScriptContext.ENGINE_SCOPE)));
assertThat(engineScope, sameInstance(context.getBindings(ScriptContext.ENGINE_SCOPE)));
assertThat(engineScope, not(sameInstance(manager.getBindings())));
}
public static void main(final String[] args) throws Exception {
final ScriptEngineManager manager = new ScriptEngineManager();
final ScriptEngine engine = manager.getEngineByName("nashorn");
engine.put("x", "hello");
// print global variable "x"
engine.eval("print(x);");
// the above line prints "hello"
// Now, pass a different script context
final ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
final Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
// add new variable "x" to the new engineScope
engineScope.put("x", "world");
// execute the same script - but this time pass a different script context
engine.eval("print(x);", newContext);
// the above line prints "world"
}
@Test
public void mapScriptObjectMirrorCallsiteTest() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine engine = m.getEngineByName("nashorn");
final String TEST_SCRIPT = "typeof obj.foo";
final Bindings global = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
engine.eval("var obj = java.util.Collections.emptyMap()");
// this will drive callsite "obj.foo" of TEST_SCRIPT
// to use "obj instanceof Map" as it's guard
engine.eval(TEST_SCRIPT, global);
// redefine 'obj' to be a script object
engine.eval("obj = {}");
final Bindings newGlobal = engine.createBindings();
// transfer 'obj' from default global to new global
// new global will get a ScriptObjectMirror wrapping 'obj'
newGlobal.put("obj", global.get("obj"));
// Every ScriptObjectMirror is a Map! If callsite "obj.foo"
// does not see the new 'obj' is a ScriptObjectMirror, it'll
// continue to use Map's get("obj.foo") instead of ScriptObjectMirror's
// getMember("obj.foo") - thereby getting null instead of undefined
assertEquals("undefined", engine.eval(TEST_SCRIPT, newGlobal));
}
@Test
public void userEngineScopeBindingsRetentionTest() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
final ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
e.eval("function foo() {}", newContext);
// definition retained with user's ENGINE_SCOPE Binding
assertTrue(e.eval("typeof foo", newContext).equals("function"));
final Bindings oldBindings = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
// but not in another ENGINE_SCOPE binding
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
assertTrue(e.eval("typeof foo", newContext).equals("undefined"));
// restore ENGINE_SCOPE and check again
newContext.setBindings(oldBindings, ScriptContext.ENGINE_SCOPE);
assertTrue(e.eval("typeof foo", newContext).equals("function"));
}
@Test
public void invokeFunctionWithCustomScriptContextTest() throws Exception {
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
// create an engine and a ScriptContext, but don't set it as default
ScriptContext scriptContext = new SimpleScriptContext();
// Set some value in the context
scriptContext.setAttribute("myString", "foo", ScriptContext.ENGINE_SCOPE);
// Evaluate script with custom context and get back a function
final String script = "function (c) { return myString.indexOf(c); }";
CompiledScript compiledScript = ((Compilable)engine).compile(script);
Object func = compiledScript.eval(scriptContext);
// Invoked function should be able to see context it was evaluated with
Object result = ((Invocable) engine).invokeMethod(func, "call", func, "o", null);
assertTrue(((Number)result).intValue() == 1);
}
@Test
public void globalPerEngineTest() throws ScriptException {
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
final String[] options = new String[] { "--global-per-engine" };
final ScriptEngine e = fac.getScriptEngine(options);
e.eval("function foo() {}");
final ScriptContext newCtx = new SimpleScriptContext();
newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
// all global definitions shared and so 'foo' should be
// visible in new Bindings as well.
assertTrue(e.eval("typeof foo", newCtx).equals("function"));
e.eval("function bar() {}", newCtx);
// bar should be visible in default context
assertTrue(e.eval("typeof bar").equals("function"));
}
@Override
public void setup(OperatorContext context)
{
for (Map.Entry<String, Object> entry : serializableBindings.entrySet()) {
scriptBindings.put(entry.getKey(), entry.getValue());
}
this.scriptContext.setBindings(scriptBindings, ScriptContext.ENGINE_SCOPE);
engine.setContext(this.scriptContext);
try {
for (String s : setupScripts) {
engine.eval(s, this.scriptContext);
}
} catch (ScriptException ex) {
throw new RuntimeException(ex);
}
}
@Test
public void globalPerEngineTest() throws ScriptException {
final NashornScriptEngineFactory fac = new NashornScriptEngineFactory();
final String[] options = new String[] { "--global-per-engine" };
final ScriptEngine e = fac.getScriptEngine(options);
e.eval("function foo() {}");
final ScriptContext newCtx = new SimpleScriptContext();
newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE);
// all global definitions shared and so 'foo' should be
// visible in new Bindings as well.
assertTrue(e.eval("typeof foo", newCtx).equals("function"));
e.eval("function bar() {}", newCtx);
// bar should be visible in default context
assertTrue(e.eval("typeof bar").equals("function"));
}
@Test
public void isolatedBindingsWithContextAndSimpleBindings() throws ScriptException {
ScriptContext context = new SimpleScriptContext();
Bindings binding = new SimpleBindings();
context.setBindings(binding, ScriptContext.ENGINE_SCOPE);
engine.eval("var value = 'Zeta Scorpii'", context);
assertThat(engine.eval("value", context), instanceOfWith(String.class, is("Zeta Scorpii")));
context.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
assertThat(engine.eval("typeof value", context), instanceOfWith(String.class, is("undefined")));
context.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
assertThat(engine.eval("typeof value", context), instanceOfWith(String.class, is("undefined")));
context.setBindings(binding, ScriptContext.ENGINE_SCOPE);
assertThat(engine.eval("value", context), instanceOfWith(String.class, is("Zeta Scorpii")));
}
/**
* Executes a compiled script and returns the result.
*
* @param script Compiled script.
* @param functionName Optional function or method to invoke.
* @param scriptContext Script execution context.
* @return The script result.
* @throws IllegalArgumentException
*/
public static Object executeScript(CompiledScript script, String functionName, ScriptContext scriptContext, Object[] args) throws ScriptException, NoSuchMethodException {
Assert.notNull("script", script, "scriptContext", scriptContext);
Object result = script.eval(scriptContext);
if (UtilValidate.isNotEmpty(functionName)) {
if (Debug.verboseOn()) {
Debug.logVerbose("Invoking function/method " + functionName, module);
}
ScriptEngine engine = script.getEngine();
try {
Invocable invocableEngine = (Invocable) engine;
result = invocableEngine.invokeFunction(functionName, args == null ? EMPTY_ARGS : args);
} catch (ClassCastException e) {
throw new ScriptException("Script engine " + engine.getClass().getName() + " does not support function/method invocations");
}
}
return result;
}
@Test
public void scopeInteractionNewContextSimpleBindingsPropertyAssignment() throws ScriptException {
ScriptContext context = new SimpleScriptContext();
context.setBindings(engine.getBindings(ScriptContext.GLOBAL_SCOPE), ScriptContext.GLOBAL_SCOPE);
context.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
context.setAttribute("value", "Phecda", ScriptContext.ENGINE_SCOPE);
context.setAttribute("value", "Scheat", ScriptContext.GLOBAL_SCOPE);
engine.eval("this.value = 'Aludra'", context);
assertThat(engine.eval("this.value", context), nullValue());
assertThat(engine.eval("value", context), instanceOfWith(String.class, is("Phecda")));
assertThat(context.getAttribute("value", ScriptContext.ENGINE_SCOPE),
instanceOfWith(String.class, is("Phecda")));
assertThat(context.getAttribute("value", ScriptContext.GLOBAL_SCOPE),
instanceOfWith(String.class, is("Scheat")));
}
private String initPassword(Business business, Person person) throws Exception {
String str = Config.person().getPassword();
Pattern pattern = Pattern.compile(com.x.base.core.project.config.Person.REGULAREXPRESSION_SCRIPT);
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
String eval = ScriptFactory.functionalization(StringEscapeUtils.unescapeJson(matcher.group(1)));
ScriptContext scriptContext = new SimpleScriptContext();
Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("person", person);
Object o = ScriptFactory.scriptEngine.eval(eval, scriptContext);
return o.toString();
} else {
return str;
}
}
NashornScriptEngine(final NashornScriptEngineFactory factory, final String[] args, final ClassLoader appLoader) {
this.factory = factory;
final Options options = new Options("nashorn");
options.process(args);
// throw ParseException on first error from script
final ErrorManager errMgr = new Context.ThrowErrorManager();
// create new Nashorn Context
this.nashornContext = AccessController.doPrivileged(new PrivilegedAction<Context>() {
@Override
public Context run() {
try {
return new Context(options, errMgr, appLoader);
} catch (final RuntimeException e) {
if (Context.DEBUG) {
e.printStackTrace();
}
throw e;
}
}
}, CREATE_CONTEXT_ACC_CTXT);
// cache this option that is used often
this._global_per_engine = nashornContext.getEnv()._global_per_engine;
// create new global object
this.global = createNashornGlobal(context);
// set the default ENGINE_SCOPE object for the default context
context.setBindings(new ScriptObjectMirror(global, global), ScriptContext.ENGINE_SCOPE);
}
@SneakyThrows
private void init() {
engine = new ScriptEngineManager().getEngineByName("nashorn");
ctx = new SimpleScriptContext();
ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.eval(new InputStreamReader(getClass().getResourceAsStream("/js/sjcl-1.0.7.js")), ctx);
engine.eval( "function encrypt(pass,data){try{return sjcl.encrypt(pass,data, {mode:'gcm',ks:256,ts:128});}catch(e){return e;}}", ctx);
engine.eval( "function decrypt(pass,data){try{return sjcl.decrypt(pass,data);}catch(e){return e;}}", ctx);
}
@Test
public void userEngineScopeBindingsNoLeakTest() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
final ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
e.eval("function foo() {}", newContext);
// in the default context's ENGINE_SCOPE, 'foo' shouldn't exist
assertTrue(e.eval("typeof foo").equals("undefined"));
}
private void setContextVariables(final ScriptObject ctxtGlobal, final ScriptContext ctxt) {
// set "context" global variable via contextProperty - because this
// property is non-writable
contextProperty.setObjectValue(ctxtGlobal, ctxtGlobal, ctxt, false);
Object args = ScriptObjectMirror.unwrap(ctxt.getAttribute("arguments"), ctxtGlobal);
if (args == null || args == UNDEFINED) {
args = ScriptRuntime.EMPTY_ARRAY;
}
// if no arguments passed, expose it
if (! (args instanceof ScriptObject)) {
args = ((GlobalObject)ctxtGlobal).wrapAsObject(args);
ctxtGlobal.set("arguments", args, false);
}
}
ScriptRunner(final ScriptEngine engine, final ScriptContext context, final String source, final Object expected, final int iterations) {
this.engine = engine;
this.context = context;
this.source = source;
this.expected = expected;
this.iterations = iterations;
}
public static void assertLargeObjectObjectArray(final Object[][] array) throws ScriptException {
assertEquals(4, array.length);
assertTrue(Arrays.equals(new Object[] { Boolean.FALSE }, array[0]));
assertTrue(Arrays.equals(new Object[] { 1 }, array[1]));
assertTrue(Arrays.equals(new Object[] { "foo", 42.3d }, array[2]));
assertEquals(1, array[3].length);
e.getBindings(ScriptContext.ENGINE_SCOPE).put("obj", array[3][0]);
assertEquals(17, e.eval("obj.x"));
}
@Test
public void userEngineScopeBindingsTest() throws ScriptException {
final ScriptEngineManager m = new ScriptEngineManager();
final ScriptEngine e = m.getEngineByName("nashorn");
e.eval("function func() {}");
final ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
// we are using a new bindings - so it should have 'func' defined
final Object value = e.eval("typeof func", newContext);
assertTrue(value.equals("undefined"));
}
protected ClojureScriptEngine(ScriptEngineFactory scriptEngineFactory) {
this.scriptEngineFactory = scriptEngineFactory;
// Set up the engine bindings
Bindings engineScope = getBindings(ScriptContext.ENGINE_SCOPE);
engineScope.put(ENGINE, ENGINE_NAME);
engineScope.put(ENGINE_VERSION, ENGINE_VERSION);
engineScope.put(NAME, ENGINE_NAME);
engineScope.put(LANGUAGE, ENGINE_NAME);
engineScope.put(LANGUAGE_VERSION, ENGINE_VERSION);
}
@Test
public void testScriptContextGetRemoveUndefined() throws Exception {
final ScriptEngineManager manager = new ScriptEngineManager();
final ScriptEngine e = manager.getEngineByName("nashorn");
final ScriptContext ctx = e.getContext();
assertNull(ctx.getAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
assertNull(ctx.removeAttribute("undefinedname", ScriptContext.ENGINE_SCOPE));
}
/**
* Hook to search missing variables in ScriptContext if available
* @param self used to detect if scope call or not (this function is 'strict')
* @param name name of the variable missing
* @return value of the missing variable or undefined (or TypeError for scope search)
*/
public static Object __noSuchProperty__(final Object self, final Object name) {
final Global global = Global.instance();
final ScriptContext sctxt = global.currentContext();
final String nameStr = name.toString();
if (sctxt != null) {
final int scope = sctxt.getAttributesScope(nameStr);
if (scope != -1) {
return ScriptObjectMirror.unwrap(sctxt.getAttribute(nameStr, scope), global);
}
}
if ("context".equals(nameStr)) {
return sctxt;
} else if ("engine".equals(nameStr)) {
// expose "engine" variable only when there is no security manager
// or when no class filter is set.
if (System.getSecurityManager() == null || global.getClassFilter() == null) {
return global.engine;
}
}
if (self == UNDEFINED) {
// scope access and so throw ReferenceError
throw referenceError(global, "not.defined", nameStr);
}
return UNDEFINED;
}
@Test
public void testConsStringFlattening() throws ScriptException {
final Bindings b = e.getBindings(ScriptContext.ENGINE_SCOPE);
final Map<Object, Object> m = new HashMap<>();
b.put("m", m);
e.eval("var x = 'f'; x += 'oo'; var y = 'b'; y += 'ar'; m.put(x, y)");
assertEquals("bar", m.get("foo"));
}
private CompiledScript asCompiledScript(final Source source) throws ScriptException {
final Context.MultiGlobalCompiledScript mgcs;
final ScriptFunction func;
final Global oldGlobal = Context.getGlobal();
final Global newGlobal = getNashornGlobalFrom(context);
final boolean globalChanged = (oldGlobal != newGlobal);
try {
if (globalChanged) {
Context.setGlobal(newGlobal);
}
mgcs = nashornContext.compileScript(source);
func = mgcs.getFunction(newGlobal);
} catch (final Exception e) {
throwAsScriptException(e, newGlobal);
throw new AssertionError("should not reach here");
} finally {
if (globalChanged) {
Context.setGlobal(oldGlobal);
}
}
return new CompiledScript() {
@Override
public Object eval(final ScriptContext ctxt) throws ScriptException {
final Global globalObject = getNashornGlobalFrom(ctxt);
// Are we running the script in the same global in which it was compiled?
if (func.getScope() == globalObject) {
return evalImpl(func, ctxt, globalObject);
}
// different global
return evalImpl(mgcs, ctxt, globalObject);
}
@Override
public ScriptEngine getEngine() {
return NashornScriptEngine.this;
}
};
}