Browse Source
Including ScriptEvaluator implementations for JSR-223, Groovy and BeanShell. BeanShell consistently receives the bean ClassLoader now. Also revised ScriptFactory and its implementations for varargs. Issue: SPR-11007pull/393/merge
21 changed files with 629 additions and 110 deletions
@ -0,0 +1,54 @@
@@ -0,0 +1,54 @@
|
||||
/* |
||||
* Copyright 2002-2013 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.springframework.scripting; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Spring's strategy interface for evaluating a script. |
||||
* |
||||
* <p>Aside from language-specific implementations, Spring also ships |
||||
* a version based on the standard {@code javax.script} package (JSR-223): |
||||
* {@link org.springframework.scripting.support.StandardScriptEvaluator}. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @author Costin Leau |
||||
* @since 4.0 |
||||
*/ |
||||
public interface ScriptEvaluator { |
||||
|
||||
/** |
||||
* Evaluate the given script. |
||||
* @param script the ScriptSource for the script to evaluate |
||||
* @return the return value of the script, if any |
||||
* @throws ScriptCompilationException if the evaluator failed to read, |
||||
* compile or evaluate the script |
||||
*/ |
||||
Object evaluate(ScriptSource script) throws ScriptCompilationException; |
||||
|
||||
/** |
||||
* Evaluate the given script with the given arguments. |
||||
* @param script the ScriptSource for the script to evaluate |
||||
* @param arguments the key-value pairs to expose to the script, |
||||
* typically as script variables. May be {@code null}. |
||||
* @return the return value of the script, if any |
||||
* @throws ScriptCompilationException if the evaluator failed to read, |
||||
* compile or evaluate the script |
||||
*/ |
||||
Object evaluate(ScriptSource script, Map<String, Object> arguments) throws ScriptCompilationException; |
||||
|
||||
} |
||||
@ -0,0 +1,89 @@
@@ -0,0 +1,89 @@
|
||||
/* |
||||
* Copyright 2002-2013 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.springframework.scripting.bsh; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.StringReader; |
||||
import java.util.Map; |
||||
|
||||
import bsh.EvalError; |
||||
import bsh.Interpreter; |
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware; |
||||
import org.springframework.scripting.ScriptCompilationException; |
||||
import org.springframework.scripting.ScriptEvaluator; |
||||
import org.springframework.scripting.ScriptSource; |
||||
|
||||
/** |
||||
* BeanShell-based implementation of Spring's {@link ScriptEvaluator} strategy interface. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 4.0 |
||||
* @see Interpreter#eval(String) |
||||
*/ |
||||
public class BshScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { |
||||
|
||||
private ClassLoader classLoader; |
||||
|
||||
|
||||
/** |
||||
* Construct a new BshScriptEvaluator. |
||||
*/ |
||||
public BshScriptEvaluator() { |
||||
} |
||||
|
||||
/** |
||||
* Construct a new BshScriptEvaluator. |
||||
* @param classLoader the ClassLoader to use for the {@link Interpreter} |
||||
*/ |
||||
public BshScriptEvaluator(ClassLoader classLoader) { |
||||
this.classLoader = classLoader; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setBeanClassLoader(ClassLoader classLoader) { |
||||
this.classLoader = classLoader; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script) { |
||||
return evaluate(script, null); |
||||
} |
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script, Map<String, Object> arguments) { |
||||
try { |
||||
Interpreter interpreter = new Interpreter(); |
||||
interpreter.setClassLoader(this.classLoader); |
||||
if (arguments != null) { |
||||
for (Map.Entry<String, Object> entry : arguments.entrySet()) { |
||||
interpreter.set(entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
return interpreter.eval(new StringReader(script.getScriptAsString())); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new ScriptCompilationException(script, "Cannot access script", ex); |
||||
} |
||||
catch (EvalError ex) { |
||||
throw new ScriptCompilationException(script, "Evaluation failure", ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,76 @@
@@ -0,0 +1,76 @@
|
||||
package org.springframework.scripting.groovy; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Collections; |
||||
import java.util.Map; |
||||
|
||||
import groovy.lang.Binding; |
||||
import groovy.lang.GroovyShell; |
||||
import org.codehaus.groovy.control.CompilationFailedException; |
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware; |
||||
import org.springframework.scripting.ScriptCompilationException; |
||||
import org.springframework.scripting.ScriptEvaluator; |
||||
import org.springframework.scripting.ScriptSource; |
||||
import org.springframework.scripting.support.ResourceScriptSource; |
||||
|
||||
/** |
||||
* Groovy-based implementation of Spring's {@link ScriptEvaluator} strategy interface. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @since 4.0 |
||||
* @see GroovyShell#evaluate(String, String) |
||||
*/ |
||||
public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { |
||||
|
||||
private ClassLoader classLoader; |
||||
|
||||
|
||||
/** |
||||
* Construct a new GroovyScriptEvaluator. |
||||
*/ |
||||
public GroovyScriptEvaluator() { |
||||
} |
||||
|
||||
/** |
||||
* Construct a new GroovyScriptEvaluator. |
||||
* @param classLoader the ClassLoader to use as a parent for the {@link GroovyShell} |
||||
*/ |
||||
public GroovyScriptEvaluator(ClassLoader classLoader) { |
||||
this.classLoader = classLoader; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setBeanClassLoader(ClassLoader classLoader) { |
||||
this.classLoader = classLoader; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script) { |
||||
return evaluate(script, null); |
||||
} |
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script, Map<String, Object> arguments) { |
||||
GroovyShell groovyShell = new GroovyShell(this.classLoader, new Binding(arguments)); |
||||
try { |
||||
String filename = (script instanceof ResourceScriptSource ? |
||||
((ResourceScriptSource) script).getResource().getFilename() : null); |
||||
if (filename != null) { |
||||
return groovyShell.evaluate(script.getScriptAsString(), filename); |
||||
} |
||||
else { |
||||
return groovyShell.evaluate(script.getScriptAsString()); |
||||
} |
||||
} |
||||
catch (IOException ex) { |
||||
throw new ScriptCompilationException(script, "Cannot access script", ex); |
||||
} |
||||
catch (CompilationFailedException ex) { |
||||
throw new ScriptCompilationException(script, "Evaluation failure", ex); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,135 @@
@@ -0,0 +1,135 @@
|
||||
/* |
||||
* Copyright 2002-2013 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.springframework.scripting.support; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import javax.script.Bindings; |
||||
import javax.script.ScriptEngine; |
||||
import javax.script.ScriptEngineManager; |
||||
import javax.script.ScriptException; |
||||
import javax.script.SimpleBindings; |
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware; |
||||
import org.springframework.core.io.Resource; |
||||
import org.springframework.scripting.ScriptCompilationException; |
||||
import org.springframework.scripting.ScriptEvaluator; |
||||
import org.springframework.scripting.ScriptSource; |
||||
import org.springframework.util.CollectionUtils; |
||||
import org.springframework.util.StringUtils; |
||||
|
||||
/** |
||||
* {@code javax.script} (JSR-223) based implementation of |
||||
* Spring's {@link ScriptEvaluator} strategy interface. |
||||
* |
||||
* @author Juergen Hoeller |
||||
* @author Costin Leau |
||||
* @since 4.0 |
||||
* @see ScriptEngine#eval(String) |
||||
*/ |
||||
public class StandardScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAware { |
||||
|
||||
private volatile ScriptEngineManager scriptEngineManager; |
||||
|
||||
private String language; |
||||
|
||||
|
||||
/** |
||||
* Construct a new StandardScriptEvaluator. |
||||
*/ |
||||
public StandardScriptEvaluator() { |
||||
} |
||||
|
||||
/** |
||||
* Construct a new StandardScriptEvaluator. |
||||
* @param classLoader the class loader to use for script engine detection |
||||
*/ |
||||
public StandardScriptEvaluator(ClassLoader classLoader) { |
||||
this.scriptEngineManager = new ScriptEngineManager(classLoader); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setBeanClassLoader(ClassLoader classLoader) { |
||||
this.scriptEngineManager = new ScriptEngineManager(classLoader); |
||||
} |
||||
|
||||
/** |
||||
* Set the name of language meant for evaluation the scripts (e.g. "Groovy"). |
||||
*/ |
||||
public void setLanguage(String language) { |
||||
this.language = language; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script) { |
||||
return evaluate(script, null); |
||||
} |
||||
|
||||
@Override |
||||
public Object evaluate(ScriptSource script, Map<String, Object> arguments) { |
||||
ScriptEngine engine = getScriptEngine(script); |
||||
Bindings bindings = (!CollectionUtils.isEmpty(arguments) ? new SimpleBindings(arguments) : null); |
||||
try { |
||||
return (bindings != null ? engine.eval(script.getScriptAsString(), bindings) : |
||||
engine.eval(script.getScriptAsString())); |
||||
} |
||||
catch (IOException ex) { |
||||
throw new ScriptCompilationException(script, "Cannot access script", ex); |
||||
} |
||||
catch (ScriptException ex) { |
||||
throw new ScriptCompilationException(script, "Evaluation failure", ex); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Obtain the JSR-223 ScriptEngine to use for the given script. |
||||
* @param script the script to evaluate |
||||
* @return the ScriptEngine (never {@code null}) |
||||
*/ |
||||
protected ScriptEngine getScriptEngine(ScriptSource script) { |
||||
if (this.scriptEngineManager == null) { |
||||
this.scriptEngineManager = new ScriptEngineManager(); |
||||
} |
||||
if (StringUtils.hasText(this.language)) { |
||||
ScriptEngine engine = this.scriptEngineManager.getEngineByName(this.language); |
||||
if (engine == null) { |
||||
throw new IllegalStateException("No matching engine found for language '" + this.language + "'"); |
||||
} |
||||
return engine; |
||||
} |
||||
else if (script instanceof ResourceScriptSource) { |
||||
Resource resource = ((ResourceScriptSource) script).getResource(); |
||||
String extension = StringUtils.getFilenameExtension(resource.getFilename()); |
||||
if (extension == null) { |
||||
throw new IllegalStateException( |
||||
"No script language defined, and no file extension defined for resource: " + resource); |
||||
} |
||||
ScriptEngine engine = this.scriptEngineManager.getEngineByExtension(extension); |
||||
if (engine == null) { |
||||
throw new IllegalStateException("No matching engine found for file extension '" + extension + "'"); |
||||
} |
||||
return engine; |
||||
} |
||||
else { |
||||
throw new IllegalStateException( |
||||
"No script language defined, and no resource associated with script: " + script); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
@@ -0,0 +1,60 @@
|
||||
/* |
||||
* Copyright 2002-2013 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.springframework.scripting.bsh; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.scripting.ScriptEvaluator; |
||||
import org.springframework.scripting.support.ResourceScriptSource; |
||||
import org.springframework.scripting.support.StaticScriptSource; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* @author Juergen Hoeller |
||||
*/ |
||||
public class BshScriptEvaluatorTests { |
||||
|
||||
@Test |
||||
public void testBshScriptFromString() { |
||||
ScriptEvaluator evaluator = new BshScriptEvaluator(); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return 3 * 2;")); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testBshScriptFromFile() { |
||||
ScriptEvaluator evaluator = new BshScriptEvaluator(); |
||||
Object result = evaluator.evaluate(new ResourceScriptSource(new ClassPathResource("simple.bsh", getClass()))); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptWithArguments() { |
||||
ScriptEvaluator evaluator = new BshScriptEvaluator(); |
||||
Map<String, Object> arguments = new HashMap<String, Object>(); |
||||
arguments.put("a", 3); |
||||
arguments.put("b", 2); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return a * b;"), arguments); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
return 3 * 2; |
||||
@ -0,0 +1,87 @@
@@ -0,0 +1,87 @@
|
||||
/* |
||||
* Copyright 2002-2013 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.springframework.scripting.groovy; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.core.io.ClassPathResource; |
||||
import org.springframework.scripting.ScriptEvaluator; |
||||
import org.springframework.scripting.support.ResourceScriptSource; |
||||
import org.springframework.scripting.support.StandardScriptEvaluator; |
||||
import org.springframework.scripting.support.StaticScriptSource; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* @author Juergen Hoeller |
||||
*/ |
||||
public class GroovyScriptEvaluatorTests { |
||||
|
||||
@Test |
||||
public void testGroovyScriptFromString() { |
||||
ScriptEvaluator evaluator = new GroovyScriptEvaluator(); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return 3 * 2")); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptFromFile() { |
||||
ScriptEvaluator evaluator = new GroovyScriptEvaluator(); |
||||
Object result = evaluator.evaluate(new ResourceScriptSource(new ClassPathResource("simple.groovy", getClass()))); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptWithArguments() { |
||||
ScriptEvaluator evaluator = new GroovyScriptEvaluator(); |
||||
Map<String, Object> arguments = new HashMap<String, Object>(); |
||||
arguments.put("a", 3); |
||||
arguments.put("b", 2); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return a * b"), arguments); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptFromStringUsingJsr223() { |
||||
StandardScriptEvaluator evaluator = new StandardScriptEvaluator(); |
||||
evaluator.setLanguage("Groovy"); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return 3 * 2")); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptFromFileUsingJsr223() { |
||||
ScriptEvaluator evaluator = new StandardScriptEvaluator(); |
||||
Object result = evaluator.evaluate(new ResourceScriptSource(new ClassPathResource("simple.groovy", getClass()))); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
@Test |
||||
public void testGroovyScriptWithArgumentsUsingJsr223() { |
||||
StandardScriptEvaluator evaluator = new StandardScriptEvaluator(); |
||||
evaluator.setLanguage("Groovy"); |
||||
Map<String, Object> arguments = new HashMap<String, Object>(); |
||||
arguments.put("a", 3); |
||||
arguments.put("b", 2); |
||||
Object result = evaluator.evaluate(new StaticScriptSource("return a * b"), arguments); |
||||
assertEquals(6, result); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
return 3 * 2 |
||||
Loading…
Reference in new issue