package org.jruby.embed.jsr223;
import java.io.Reader;
import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptException;
import javax.script.SimpleBindings;
import javax.script.SimpleScriptContext;
import org.jruby.embed.EmbedEvalUnit;
import org.jruby.embed.ScriptingContainer;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;
public class JRubyEngine implements Compilable, Invocable, ScriptEngine {
final ScriptingContainer container;
private JRubyEngineFactory factory;
private ScriptContext context;
JRubyEngine(ScriptingContainer container, JRubyEngineFactory factory) {
this.container = container;
this.factory = factory;
this.context = new JRubyContext(container);
}
public CompiledScript compile(String script) throws ScriptException {
if (script == null) {
throw new NullPointerException("script is null");
}
return new JRubyCompiledScript(container, this, script);
}
public CompiledScript compile(Reader reader) throws ScriptException {
if (reader == null) {
throw new NullPointerException("reader is null");
}
return new JRubyCompiledScript(container, this, reader);
}
public Object eval(String script, ScriptContext context) throws ScriptException {
if (script == null || context == null) {
throw new NullPointerException("either script or context is null");
}
container.setScriptFilename(Utils.getFilename(context));
try {
if (Utils.isClearVariablesOn(context)) {
container.clear();
}
Utils.preEval(container, context);
EmbedEvalUnit unit = container.parse(script, Utils.getLineNumber(context));
IRubyObject ret = unit.run();
return JavaEmbedUtils.rubyToJava(ret);
} catch (Exception e) {
throw wrapException(e);
} finally {
Utils.postEval(container, context);
boolean termination = Utils.isTerminationOn(context);
if (termination) {
container.terminate();
}
}
}
private ScriptException wrapException(Exception e) {
return new ScriptException(e);
}
public Object eval(Reader reader, ScriptContext context) throws ScriptException {
if (reader == null || context == null) {
throw new NullPointerException("either reader or context is null");
}
String filename = Utils.getFilename(context);
try {
if (Utils.isClearVariablesOn(context)) {
container.clear();
}
Utils.preEval(container, context);
EmbedEvalUnit unit = container.parse(reader, filename, Utils.getLineNumber(context));
IRubyObject ret = unit.run();
return JavaEmbedUtils.rubyToJava(ret);
} catch (Exception e) {
throw wrapException(e);
} finally {
Utils.postEval(container, context);
boolean termination = Utils.isTerminationOn(context);
if (termination) {
container.terminate();
}
}
}
public Object eval(String script, Bindings bindings) throws ScriptException {
ScriptContext context = getScriptContext(bindings);
return eval(script, context);
}
public Object eval(Reader reader, Bindings bindings) throws ScriptException {
ScriptContext context = getScriptContext(bindings);
return eval(reader, context);
}
public Object eval(String script) throws ScriptException {
return eval(script, context);
}
public Object eval(Reader reader) throws ScriptException {
return eval(reader, context);
}
protected ScriptContext getScriptContext(Bindings bindings) {
if (bindings == null) {
throw new NullPointerException("null bindings in engine scope");
}
ScriptContext newContext = new SimpleScriptContext();
newContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
Bindings global = getBindings(ScriptContext.GLOBAL_SCOPE);
if (global != null) {
newContext.setBindings(global, ScriptContext.GLOBAL_SCOPE);
}
newContext.setReader(context.getReader());
newContext.setWriter(context.getWriter());
newContext.setErrorWriter(context.getErrorWriter());
return newContext;
}
public Object get(String key) {
return context.getAttribute(key, ScriptContext.ENGINE_SCOPE);
}
public void put(String key, Object value) {
context.getBindings(ScriptContext.ENGINE_SCOPE).put(key, value);
}
public Bindings getBindings(int scope) {
return context.getBindings(scope);
}
public void setBindings(Bindings bindings, int scope) {
context.setBindings(bindings, scope);
}
public Bindings createBindings() {
return new SimpleBindings();
}
public ScriptContext getContext() {
return context;
}
public void setContext(ScriptContext ctx) {
if (ctx == null) {
throw new NullPointerException("context is null");
}
context = ctx;
}
public ScriptEngineFactory getFactory() {
return factory;
}
public Object invokeMethod(Object receiver, String method, Object... args)
throws ScriptException, NoSuchMethodException {
if (method == null) {
throw new NullPointerException("method is null");
}
if (receiver == null) {
throw new NullPointerException("receiver is null");
}
try {
Utils.preEval(container, context);
if (args == null || args.length == 0) {
return container.callMethod(receiver, method, Object.class);
}
return container.callMethod(receiver, method, args, Object.class);
} catch (Exception e) {
if (e.getCause() != null && e.getCause().getMessage() != null
&& e.getCause().getMessage().contains("undefined method")) {
throw wrapMethodException(e);
}
throw wrapException(e);
} finally {
Utils.postEval(container, context);
}
}
private static NoSuchMethodException wrapMethodException(Exception e) {
return (NoSuchMethodException) new NoSuchMethodException(e.getCause().getMessage()).initCause(e);
}
public Object invokeFunction(String method, Object... args)
throws ScriptException, NoSuchMethodException {
if (method == null) {
throw new NullPointerException("method is null");
}
try {
Utils.preEval(container, context);
if (args == null || args.length == 0) {
return container.callMethod(container.getProvider().getRuntime().getTopSelf(), method, Object.class);
}
return container.callMethod(container.getProvider().getRuntime().getTopSelf(), method, args, Object.class);
} catch (Exception e) {
if (e.getCause() != null && e.getCause().getMessage() != null
&& e.getCause().getMessage().contains("undefined method")) {
throw wrapMethodException(e);
}
throw wrapException(e);
} finally {
Utils.postEval(container, context);
}
}
public <T> T getInterface(Class<T> returnType) {
return getInterface(null, returnType);
}
public <T> T getInterface(Object receiver, Class<T> returnType) {
return container.getInstance(receiver, returnType);
}
}