blob: 6fa76e0a3b18534634d24fa937cfeecce510568f [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.groovy.bsf;
import groovy.lang.Closure;
import groovy.lang.GroovyShell;
import org.apache.bsf.BSFDeclaredBean;
import org.apache.bsf.BSFException;
import org.apache.bsf.BSFManager;
import org.apache.bsf.util.BSFEngineImpl;
import org.apache.bsf.util.BSFFunctions;
import org.codehaus.groovy.runtime.InvokerHelper;
import java.util.Vector;
/**
* A BSF Engine for the <a href="http://groovy.codehaus.org/">Groovy</a>
* scripting language.
* <p/>
* It's derived from the Jython / JPython engine
*
* @author James Strachan
*/
public class GroovyEngine extends BSFEngineImpl {
protected GroovyShell shell;
/*
* Convert a non java class name to a java classname
* This is used to convert a script name to a name
* that can be used as a classname with the script is
* loaded in GroovyClassloader#load()
* The method simply replaces any invalid characters
* with "_".
*/
private String convertToValidJavaClassname(String inName) {
if (inName == null || inName.equals("")) {
return "_";
}
StringBuffer output = new StringBuffer(inName.length());
boolean firstChar = true;
for (int i = 0; i < inName.length(); ++i) {
char ch = inName.charAt(i);
if (firstChar && !Character.isJavaIdentifierStart(ch)) {
ch = '_';
} else if (!firstChar
&& !(Character.isJavaIdentifierPart(ch) || ch == '.')) {
ch = '_';
}
firstChar = (ch == '.');
output.append(ch);
}
return output.toString();
}
/**
* Allow an anonymous function to be declared and invoked
*/
public Object apply(String source, int lineNo, int columnNo, Object funcBody, Vector paramNames,
Vector arguments) throws BSFException {
Object object = eval(source, lineNo, columnNo, funcBody);
if (object instanceof Closure) {
// lets call the function
Closure closure = (Closure) object;
return closure.call(arguments.toArray());
}
return object;
}
/**
* Call the named method of the given object.
*/
public Object call(Object object, String method, Object[] args) throws BSFException {
return InvokerHelper.invokeMethod(object, method, args);
}
/**
* Evaluate an expression.
*/
public Object eval(String source, int lineNo, int columnNo, Object script) throws BSFException {
try {
source = convertToValidJavaClassname(source);
return getEvalShell().evaluate(script.toString(), source);
} catch (Exception e) {
throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
}
}
/**
* Execute a script.
*/
public void exec(String source, int lineNo, int columnNo, Object script) throws BSFException {
try {
// use evaluate to pass in the BSF variables
source = convertToValidJavaClassname(source);
getEvalShell().evaluate(script.toString(), source);
} catch (Exception e) {
throw new BSFException(BSFException.REASON_EXECUTION_ERROR, "exception from Groovy: " + e, e);
}
}
/**
* Initialize the engine.
*/
public void initialize(BSFManager mgr, String lang, Vector declaredBeans) throws BSFException {
super.initialize(mgr, lang, declaredBeans);
// create a shell
shell = new GroovyShell(mgr.getClassLoader());
// register the mgr with object name "bsf"
shell.setVariable("bsf", new BSFFunctions(mgr, this));
int size = declaredBeans.size();
for (int i = 0; i < size; i++) {
declareBean((BSFDeclaredBean) declaredBeans.elementAt(i));
}
}
/**
* Declare a bean
*/
public void declareBean(BSFDeclaredBean bean) throws BSFException {
shell.setVariable(bean.name, bean.bean);
}
/**
* Undeclare a previously declared bean.
*/
public void undeclareBean(BSFDeclaredBean bean) throws BSFException {
shell.setVariable(bean.name, null);
}
/**
* @return a newly created GroovyShell using the same variable scope but a new class loader
*/
protected GroovyShell getEvalShell() {
return new GroovyShell(shell);
}
}