You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ol...@apache.org on 2020/05/26 10:46:15 UTC
[maven-enforcer] branch master updated: MENFORCER-336: Changed
beanshell interpreter from singleton / static field to ThreadLocal.
This is an automated email from the ASF dual-hosted git repository.
olamy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-enforcer.git
The following commit(s) were added to refs/heads/master by this push:
new c273451 MENFORCER-336: Changed beanshell interpreter from singleton / static field to ThreadLocal.
c273451 is described below
commit c273451308dec5642760e3bcf56bd292f3ef587c
Author: Vidar Breivik <vb...@gmail.com>
AuthorDate: Tue Dec 24 00:10:14 2019 +0100
MENFORCER-336: Changed beanshell interpreter from singleton / static field to ThreadLocal.
---
.../maven/plugins/enforcer/EvaluateBeanshell.java | 11 +-
.../plugins/enforcer/TestEvaluateBeanshell.java | 116 +++++++++++++++++++++
2 files changed, 125 insertions(+), 2 deletions(-)
diff --git a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java
index c41982f..91a6635 100644
--- a/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java
+++ b/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/EvaluateBeanshell.java
@@ -38,7 +38,14 @@ public class EvaluateBeanshell
{
/** Beanshell interpreter. */
- private static final Interpreter BSH = new Interpreter();
+ private static final ThreadLocal<Interpreter> INTERPRETER = new ThreadLocal<Interpreter>()
+ {
+ @Override
+ protected Interpreter initialValue()
+ {
+ return new Interpreter();
+ }
+ };
/** The condition to be evaluated.
*
@@ -99,7 +106,7 @@ public class EvaluateBeanshell
Boolean evaluation = Boolean.FALSE;
try
{
- evaluation = (Boolean) BSH.eval( script );
+ evaluation = (Boolean) INTERPRETER.get().eval( script );
log.debug( "Echo evaluating : " + evaluation );
}
catch ( EvalError ex )
diff --git a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java
index 7f8faa7..f78729f 100644
--- a/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java
+++ b/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/TestEvaluateBeanshell.java
@@ -24,6 +24,15 @@ import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
import static org.mockito.Mockito.*;
/**
@@ -136,4 +145,111 @@ public class TestEvaluateBeanshell
assertFalse( e.getLocalizedMessage().equals( rule.getMessage() ) );
}
}
+
+
+ public void testRuleCanExecuteMultipleThreads() throws InterruptedException {
+ final String condition = "String property1 = \"${property1}\";\n" +
+ "(property1.equals(\"prop0\") && \"${property2}\".equals(\"prop0\"))\n" +
+ "|| (property1.equals(\"prop1\") && \"${property2}\".equals(\"prop1\"))\n" +
+ "|| (property1.equals(\"prop2\") && \"${property2}\".equals(\"prop2\"))\n";
+
+ final List<Runnable> runnables = new ArrayList<>();
+
+ runnables.add(new Runnable() {
+ @Override
+ public void run() {
+ final int threadNumber = 0;
+ MockProject multiProject = new MockProject();
+ multiProject.setProperty("property1", "prop" + threadNumber);
+ multiProject.setProperty("property2", "prop" + threadNumber);
+
+ EvaluateBeanshell rule = new EvaluateBeanshell();
+ rule.setCondition(condition);
+ rule.setMessage("Race condition in thread " + threadNumber);
+ EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
+ try {
+ rule.execute(helper);
+
+ } catch (EnforcerRuleException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ runnables.add(new Runnable() {
+ @Override
+ public void run() {
+ final int threadNumber = 1;
+ MockProject multiProject = new MockProject();
+ multiProject.setProperty("property1", "prop" + threadNumber);
+ multiProject.setProperty("property2", "prop" + threadNumber);
+
+ EvaluateBeanshell rule = new EvaluateBeanshell();
+ rule.setCondition(condition);
+ rule.setMessage("Race condition in thread " + threadNumber);
+ EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
+ try {
+ rule.execute(helper);
+
+ } catch (EnforcerRuleException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+ });
+ runnables.add(new Runnable() {
+ @Override
+ public void run() {
+ final int threadNumber = 2;
+ MockProject multiProject = new MockProject();
+ multiProject.setProperty("property1", "prop" + threadNumber);
+ multiProject.setProperty("property2", "prop" + threadNumber);
+
+ EvaluateBeanshell rule = new EvaluateBeanshell();
+ rule.setCondition(condition);
+ rule.setMessage("Race condition in thread " + threadNumber);
+ EnforcerRuleHelper helper = EnforcerTestUtils.getHelper(multiProject);
+ try {
+ rule.execute(helper);
+ } catch (EnforcerRuleException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ assertConcurrent( runnables, 4);
+ }
+
+ private static void assertConcurrent(final List<? extends Runnable> runnables, final int maxTimeoutSeconds) throws InterruptedException {
+ final int numThreads = runnables.size();
+ final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
+ final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
+ try {
+ final CountDownLatch allExecutorThreadsReady = new CountDownLatch(numThreads);
+ final CountDownLatch afterInitBlocker = new CountDownLatch(1);
+ final CountDownLatch allDone = new CountDownLatch(numThreads);
+ for (final Runnable submittedTestRunnable : runnables) {
+ threadPool.submit(new Runnable() {
+ public void run() {
+ allExecutorThreadsReady.countDown();
+ try {
+ afterInitBlocker.await();
+ submittedTestRunnable.run();
+ } catch (final Throwable e) {
+ exceptions.add(e);
+ } finally {
+ allDone.countDown();
+ }
+ }
+ });
+ }
+ // wait until all threads are ready
+ assertTrue("Timeout initializing threads! Perform long lasting initializations before passing runnables to assertConcurrent", allExecutorThreadsReady.await(runnables.size() * 10, TimeUnit.MILLISECONDS));
+ // start all test runners
+ afterInitBlocker.countDown();
+ assertTrue("Timeout! More than" + maxTimeoutSeconds + "seconds", allDone.await(maxTimeoutSeconds, TimeUnit.SECONDS));
+ } finally {
+ threadPool.shutdownNow();
+ }
+ assertTrue("Failed with exception(s)" + exceptions, exceptions.isEmpty());
+ }
}