blob: 2c3e433ee4da537db7217a42ee4061d772a1d0f0 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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-lang.org/">Groovy</a> scripting language.
* <p>
* It's inspired from the Jython engine
*/
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 static String convertToValidJavaClassname(String inName) {
if (inName == null) return "_";
if (inName.startsWith("scriptdef_")) inName = inName.substring(10);
if (inName.isEmpty()) return "_";
StringBuilder output = new StringBuilder(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);
}
}