This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch feature/WW-5414-after in repository https://gitbox.apache.org/repos/asf/struts.git
commit 32f9b68c94ebe21f814962206e45ff8907a6105b Author: Lukasz Lenart <lukaszlen...@apache.org> AuthorDate: Sat May 11 08:23:56 2024 +0200 WW-5414 Always call afterInvocation even in case of exception --- .../interceptor/exec/StrutsBackgroundProcess.java | 19 +++++-- .../exec/StrutsBackgroundProcessTest.java | 58 ++++++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcess.java b/core/src/main/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcess.java index 42237262f..3eb7c230f 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcess.java +++ b/core/src/main/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcess.java @@ -20,8 +20,11 @@ package org.apache.struts2.interceptor.exec; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.Serializable; +import java.util.concurrent.ExecutionException; /** * Background thread to be executed by the ExecuteAndWaitInterceptor. @@ -30,6 +33,8 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable private static final long serialVersionUID = 3884464776311686443L; + private static final Logger LOG = LogManager.getLogger(StrutsBackgroundProcess.class); + private final String threadName; private final int threadPriority; @@ -44,8 +49,8 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable /** * Constructs a background process * - * @param invocation The action invocation - * @param threadName The name of background thread + * @param invocation The action invocation + * @param threadName The name of background thread * @param threadPriority The priority of background thread */ public StrutsBackgroundProcess(ActionInvocation invocation, String threadName, int threadPriority) { @@ -61,11 +66,17 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable try { beforeInvocation(); result = invocation.invokeActionOnly(); - afterInvocation(); } catch (Exception e) { + LOG.warn("Exception during invokeActionOnly() execution", e); exception = e; } finally { - done = true; + try { + afterInvocation(); + } catch (Exception ex) { + exception = ex; + LOG.warn("Exception during afterInvocation() execution", ex); + } + done = true; } }); processThread.setName(threadName); diff --git a/core/src/test/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcessTest.java b/core/src/test/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcessTest.java index 5906c995a..bfcfbf175 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcessTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/exec/StrutsBackgroundProcessTest.java @@ -59,9 +59,9 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase { invocation.setInvocationContext(ActionContext.getContext()); StrutsBackgroundProcess bp = (StrutsBackgroundProcess) new StrutsBackgroundProcess( - invocation, - "BackgroundProcessTest.testSerializeDeserialize", - Thread.MIN_PRIORITY + invocation, + "BackgroundProcessTest.testSerializeDeserialize", + Thread.MIN_PRIORITY ).prepare(); executor.execute(bp); @@ -120,6 +120,33 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase { assertEquals(100, mutableState.get()); } + public void testErrorableProcesses1() throws InterruptedException { + MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> { + throw new IllegalStateException("boom"); + }); + + BackgroundProcess bp = new ErrorableBackgroundProcess(invocation, null).prepare(); + executor.execute(bp); + + Thread.sleep(100); + + assertTrue("afterInvocation not called in case of exception", ((ErrorableBackgroundProcess) bp).isDoneAfter()); + } + + public void testErrorableProcesses2() throws InterruptedException { + MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> { + throw new IllegalArgumentException("boom!"); + }); + + IllegalStateException expected = new IllegalStateException("after!"); + BackgroundProcess bp = new ErrorableBackgroundProcess(invocation, expected).prepare(); + executor.execute(bp); + + Thread.sleep(100); + + assertEquals(expected, bp.getException()); + } + public void testUnpreparedProcess() throws ExecutionException, InterruptedException, TimeoutException { // given MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> "done"); @@ -177,3 +204,28 @@ class LockBackgroundProcess extends StrutsBackgroundProcess { lock.notify(); } } + +class ErrorableBackgroundProcess extends StrutsBackgroundProcess { + + private final Exception afterException; + private boolean doneAfter; + + public ErrorableBackgroundProcess(ActionInvocation invocation, Exception afterException) { + super(invocation, "errorabale process", Thread.NORM_PRIORITY); + this.afterException = afterException; + } + + @Override + protected void afterInvocation() throws Exception { + if (afterException != null) { + throw afterException; + } else { + super.afterInvocation(); + doneAfter = true; + } + } + + public boolean isDoneAfter() { + return doneAfter; + } +}