Skip to content

Commit

Permalink
JSR-223 support added directly into dynjs.jar.
Browse files Browse the repository at this point in the history
  • Loading branch information
bobmcwhirter committed Oct 3, 2014
1 parent b250c9d commit f8cc6c1
Show file tree
Hide file tree
Showing 10 changed files with 658 additions and 34 deletions.
169 changes: 169 additions & 0 deletions src/main/java/org/dynjs/jsr223/DynJSScriptContext.java
@@ -0,0 +1,169 @@
package org.dynjs.jsr223;

import org.dynjs.Config;
import org.dynjs.runtime.DynJS;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.SimpleBindings;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* @author Bob McWhirter
*/
public class DynJSScriptContext implements ScriptContext {

private final static List<Integer> SCOPES;

static {
SCOPES = Collections.unmodifiableList(new ArrayList<Integer>() {{
add( ScriptContext.ENGINE_SCOPE );
add( ScriptContext.GLOBAL_SCOPE );
}});
}

private final DynJSScriptEngine engine;
private final ScriptEngineGlobalObject global;
private Writer writer;
private Writer errorWriter;
private Reader reader;

public DynJSScriptContext(DynJSScriptEngine engine) {
this.engine = engine;
this.writer = new OutputStreamWriter(System.out);
this.errorWriter = new OutputStreamWriter(System.err);
this.reader = new InputStreamReader(System.in);

this.global = new ScriptEngineGlobalObject( this );
}

ScriptEngineGlobalObject getGlobalObject() {
return this.global;
}

DynJSScriptEngine getEngine() {
return engine;
}

@Override
public void setBindings(Bindings bindings, int scope) {
if (scope == ScriptContext.GLOBAL_SCOPE) {
this.engine.getFactory().setGlobalBindings(bindings);
return;
} else if (scope == ScriptContext.ENGINE_SCOPE) {
this.global.setBindings( bindings );
return;
}

throw new IllegalArgumentException("Invalid scope: " + scope);
}

@Override
public Bindings getBindings(int scope) {
if (scope == ScriptContext.GLOBAL_SCOPE) {
return this.engine.getFactory().getGlobalBindings();
} else if (scope == ScriptContext.ENGINE_SCOPE) {
return this.global.getBindings();
}

throw new IllegalArgumentException("Invalid scope: " + scope);
}

@Override
public void setAttribute(String name, Object value, int scope) {
if (scope == ScriptContext.GLOBAL_SCOPE) {
this.engine.getFactory().getGlobalBindings().put(name, value);
return;
} else if (scope == ScriptContext.ENGINE_SCOPE) {
this.global.getBindings().put(name, value);
return;
}

throw new IllegalArgumentException("Invalid scope: " + scope);
}

@Override
public Object getAttribute(String name, int scope) {
if (scope == ScriptContext.GLOBAL_SCOPE) {
return this.engine.getFactory().getGlobalBindings().get(name);
} else if (scope == ScriptContext.ENGINE_SCOPE) {
return this.global.getBindings().get(name);
}
throw new IllegalArgumentException("Invalid scope: " + scope);
}

@Override
public Object removeAttribute(String name, int scope) {
if (scope == ScriptContext.GLOBAL_SCOPE) {
return this.engine.getFactory().getGlobalBindings().remove(name);
} else if (scope == ScriptContext.ENGINE_SCOPE) {
return this.global.getBindings().remove(name);
}

throw new IllegalArgumentException("Invalid scope: " + scope);
}

@Override
public Object getAttribute(String name) {
Object value = getAttribute(name, ScriptContext.ENGINE_SCOPE);
if (value == null) {
value = getAttribute(name, ScriptContext.GLOBAL_SCOPE);
}
return value;
}

@Override
public int getAttributesScope(String name) {
if (getAttribute(name, ScriptContext.ENGINE_SCOPE) != null) {
return ScriptContext.ENGINE_SCOPE;
}

if (getAttribute(name, ScriptContext.GLOBAL_SCOPE) != null) {
return ScriptContext.GLOBAL_SCOPE;
}

return -1;
}

@Override
public Writer getWriter() {
return this.writer;
}

@Override
public Writer getErrorWriter() {
return this.errorWriter;
}

@Override
public void setWriter(Writer writer) {
this.writer = writer;
}

@Override
public void setErrorWriter(Writer writer) {
this.errorWriter = writer;
}

@Override
public Reader getReader() {
return this.reader;
}

@Override
public void setReader(Reader reader) {
this.reader = reader;
}

@Override
public List<Integer> getScopes() {
return SCOPES;
}
}
159 changes: 159 additions & 0 deletions src/main/java/org/dynjs/jsr223/DynJSScriptEngine.java
@@ -0,0 +1,159 @@
package org.dynjs.jsr223;

import org.dynjs.Config;
import org.dynjs.runtime.DynJS;
import org.dynjs.runtime.Types;
import org.dynjs.runtime.builtins.DynJSBuiltin;

import javax.script.*;
import java.io.Reader;

/**
* @author Bob McWhirter
*/
public class DynJSScriptEngine implements ScriptEngine {

private final DynJSScriptEngineFactory factory;
private DynJSScriptContext context;

public DynJSScriptEngine(DynJSScriptEngineFactory factory) {
this.factory = factory;
this.context = new DynJSScriptContext(this);
}

@Override
public Object eval(String script, ScriptContext context) throws ScriptException {
return eval( script, context, null );
}

@Override
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
return eval( reader, context, null );
}

@Override
public Object eval(String script) throws ScriptException {
return eval( script, this.context, null );
}

@Override
public Object eval(Reader reader) throws ScriptException {
return eval( reader, this.context, null );
}

@Override
public Object eval(String script, Bindings n) throws ScriptException {
return eval( script, this.context, n );
}

@Override
public Object eval(Reader reader, Bindings n) throws ScriptException {
return eval( reader, this.context, n );
}

protected Object eval(String script, ScriptContext context, Bindings bindings) throws ScriptException {
if ( ! ( context instanceof DynJSScriptContext ) ) {
throw new IllegalArgumentException( "context must be an instance of " + DynJSScriptContext.class.getName() );
}

DynJSScriptContext dynjsContext = (DynJSScriptContext) context;
ScriptEngineGlobalObject global = getGlobalObject(dynjsContext, bindings);
DynJS runtime = getRuntime( global, dynjsContext );

try {
return runtime.newRunner().withSource(script).execute();
} catch (Exception t) {
throw new ScriptException(t);
}
}

protected Object eval(Reader reader, ScriptContext context, Bindings bindings) throws ScriptException {
if ( ! ( context instanceof DynJSScriptContext ) ) {
throw new IllegalArgumentException( "context must be an instance of " + DynJSScriptContext.class.getName() );
}

DynJSScriptContext dynjsContext = (DynJSScriptContext) context;
ScriptEngineGlobalObject global = getGlobalObject(dynjsContext, bindings);
DynJS runtime = getRuntime( global, dynjsContext );

try {
return runtime.newRunner().withSource(reader).execute();
} catch (Exception t) {
throw new ScriptException(t);
}
}

private ScriptEngineGlobalObject getGlobalObject(DynJSScriptContext context, Bindings localBindings) {
if ( localBindings == null ) {
return context.getGlobalObject();
}

return new ScriptEngineGlobalObject( context.getGlobalObject(), localBindings );
}

private DynJS getRuntime(ScriptEngineGlobalObject global, DynJSScriptContext context) {
Object builtin = global.get(null, "dynjs");

DynJS runtime = null;

if ( builtin != Types.UNDEFINED ) {
runtime = ((DynJSBuiltin) builtin).getRuntime();
}

runtime = new DynJS( new Config(), global );

Object argv = context.getAttribute( ScriptEngine.ARGV );
if ( argv != null ) {
if ( ! argv.getClass().isArray() ) {
throw new IllegalArgumentException( "ARGV must be an array" );
}
runtime.getConfig().setArgv((Object[]) argv);
}

return runtime;
}

@Override
public void put(String key, Object value) {
getBindings( ScriptContext.ENGINE_SCOPE ).put( key, value );
}

@Override
public Object get(String key) {
return getBindings( ScriptContext.ENGINE_SCOPE ).get( key );
}

@Override
public Bindings getBindings(int scope) {
return this.context.getBindings( scope );
}

@Override
public void setBindings(Bindings bindings, int scope) {
this.context.setBindings( bindings, scope );
}

@Override
public Bindings createBindings() {
return new SimpleBindings();
}

@Override
public ScriptContext getContext() {
return this.context;
}

@Override
public void setContext(ScriptContext context) {
if ( ! ( context instanceof DynJSScriptContext ) ) {
throw new IllegalArgumentException( "Context must be " + DynJSScriptContext.class.getName() );
}
this.context = (DynJSScriptContext) context;
}

@Override
public DynJSScriptEngineFactory getFactory() {
return this.factory;
}

}

0 comments on commit f8cc6c1

Please sign in to comment.