/*
Copyright (c) 2003 eInnovation Inc. All rights reserved
This library is free software; you can redistribute it and/or modify it under the terms
of the GNU Lesser General Public License as published by the Free Software Foundation;
either version 2.1 of the License, or (at your option) any later version.
This library 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 Lesser General Public License for more details.
*/
package com.openedit.entermedia.scripts;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeJavaObject;
import org.mozilla.javascript.Scriptable;
import com.openedit.OpenEditException;
/**
* This implementation of {@link ScriptRunner} uses Mozilla's Rhino JavaScript engine.
*
* @author Eric Galluzzo
*/
public class RhinoScriptRunner implements ScriptRunner
{
private static final Log LOGGER = LogFactory.getLog(RhinoScriptRunner.class);
protected Scriptable fieldGlobalScope;
/**
* ScriptRunner constructor comment.
*
* @param inScripts DOCUMENT ME!
*/
public RhinoScriptRunner()
{
}
/**
* @see ScriptRunner#execFunction(String, Object[])
public Object execFunction(String inFuncName, Object[] inParameters)
throws OpenEditException
{
try
{
Context context = Context.enter();
// See comment above about the context class loader.
ClassLoader loader = getClass().getClassLoader();
if( loader == null)
{
loader = ClassLoader.getSystemClassLoader();
}
Thread.currentThread().setContextClassLoader(loader);
Object function = getScope().get(inFuncName, getScope());
if (function instanceof Function)
{
LOGGER.debug(
"Evaluating the " + inFuncName + "() function on " +
getScript().getDescription());
Object result = ((Function) function).call(context, getScope(), null, inParameters);
return unmarshal(result);
}
else
{
LOGGER.debug(
"No " + inFuncName + "() function found on " + getScript().getDescription() +
", was " + function.toString());
}
}
catch (Exception e)
{
LOGGER.error("execFunction(): Error during " + inFuncName + "(): " + e.getMessage());
//e.printStackTrace();
throw new OpenEditException(e);
}
finally
{
Context.exit();
}
return null;
}
*/
protected String makeStringFromCode(String inCode)
{
if ((inCode.indexOf('"') < 0) && (inCode.indexOf('\\') < 0))
{
return "\"" + inCode + "\"";
}
StringBuffer sb = new StringBuffer('"');
for (int i = 0; i < inCode.length(); i++)
{
char c = inCode.charAt(i);
switch (c)
{
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
default:
sb.append(c);
break;
}
}
sb.append('"');
return sb.toString();
}
/**
* Unmarshal the given JavaScript object into a Java object.
*
* @param inObj The JavaScript object
*
* @return The Java object
*/
protected Object unmarshal(Object inObj)
{
if (inObj instanceof NativeJavaObject)
{
return ((NativeJavaObject) inObj).unwrap();
}
if (inObj instanceof NativeArray)
{
NativeArray array = (NativeArray) inObj;
Object[] result = new Object[(int) array.jsGet_length()];
for (int i = 0; i < array.jsGet_length(); i++)
{
result[i] = unmarshal(array.get(i, null));
}
return result;
}
return inObj;
}
@Override
public Object exec(Script inScript, Map inContext) throws OpenEditException
{
// TODO Auto-generated method stub
// Run the main script, which contains the calculate() (and
// possibly init() ) function definitions.
try
{
// We need to set the context class loader so that Rhino's
// DefiningClassLoader picks it up. In reality, we should
// probably set this elsewhere (i.e. where we create the
// thread), but we don't really need to right now.
Context context = Context.enter();
// if (Thread.currentThread().getContextClassLoader() != getClass().getClassLoader())
// {
// //setInitialized(true);
// Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
// context.setOptimizationLevel(-1);
// }
Scriptable scope = createScope();
if (inContext != null)
{
for (Iterator iter = inContext.keySet().iterator(); iter.hasNext();)
{
String name = (String) iter.next();
Object bean = inContext.get(name);
scope.put(name, scope, Context.toObject(bean, scope));
//runner.declareBean((String) element, );
}
}
Object returned = context.evaluateString(
scope, inScript.getScriptText(), inScript.getDescription(),
inScript.getStartLineNumber(), null);
return returned;
//LOGGER.info( "Javascript optimization level: " + context.getOptimizationLevel() );
}
catch (Exception e)
{
LOGGER.error("init(): " + e.getMessage());
// LOGGER.error(bse);
throw new OpenEditException(e);
}
finally
{
Context.exit();
}
}
public Scriptable getGlobalScope()
{
if( fieldGlobalScope == null)
{
try
{
Context context = Context.enter();
fieldGlobalScope = new ImporterTopLevel(context);
}
catch (Exception e)
{
throw new OpenEditException(e);
}
finally
{
Context.exit();
}
}
return fieldGlobalScope;
}
public Scriptable createScope()
{
try
{
Context context = Context.enter();
Scriptable scope = context.newObject(getGlobalScope());
scope.setPrototype(getGlobalScope());
scope.setParentScope(null);
return scope;
}
catch (Exception e)
{
throw new OpenEditException(e);
}
finally
{
Context.exit();
}
}
}