package org.jactr.scripting.javascript;
/*
* default logging
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.model.IModel;
import org.jactr.core.production.CannotInstantiateException;
import org.jactr.core.production.IInstantiation;
import org.jactr.core.production.VariableBindings;
import org.jactr.core.utils.ModelerException;
import org.jactr.scripting.IScriptableFactory;
import org.jactr.scripting.ScriptSupport;
import org.jactr.scripting.ScriptingManager;
import org.jactr.scripting.action.IActionScript;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.WrappedException;
public class JavascriptAction implements IActionScript
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(JavascriptAction.class);
private final IScriptableFactory _factory;
private final String _script;
private final Script _compiledScript;
public JavascriptAction(String script, IScriptableFactory factory)
{
_script = script;
_factory = factory;
ScopeManager.getPublicScope();
Context cx = Context.enter();
try
{
_compiledScript = cx.compileString(_script, "ScriptableAction", 0, null);
}
catch (Exception ioe)
{
LOGGER.error("Could not compile script: " + _script);
throw new ModelerException("Error in Scriptable IAction", ioe,
"double check your sytanx. The script parser detected an error");
}
finally
{
Context.exit();
}
}
private JavascriptAction(String script, Script compiled,
IScriptableFactory factory)
{
_script = script;
_compiledScript = compiled;
_factory = factory;
}
public IActionScript bind(VariableBindings variableBindings)
throws CannotInstantiateException
{
// recycle
return new JavascriptAction(_script, _compiledScript, _factory);
}
public void dispose()
{
// noop since we recycle
}
public double fire(ScriptSupport scriptSupport, IInstantiation instantiation,
double firedAt)
{
IModel model = instantiation.getModel();
// enter the context for the thread and get the shared scope for
// the model..
Context cx = Context.enter();
Scriptable scope = ScopeManager.newScope(ScopeManager
.getScopeForModel(model));
ScopeManager.defineVariable(scope, "jactr", scriptSupport);
ScriptingManager.configureScripting(_factory, model, scriptSupport, scope);
try
{
_compiledScript.exec(cx, scope);
}
catch (JavaScriptException jse)
{
Context.exit();
LOGGER.error("Error in scriptable condition", jse);
throw new ModelerException("Error in Scriptable IAction", jse,
"double check your sytanx in " + instantiation
+ ". The script was unable to be run..");
}
// let's get the function fire(model, prod, bindings)
Object fire = ScriptableObject.getProperty(scope, "fire");
if (!(fire instanceof Function))
{
Context.exit();
throw new ModelerException("Could not find fire() in script", null,
"ScriptableActions must defined function fire(instantiation)");
}
// and fire that beatch
double fireTime = 0;
try
{
Object[] args = {};
Object result = ((Function) fire).call(cx, scope, scope, args);
fireTime = Context.toNumber(result);
return fireTime;
}
catch (WrappedException we)
{
Throwable cause = we.getWrappedException();
if (cause instanceof RuntimeException) throw (RuntimeException) cause;
throw new RuntimeException(cause);
}
catch (JavaScriptException jse2)
{
LOGGER.error("Error in scriptable action", jse2);
throw new ModelerException(
"Error in Scriptable IAction",
jse2,
"double check your sytanx in "
+ instantiation
+ ". Scripting failed to execute fire(model, production, bindings)");
}
finally
{
Context.exit();
}
}
public IScriptableFactory getFactory()
{
return _factory;
}
public String getScript()
{
return _script;
}
}