This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/9.0.x by this push:
     new d3d4ac5c66 Review "Keep monitor, heartbeat and JMX alive across 
partial ... stops"
d3d4ac5c66 is described below

commit d3d4ac5c66927ead10543f9ad334f7a287d62f3d
Author: Mark Thomas <[email protected]>
AuthorDate: Wed Oct 21 11:23:25 2026 +0100

    Review "Keep monitor, heartbeat and JMX alive across partial ... stops"
    
    Clean-up TLS if all services have stopped
    Keep channel on partial stop for Interceptors
---
 .../tribes/group/ChannelInterceptorBase.java       | 32 ++++++++++++++++++----
 .../tribes/group/TestGroupChannelStartStop.java    | 18 ++++++++++++
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/java/org/apache/catalina/tribes/group/ChannelInterceptorBase.java 
b/java/org/apache/catalina/tribes/group/ChannelInterceptorBase.java
index c535233675..18e83ac2b7 100644
--- a/java/org/apache/catalina/tribes/group/ChannelInterceptorBase.java
+++ b/java/org/apache/catalina/tribes/group/ChannelInterceptorBase.java
@@ -187,14 +187,34 @@ public abstract class ChannelInterceptorBase implements 
ChannelInterceptor {
         if (getNext() != null) {
             getNext().stop(svc);
         }
-        if (oname != null) {
-            JmxRegistry jmxRegistry = JmxRegistry.getRegistry(channel);
-            if (jmxRegistry != null) {
-                jmxRegistry.unregisterJmx(oname);
+        // Only release the channel and the JMX registration once all services 
have been stopped. A partial stop leaves
+        // services running that still use them.
+        if (isFullyStopped()) {
+            if (oname != null) {
+                JmxRegistry jmxRegistry = JmxRegistry.getRegistry(channel);
+                if (jmxRegistry != null) {
+                    jmxRegistry.unregisterJmx(oname);
+                }
+                oname = null;
             }
-            oname = null;
+            channel = null;
         }
-        channel = null;
+    }
+
+    /**
+     * Determine if all services of the coordinator at the end of the 
interceptor stack have been stopped.
+     *
+     * @return {@code true} if no service is started, or if there is no 
coordinator after this interceptor
+     */
+    private boolean isFullyStopped() {
+        ChannelInterceptor interceptor = getNext();
+        while (interceptor != null) {
+            if (interceptor instanceof ChannelCoordinator) {
+                return ((ChannelCoordinator) interceptor).getStartLevel() == 0;
+            }
+            interceptor = interceptor.getNext();
+        }
+        return true;
     }
 
     @Override
diff --git 
a/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java 
b/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
index cd6f2765a4..1dcf65275b 100644
--- a/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
+++ b/test/org/apache/catalina/tribes/group/TestGroupChannelStartStop.java
@@ -16,6 +16,7 @@
  */
 package org.apache.catalina.tribes.group;
 
+import java.util.Iterator;
 import java.util.concurrent.ScheduledFuture;
 
 import org.junit.After;
@@ -24,6 +25,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import org.apache.catalina.tribes.Channel;
+import org.apache.catalina.tribes.ChannelInterceptor;
 import org.apache.catalina.tribes.membership.McastService;
 import org.apache.catalina.tribes.transport.ReceiverBase;
 import org.apache.catalina.tribes.transport.ReplicationTransmitter;
@@ -166,6 +168,22 @@ public class TestGroupChannelStartStop {
         Assert.assertTrue(heartbeat.isCancelled());
     }
 
+    @Test
+    public void testPartialStopKeepsInterceptorChannel() throws Exception {
+        channel.start(Channel.DEFAULT);
+        channel.stop(Channel.SND_RX_SEQ);
+        // services are still running, the interceptors must still be attached 
to the channel
+        for (Iterator<ChannelInterceptor> it = channel.getInterceptors(); 
it.hasNext();) {
+            ChannelInterceptor interceptor = it.next();
+            Assert.assertSame(interceptor.getClass().getName(), channel, 
interceptor.getChannel());
+        }
+        channel.stop(Channel.SND_TX_SEQ | Channel.MBR_RX_SEQ | 
Channel.MBR_TX_SEQ);
+        for (Iterator<ChannelInterceptor> it = channel.getInterceptors(); 
it.hasNext();) {
+            ChannelInterceptor interceptor = it.next();
+            Assert.assertNull(interceptor.getClass().getName(), 
interceptor.getChannel());
+        }
+    }
+
     @Test
     public void testOverlappingPartialStart() throws Exception {
         // start one service, then start everything: the already


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to