You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2014/01/31 17:24:11 UTC
[2/3] git commit: CAMEL-7143: Fixed camel-script would return result
from previous evaluation. Use engine factort get engine to use for
evaluation.
CAMEL-7143: Fixed camel-script would return result from previous evaluation. Use engine factort get engine to use for evaluation.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4c906bfe
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4c906bfe
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4c906bfe
Branch: refs/heads/master
Commit: 4c906bfe4854ded6a2379dcd4097233f041c802c
Parents: 59cce7e
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Jan 31 17:10:10 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Jan 31 17:24:38 2014 +0100
----------------------------------------------------------------------
.../camel/builder/script/ScriptBuilder.java | 309 +++++++++----------
.../camel/builder/script/ScriptLanguage.java | 17 +-
2 files changed, 152 insertions(+), 174 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/4c906bfe/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptBuilder.java
----------------------------------------------------------------------
diff --git a/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptBuilder.java b/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptBuilder.java
index 7fb1382..5301ea4 100644
--- a/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptBuilder.java
+++ b/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptBuilder.java
@@ -20,24 +20,25 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
+import java.io.StringReader;
import java.lang.reflect.Method;
+import java.util.HashMap;
import java.util.Map;
-import java.util.WeakHashMap;
-
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
+import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
import org.apache.camel.Expression;
import org.apache.camel.Message;
import org.apache.camel.Predicate;
import org.apache.camel.Processor;
-import org.apache.camel.converter.ObjectConverter;
-import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.spi.ClassResolver;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.ResourceHelper;
@@ -50,7 +51,7 @@ import org.slf4j.LoggerFactory;
*
* @version
*/
-public class ScriptBuilder extends ServiceSupport implements Expression, Predicate, Processor {
+public class ScriptBuilder implements Expression, Predicate, Processor {
/**
* Additional arguments to {@link ScriptEngine} provided as a header on the IN {@link org.apache.camel.Message}
@@ -60,31 +61,92 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
private static final Logger LOG = LoggerFactory.getLogger(ScriptBuilder.class);
- private String scriptEngineName;
- private String scriptResource;
- private String scriptText;
+ private Map<String, Object> attributes;
+ private final CamelContext camelContext;
+ private final ScriptEngineFactory scriptEngineFactory;
+ private final String scriptLanguage;
+ private final String scriptResource;
+ private final String scriptText;
private CompiledScript compiledScript;
- private Map<Thread, ScriptEngineHolder> engineHolders = new WeakHashMap<Thread, ScriptEngineHolder>();
- private ThreadLocal<ScriptEngineHolder> engineHolder = new ThreadLocal<ScriptEngineHolder>();
/**
* Constructor.
*
- * @param scriptEngineName the name of the scripting language
+ * @param scriptLanguage the name of the scripting language
+ * @param scriptText the script text to be evaluated, or a reference to a script resource
*/
- public ScriptBuilder(String scriptEngineName) {
- this.scriptEngineName = scriptEngineName;
+ public ScriptBuilder(String scriptLanguage, String scriptText) {
+ this(null, scriptLanguage, scriptText, null);
}
/**
* Constructor.
*
- * @param scriptEngineName the name of the scripting language
+ * @param scriptLanguage the name of the scripting language
* @param scriptText the script text to be evaluated, or a reference to a script resource
*/
- public ScriptBuilder(String scriptEngineName, String scriptText) {
- this(scriptEngineName);
- setScriptText(scriptText);
+ public ScriptBuilder(CamelContext camelContext, String scriptLanguage, String scriptText) {
+ this(camelContext, scriptLanguage, scriptText, null);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param scriptLanguage the name of the scripting language
+ * @param scriptText the script text to be evaluated, or a reference to a script resource
+ * @param scriptEngineFactory the script engine factory
+ */
+ public ScriptBuilder(CamelContext camelContext, String scriptLanguage, String scriptText, ScriptEngineFactory scriptEngineFactory) {
+ this.camelContext = camelContext;
+ this.scriptLanguage = scriptLanguage;
+ if (ResourceHelper.hasScheme(scriptText)) {
+ this.scriptResource = scriptText;
+ this.scriptText = null;
+ } else {
+ this.scriptResource = null;
+ this.scriptText = scriptText;
+ }
+ if (scriptEngineFactory == null) {
+ this.scriptEngineFactory = lookupScriptEngineFactory(scriptLanguage);
+ } else {
+ this.scriptEngineFactory = scriptEngineFactory;
+ }
+
+ if (this.scriptEngineFactory == null) {
+ throw new IllegalArgumentException("Cannot lookup ScriptEngineFactory for script language: " + scriptLanguage);
+ }
+
+ // bean shell is not compileable
+ if (isBeanShell(scriptLanguage)) {
+ return;
+ }
+
+ // pre-compile script which would execute faster if possible
+ Reader reader = null;
+ try {
+ // if we have camel context then load resources
+ if (camelContext != null && scriptResource != null) {
+ reader = createScriptReader(camelContext.getClassResolver(), scriptResource);
+ } else if (this.scriptText != null) {
+ reader = new StringReader(this.scriptText);
+ }
+
+ // pre-compile script if we have it as text
+ if (reader != null) {
+ ScriptEngine engine = this.scriptEngineFactory.getScriptEngine();
+ if (engine instanceof Compilable) {
+ Compilable compilable = (Compilable) engine;
+ this.compiledScript = compilable.compile(scriptText);
+ LOG.debug("Using compiled script: {}", this.compiledScript);
+ }
+ }
+ } catch (IOException e) {
+ throw new ScriptEvaluationException("Cannot load " + scriptLanguage + " script from resource: " + scriptResource, e);
+ } catch (ScriptException e) {
+ throw new ScriptEvaluationException("Error compiling " + scriptLanguage + " script: " + scriptText, e);
+ } finally {
+ IOHelper.close(reader);
+ }
}
@Override
@@ -129,7 +191,10 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
* @return this builder
*/
public ScriptBuilder attribute(String name, Object value) {
- getScriptContext().setAttribute(name, value, ScriptContext.ENGINE_SCOPE);
+ if (attributes == null) {
+ attributes = new HashMap<String, Object>();
+ }
+ attributes.put(name, value);
return this;
}
@@ -197,43 +262,12 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
// Properties
// -------------------------------------------------------------------------
- public ScriptEngine getEngine() {
- if (engineHolder.get() == null) {
- ScriptEngineHolder holder = new ScriptEngineHolder();
-
- engineHolder.set(holder);
- engineHolders.put(Thread.currentThread(), holder);
- }
- if (engineHolder.get() == null) {
- throw new IllegalArgumentException("No script engine could be created for: " + getScriptEngineName());
- }
- ScriptEngineHolder holder = engineHolder.get();
- if (holder.engine == null) {
- holder.engine = createScriptEngine();
- engineHolders.put(Thread.currentThread(), holder);
- }
-
- return holder.engine;
- }
-
public CompiledScript getCompiledScript() {
return compiledScript;
}
- public String getScriptText() {
- return scriptText;
- }
-
- public void setScriptText(String scriptText) {
- if (ResourceHelper.hasScheme(scriptText)) {
- this.scriptResource = scriptText;
- } else {
- this.scriptText = scriptText;
- }
- }
-
- public String getScriptEngineName() {
- return scriptEngineName;
+ public String getScriptLanguage() {
+ return scriptLanguage;
}
/**
@@ -243,54 +277,19 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
*/
public String getScriptDescription() {
if (scriptText != null) {
- return scriptEngineName + ": " + scriptText;
+ return scriptLanguage + ": " + scriptText;
} else if (scriptResource != null) {
- return scriptEngineName + ": " + scriptResource;
+ return scriptLanguage + ": " + scriptResource;
} else {
- return scriptEngineName + ": null script";
+ return scriptLanguage + ": null script";
}
}
- /**
- * Access the script context so that it can be configured such as adding attributes
- */
- public ScriptContext getScriptContext() {
- return getEngine().getContext();
- }
-
- /**
- * Sets the context to use by the script
- */
- public void setScriptContext(ScriptContext scriptContext) {
- getEngine().setContext(scriptContext);
- }
-
// Implementation methods
// -------------------------------------------------------------------------
- protected void checkInitialised(Exchange exchange) {
- if (scriptText == null && scriptResource == null) {
- throw new IllegalArgumentException("Neither scriptText or scriptResource are specified");
- }
- ScriptEngineHolder holder = engineHolder.get();
- if (holder == null) {
- holder = new ScriptEngineHolder();
- engineHolder.set(holder);
- }
- holder = engineHolder.get();
- if (holder.engine == null) {
- holder.engine = createScriptEngine();
- engineHolders.put(Thread.currentThread(), holder);
- }
- if (compiledScript == null) {
- // BeanShell implements Compilable but throws an exception if you call compile
- if (holder.engine instanceof Compilable && !isBeanShell()) {
- compileScript((Compilable)holder.engine, exchange);
- }
- }
- }
protected boolean matches(Exchange exchange, Object scriptValue) {
- return ObjectConverter.toBool(scriptValue);
+ return exchange.getContext().getTypeConverter().convertTo(boolean.class, scriptValue);
}
private static String[] getScriptNames(String name) {
@@ -304,12 +303,32 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
return new String[]{name};
}
- protected ScriptEngine createScriptEngine() {
+ protected static ScriptEngineFactory lookupScriptEngineFactory(String language) {
+ ScriptEngineManager manager = new ScriptEngineManager();
+ for (ScriptEngineFactory factory : manager.getEngineFactories()) {
+ // some script names has alias
+ String[] names = getScriptNames(language);
+ for (String name : names) {
+ if (factory.getLanguageName().equals(name)) {
+ return factory;
+ }
+ }
+ }
+
+ // fallback to get engine by name
+ ScriptEngine engine = createScriptEngine(language);
+ if (engine != null) {
+ return engine.getFactory();
+ }
+ return null;
+ }
+
+ protected static ScriptEngine createScriptEngine(String language) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = null;
// some script names has alias
- String[] names = getScriptNames(scriptEngineName);
+ String[] names = getScriptNames(language);
for (String name : names) {
try {
engine = manager.getEngineByName(name);
@@ -322,20 +341,20 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
}
}
if (engine == null) {
- engine = checkForOSGiEngine();
+ engine = checkForOSGiEngine(language);
}
if (engine == null) {
- throw new IllegalArgumentException("No script engine could be created for: " + scriptEngineName);
+ throw new IllegalArgumentException("No script engine could be created for: " + language);
}
- if (isPython()) {
+ if (isPython(language)) {
ScriptContext context = engine.getContext();
context.setAttribute("com.sun.script.jython.comp.mode", "eval", ScriptContext.ENGINE_SCOPE);
}
return engine;
}
- private ScriptEngine checkForOSGiEngine() {
- LOG.debug("No script engine found for " + scriptEngineName + " using standard javax.script auto-registration. Checking OSGi registry...");
+ private static ScriptEngine checkForOSGiEngine(String language) {
+ LOG.debug("No script engine found for " + language + " using standard javax.script auto-registration. Checking OSGi registry...");
try {
// Test the OSGi environment with the Activator
Class<?> c = Class.forName("org.apache.camel.script.osgi.Activator");
@@ -344,7 +363,7 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
LOG.debug("Found OSGi BundleContext " + ctx);
if (ctx != null) {
Method resolveScriptEngine = c.getDeclaredMethod("resolveScriptEngine", String.class);
- return (ScriptEngine)resolveScriptEngine.invoke(null, scriptEngineName);
+ return (ScriptEngine)resolveScriptEngine.invoke(null, language);
}
} catch (Throwable t) {
LOG.debug("Unable to load OSGi, script engine cannot be found", t);
@@ -352,33 +371,13 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
return null;
}
- protected void compileScript(Compilable compilable, Exchange exchange) {
- Reader reader = null;
- try {
- if (scriptText != null) {
- compiledScript = compilable.compile(scriptText);
- } else if (scriptResource != null) {
- reader = createScriptReader(exchange);
- compiledScript = compilable.compile(reader);
- }
- } catch (ScriptException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("Script compile failed: " + e.getMessage(), e);
- }
- throw createScriptCompileException(e);
- } catch (IOException e) {
- throw createScriptCompileException(e);
- } finally {
- IOHelper.close(reader);
- }
- }
-
protected Object evaluateScript(Exchange exchange) {
try {
- getScriptContext();
- populateBindings(getEngine(), exchange);
- addScriptEngineArguments(getEngine(), exchange);
- Object result = runScript(exchange);
+ // get a new engine which we must for each exchange
+ ScriptEngine engine = scriptEngineFactory.getScriptEngine();
+ ScriptContext context = populateBindings(engine, exchange, attributes);
+ addScriptEngineArguments(engine, exchange);
+ Object result = runScript(engine, exchange, context);
LOG.debug("The script evaluation result is: {}", result);
return result;
} catch (ScriptException e) {
@@ -395,22 +394,29 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
}
}
- protected Object runScript(Exchange exchange) throws ScriptException, IOException {
- checkInitialised(exchange);
- Object result;
+ protected Object runScript(ScriptEngine engine, Exchange exchange, ScriptContext context) throws ScriptException, IOException {
+ Object result = null;
if (compiledScript != null) {
- result = compiledScript.eval();
+ LOG.trace("Evaluate using compiled script for context: {} on exchange: {}", context, exchange);
+ result = compiledScript.eval(context);
} else {
if (scriptText != null) {
- result = getEngine().eval(scriptText);
- } else {
- result = getEngine().eval(createScriptReader(exchange));
+ LOG.trace("Evaluate script for context: {} on exchange: {}", context, exchange);
+ result = engine.eval(scriptText, context);
+ } else if (scriptResource != null) {
+ Reader reader = createScriptReader(exchange.getContext().getClassResolver(), scriptResource);
+ try {
+ LOG.trace("Evaluate script for context: {} on exchange: {}", context, exchange);
+ result = engine.eval(reader, context);
+ } finally {
+ IOHelper.close(reader);
+ }
}
}
return result;
}
- protected void populateBindings(ScriptEngine engine, Exchange exchange) {
+ protected ScriptContext populateBindings(ScriptEngine engine, Exchange exchange, Map<String, Object> attributes) {
ScriptContext context = engine.getContext();
int scope = ScriptContext.ENGINE_SCOPE;
context.setAttribute("context", exchange.getContext(), scope);
@@ -427,6 +433,13 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
}
// to make using properties component easier
context.setAttribute("properties", new ScriptPropertiesFunction(exchange.getContext()), scope);
+ // any additional attributes
+ if (attributes != null) {
+ for (Map.Entry<String, Object> entry : attributes.entrySet()) {
+ context.setAttribute(entry.getKey(), entry.getValue(), scope);
+ }
+ }
+ return context;
}
@SuppressWarnings("unchecked")
@@ -448,16 +461,11 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
}
}
- protected InputStreamReader createScriptReader(Exchange exchange) throws IOException {
- ObjectHelper.notNull(scriptResource, "scriptResource", this);
- InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(exchange.getContext().getClassResolver(), scriptResource);
+ protected static InputStreamReader createScriptReader(ClassResolver classResolver, String resource) throws IOException {
+ InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(classResolver, resource);
return new InputStreamReader(is);
}
- protected ScriptEvaluationException createScriptCompileException(Exception e) {
- return new ScriptEvaluationException("Failed to compile: " + getScriptDescription() + ". Cause: " + e, e);
- }
-
protected ScriptEvaluationException createScriptEvaluationException(Throwable e) {
if (e.getClass().getName().equals("org.jruby.exceptions.RaiseException")) {
// Only the nested exception has the specific problem
@@ -471,29 +479,12 @@ public class ScriptBuilder extends ServiceSupport implements Expression, Predica
return new ScriptEvaluationException("Failed to evaluate: " + getScriptDescription() + ". Cause: " + e, e);
}
- protected boolean isPython() {
- return "python".equals(scriptEngineName) || "jython".equals(scriptEngineName);
- }
-
- protected boolean isBeanShell() {
- return "beanshell".equals(scriptEngineName) || "bsh".equals(scriptEngineName);
+ private static boolean isPython(String language) {
+ return "python".equals(language) || "jython".equals(language);
}
- @Override
- protected void doStart() throws Exception {
- // do nothing here
+ private static boolean isBeanShell(String language) {
+ return "beanshell".equals(language) || "bsh".equals(language);
}
- @Override
- protected void doStop() throws Exception {
- // we need to clean up the engines map
- for (ScriptEngineHolder holder : engineHolders.values()) {
- holder.engine = null;
- }
- engineHolders.clear();
- }
-
- static class ScriptEngineHolder {
- ScriptEngine engine;
- }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4c906bfe/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptLanguage.java
----------------------------------------------------------------------
diff --git a/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptLanguage.java b/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptLanguage.java
index 171b63a..01da27d 100644
--- a/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptLanguage.java
+++ b/components/camel-script/src/main/java/org/apache/camel/builder/script/ScriptLanguage.java
@@ -18,7 +18,6 @@ package org.apache.camel.builder.script;
import org.apache.camel.Expression;
import org.apache.camel.Predicate;
-import org.apache.camel.RuntimeCamelException;
import org.apache.camel.support.LanguageSupport;
/**
@@ -33,24 +32,12 @@ public class ScriptLanguage extends LanguageSupport {
public Predicate createPredicate(String expression) {
expression = loadResource(expression);
- ScriptBuilder builder = new ScriptBuilder(language, expression);
- try {
- getCamelContext().addService(builder);
- } catch (Exception ex) {
- throw new RuntimeCamelException(ex);
- }
- return builder;
+ return new ScriptBuilder(getCamelContext(), language, expression);
}
public Expression createExpression(String expression) {
expression = loadResource(expression);
- ScriptBuilder builder = new ScriptBuilder(language, expression);
- try {
- getCamelContext().addService(builder);
- } catch (Exception ex) {
- throw new RuntimeCamelException(ex);
- }
- return builder;
+ return new ScriptBuilder(getCamelContext(), language, expression);
}
}