CAMEL-6559 fixed the script builder synchronized the operation of evaluateScript issue
Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/f66375e9 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/f66375e9 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/f66375e9 Branch: refs/heads/master Commit: f66375e91e2755e956c1527752c255aa2d0f8c42 Parents: f478217 Author: Willem Jiang <[email protected]> Authored: Fri Jul 26 16:46:50 2013 +0800 Committer: Willem Jiang <[email protected]> Committed: Fri Jul 26 16:48:39 2013 +0800 ---------------------------------------------------------------------- .../camel/builder/script/ScriptBuilder.java | 61 ++++++++++++++++---- .../camel/builder/script/ScriptLanguage.java | 17 +++++- .../script/JavaScriptExpressionTest.java | 35 ++++++++++- 3 files changed, 99 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/f66375e9/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 710be36..7477673 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 @@ -22,6 +22,8 @@ import java.io.InputStreamReader; import java.io.Reader; import java.lang.reflect.Method; import java.util.Map; +import java.util.WeakHashMap; + import javax.script.Compilable; import javax.script.CompiledScript; import javax.script.ScriptContext; @@ -35,6 +37,7 @@ 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.util.IOHelper; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ResourceHelper; @@ -47,7 +50,7 @@ import org.slf4j.LoggerFactory; * * @version */ -public class ScriptBuilder implements Expression, Predicate, Processor { +public class ScriptBuilder extends ServiceSupport implements Expression, Predicate, Processor { /** * Additional arguments to {@link ScriptEngine} provided as a header on the IN {@link org.apache.camel.Message} @@ -60,8 +63,9 @@ public class ScriptBuilder implements Expression, Predicate, Processor { private String scriptEngineName; private String scriptResource; private String scriptText; - private ScriptEngine engine; private CompiledScript compiledScript; + private Map<Thread, ScriptEngineHolder> engineHolders = new WeakHashMap<Thread, ScriptEngineHolder>(); + private ThreadLocal<ScriptEngineHolder> engineHolder = new ThreadLocal<ScriptEngineHolder>(); /** * Constructor. @@ -194,13 +198,22 @@ public class ScriptBuilder implements Expression, Predicate, Processor { // ------------------------------------------------------------------------- public ScriptEngine getEngine() { - if (engine == null) { - engine = createScriptEngine(); + if (engineHolder.get() == null) { + ScriptEngineHolder holder = new ScriptEngineHolder(); + + engineHolder.set(holder); + engineHolders.put(Thread.currentThread(), holder); } - if (engine == null) { + if (engineHolder.get() == null) { throw new IllegalArgumentException("No script engine could be created for: " + getScriptEngineName()); } - return engine; + ScriptEngineHolder holder = engineHolder.get(); + if (holder.engine == null) { + holder.engine = createScriptEngine(); + engineHolders.put(Thread.currentThread(), holder); + } + + return holder.engine; } public CompiledScript getCompiledScript() { @@ -258,13 +271,20 @@ public class ScriptBuilder implements Expression, Predicate, Processor { if (scriptText == null && scriptResource == null) { throw new IllegalArgumentException("Neither scriptText or scriptResource are specified"); } - if (engine == null) { - engine = createScriptEngine(); + 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 (engine instanceof Compilable && !isBeanShell()) { - compileScript((Compilable)engine, exchange); + if (holder.engine instanceof Compilable && !isBeanShell()) { + compileScript((Compilable)holder.engine, exchange); } } } @@ -275,6 +295,7 @@ public class ScriptBuilder implements Expression, Predicate, Processor { protected ScriptEngine createScriptEngine() { ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = null; try { engine = manager.getEngineByName(scriptEngineName); } catch (NoClassDefFoundError ex) { @@ -333,7 +354,7 @@ public class ScriptBuilder implements Expression, Predicate, Processor { } } - protected synchronized Object evaluateScript(Exchange exchange) { + protected Object evaluateScript(Exchange exchange) { try { getScriptContext(); populateBindings(getEngine(), exchange); @@ -438,4 +459,22 @@ public class ScriptBuilder implements Expression, Predicate, Processor { protected boolean isBeanShell() { return "beanshell".equals(scriptEngineName) || "bsh".equals(scriptEngineName); } + + @Override + protected void doStart() throws Exception { + // do nothing here + } + + @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/f66375e9/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 c463cb8..171b63a 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,6 +18,7 @@ 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; /** @@ -32,12 +33,24 @@ public class ScriptLanguage extends LanguageSupport { public Predicate createPredicate(String expression) { expression = loadResource(expression); - return new ScriptBuilder(language, expression); + ScriptBuilder builder = new ScriptBuilder(language, expression); + try { + getCamelContext().addService(builder); + } catch (Exception ex) { + throw new RuntimeCamelException(ex); + } + return builder; } public Expression createExpression(String expression) { expression = loadResource(expression); - return new ScriptBuilder(language, expression); + ScriptBuilder builder = new ScriptBuilder(language, expression); + try { + getCamelContext().addService(builder); + } catch (Exception ex) { + throw new RuntimeCamelException(ex); + } + return builder; } } http://git-wip-us.apache.org/repos/asf/camel/blob/f66375e9/components/camel-script/src/test/java/org/apache/camel/builder/script/JavaScriptExpressionTest.java ---------------------------------------------------------------------- diff --git a/components/camel-script/src/test/java/org/apache/camel/builder/script/JavaScriptExpressionTest.java b/components/camel-script/src/test/java/org/apache/camel/builder/script/JavaScriptExpressionTest.java index 9581c6f..d02b1c2 100644 --- a/components/camel-script/src/test/java/org/apache/camel/builder/script/JavaScriptExpressionTest.java +++ b/components/camel-script/src/test/java/org/apache/camel/builder/script/JavaScriptExpressionTest.java @@ -18,6 +18,8 @@ package org.apache.camel.builder.script; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import org.apache.camel.ScriptTestHelper; import org.apache.camel.builder.RouteBuilder; @@ -146,7 +148,38 @@ public class JavaScriptExpressionTest extends CamelTestSupport { assertMockEndpointsSatisfied(); } - + + @Test + public void testSendingRequestInMutipleThreads() throws Exception { + if (!ScriptTestHelper.canRunTestOnThisPlatform()) { + return; + } + getMockEndpoint("mock:result").expectedMessageCount(0); + getMockEndpoint("mock:unmatched").expectedMessageCount(100); + long start = System.currentTimeMillis(); + ExecutorService executorService = Executors.newFixedThreadPool(100); + for (int i = 0; i < 100; i++) { + executorService.submit(new Runnable() { + @Override + public void run() { + Map<String, Object> headers = new HashMap<String, Object>(); + String arguments = "foo"; + headers.put(ScriptBuilder.ARGUMENTS, arguments); + + sendBody("direct:start", "hello", headers); + + } + + }); + } + + assertMockEndpointsSatisfied(); + long delta = System.currentTimeMillis() - start; + log.info("Processing the 100 request tooks: " + delta + " ms"); + executorService.shutdown(); + + } + protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { public void configure() throws Exception {
