This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 11.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit c8c7010e8ca6019d7490b08387dc89a2e6ae6f8f Author: opencode <[email protected]> AuthorDate: Wed Sep 30 13:28:12 2026 +0200 Delegate awaitTermination() in StandardThreadExecutor and StandardVirtualThreadExecutor to the wrapped executor rather than unconditionally returning false which violates the ExecutorService contract --- .../catalina/core/StandardThreadExecutor.java | 6 +- .../core/StandardVirtualThreadExecutor.java | 6 +- .../core/TestExecutorAwaitTermination.java | 75 ++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/java/org/apache/catalina/core/StandardThreadExecutor.java b/java/org/apache/catalina/core/StandardThreadExecutor.java index 7b8c347c5d..27545ef9ed 100644 --- a/java/org/apache/catalina/core/StandardThreadExecutor.java +++ b/java/org/apache/catalina/core/StandardThreadExecutor.java @@ -449,7 +449,11 @@ public class StandardThreadExecutor extends LifecycleMBeanBase implements Execut @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return false; + if (executor != null) { + return executor.awaitTermination(timeout, unit); + } else { + throw new IllegalStateException(sm.getString("standardThreadExecutor.notStarted")); + } } diff --git a/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java b/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java index 932f439590..424c7bff8d 100644 --- a/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java +++ b/java/org/apache/catalina/core/StandardVirtualThreadExecutor.java @@ -152,7 +152,11 @@ public class StandardVirtualThreadExecutor extends LifecycleMBeanBase implements @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { - return false; + if (executor != null) { + return executor.awaitTermination(timeout, unit); + } else { + throw new IllegalStateException(sm.getString("standardVirtualThreadExecutor.notStarted")); + } } diff --git a/test/org/apache/catalina/core/TestExecutorAwaitTermination.java b/test/org/apache/catalina/core/TestExecutorAwaitTermination.java new file mode 100644 index 0000000000..9dc6689622 --- /dev/null +++ b/test/org/apache/catalina/core/TestExecutorAwaitTermination.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.catalina.core; + +import java.util.concurrent.TimeUnit; + +import org.junit.Assert; +import org.junit.Test; + +public class TestExecutorAwaitTermination { + + @Test + public void testThreadExecutorAwaitTerminationNotStarted() throws Exception { + StandardThreadExecutor executor = new StandardThreadExecutor(); + try { + executor.awaitTermination(0, TimeUnit.MILLISECONDS); + Assert.fail("Expected an IllegalStateException before the executor is started"); + } catch (IllegalStateException e) { + // Expected + } + } + + + @Test + public void testThreadExecutorAwaitTerminationDelegates() throws Exception { + StandardThreadExecutor executor = new StandardThreadExecutor(); + executor.start(); + try { + // The pool is running so termination has not been reached + Assert.assertFalse(executor.awaitTermination(0, TimeUnit.MILLISECONDS)); + } finally { + executor.stop(); + } + } + + + @Test + public void testVirtualThreadExecutorAwaitTerminationNotStarted() throws Exception { + StandardVirtualThreadExecutor executor = new StandardVirtualThreadExecutor(); + try { + executor.awaitTermination(0, TimeUnit.MILLISECONDS); + Assert.fail("Expected an IllegalStateException before the executor is started"); + } catch (IllegalStateException e) { + // Expected + } + } + + + @Test + public void testVirtualThreadExecutorAwaitTerminationDelegates() throws Exception { + StandardVirtualThreadExecutor executor = new StandardVirtualThreadExecutor(); + executor.start(); + try { + // The executor has not been shut down so termination has not been + // reached; the call must delegate rather than block indefinitely + Assert.assertFalse(executor.awaitTermination(0, TimeUnit.MILLISECONDS)); + } finally { + executor.stop(); + } + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
