[java-shib-shared] 02/05: JSSH-71 Remove the impact of the DestructableComponent Interface

Codeberg noreply at shibboleth.net
Mon May 25 14:43:07 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/JSSH-71
in repository java-shib-shared.

View the commit online:
https://codeberg.org/Shibboleth/java-shib-shared/commit/fa1a16eed39bf2741cbc6a776c44ebe578c8d8f5

commit fa1a16eed39bf2741cbc6a776c44ebe578c8d8f5
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Sat May 23 14:35:12 2026 +0100

    JSSH-71 Remove the impact of the DestructableComponent Interface
    
    https://shibboleth.atlassian.net/browse/JSSH-71
    
    Add explicit code in our Service model to call @PreDestroy method if
    the ServiceableComponent has one.
---
 .../service/AbstractServiceableComponent.java      | 10 ++--
 .../service/ReloadableSpringServiceTest.java       |  9 ++--
 shib-support/pom.xml                               |  5 ++
 .../shared/primitive/AnnotationsSupport.java       | 56 ++++++++++++++++++++++
 4 files changed, 73 insertions(+), 7 deletions(-)

diff --git a/shib-service/src/main/java/net/shibboleth/shared/spring/service/AbstractServiceableComponent.java b/shib-service/src/main/java/net/shibboleth/shared/spring/service/AbstractServiceableComponent.java
index 8f4cd929..a4e8780b 100644
--- a/shib-service/src/main/java/net/shibboleth/shared/spring/service/AbstractServiceableComponent.java
+++ b/shib-service/src/main/java/net/shibboleth/shared/spring/service/AbstractServiceableComponent.java
@@ -20,15 +20,14 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.slf4j.Logger;
-
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.context.ConfigurableApplicationContext;
 
 import jakarta.annotation.PreDestroy;
-
 import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.AnnotationsSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.service.ServiceableComponent;
 
@@ -125,7 +124,12 @@ public abstract class AbstractServiceableComponent<T> extends AbstractIdentifiab
         }
         // If we were not created by spring we need to do the destroy of ourself.
         // Note that we will end up being called here but will fall out at the top.
-        destroy();
+        //
+        // We do this by looking for the preDetroy annotation on one of our methods).
+        // Worth of note - as opposed to the spring case this will only tearn down us
+        // (not everyone child that needs torn down).  Use spring or add the one off
+        //  yourself.
+        AnnotationsSupport.callPreDestroyAnnotation(this, getId(), log);
     }
 
     /** {@inheritDoc} */
diff --git a/shib-service/src/test/java/net/shibboleth/shared/spring/service/ReloadableSpringServiceTest.java b/shib-service/src/test/java/net/shibboleth/shared/spring/service/ReloadableSpringServiceTest.java
index bba41854..4a825222 100644
--- a/shib-service/src/test/java/net/shibboleth/shared/spring/service/ReloadableSpringServiceTest.java
+++ b/shib-service/src/test/java/net/shibboleth/shared/spring/service/ReloadableSpringServiceTest.java
@@ -26,6 +26,7 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.AnnotationsSupport;
 import net.shibboleth.shared.service.ServiceException;
 import net.shibboleth.shared.service.ServiceableComponent;
 import net.shibboleth.shared.spring.util.ApplicationContextBuilder;
@@ -117,7 +118,7 @@ public class ReloadableSpringServiceTest {
 
         Assert.assertEquals(serviceableComponent.getComponent().getTheValue(), "Two");
         serviceableComponent.unpinComponent();
-        service.destroy();
+        AnnotationsSupport.callPreDestroyAnnotation(service, null, null);
         
         deleteFile();
     }
@@ -177,8 +178,8 @@ public class ReloadableSpringServiceTest {
             Thread.sleep(RELOAD_DELAY.toMillis());
             count--;
         }
+        AnnotationsSupport.callPreDestroyAnnotation(service, null, null);
         Assert.assertTrue(component.destroyed, "After 7 second initial component has still not be destroyed");
-        service.destroy();
         deleteFile();
     }
 
@@ -218,7 +219,7 @@ public class ReloadableSpringServiceTest {
             // OK
         }
 
-        service.destroy();
+        AnnotationsSupport.callPreDestroyAnnotation(service, null, null);
         deleteFile();
     }
     @Test public void testNotFailFast() throws IOException, InterruptedException, ComponentInitializationException {
@@ -260,7 +261,7 @@ public class ReloadableSpringServiceTest {
 
         Assert.assertFalse(component.destroyed);
         serviceableComponent.unpinComponent();
-        service.destroy();
+        AnnotationsSupport.callPreDestroyAnnotation(service, null, null);
 
         count = 70;
         while (count > 0 && !component.destroyed) {
diff --git a/shib-support/pom.xml b/shib-support/pom.xml
index ce548295..b405e12d 100644
--- a/shib-support/pom.xml
+++ b/shib-support/pom.xml
@@ -31,6 +31,11 @@
         </dependency>
 
         <!-- Provided Dependencies -->
+        <dependency>
+            <groupId>jakarta.annotation</groupId>
+            <artifactId>jakarta.annotation-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
 
         <!-- Runtime Dependencies -->
 
diff --git a/shib-support/src/main/java/net/shibboleth/shared/primitive/AnnotationsSupport.java b/shib-support/src/main/java/net/shibboleth/shared/primitive/AnnotationsSupport.java
new file mode 100644
index 00000000..77643f1a
--- /dev/null
+++ b/shib-support/src/main/java/net/shibboleth/shared/primitive/AnnotationsSupport.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed 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 net.shibboleth.shared.primitive;
+
+import java.lang.reflect.Method;
+
+import org.slf4j.Logger;
+
+import jakarta.annotation.Nullable;
+import jakarta.annotation.PreDestroy;
+
+/**
+ * Static methods to work with annotations.
+ */
+public final class AnnotationsSupport {
+
+    /** Call the {@link @PreDestroy} methods.
+     * @param obj The object to introspect
+     * @param id The id of the object
+     * @param log the logger to use
+     */
+    static public void callPreDestroyAnnotation(@Nullable final Object obj, @Nullable final String id, @Nullable final Logger log) {
+        
+        if (obj == null) {
+            return;
+        }
+        for (Method m: obj.getClass().getMethods()) {
+            if (m.getParameterCount() == 0 && m.getAnnotation(PreDestroy.class) != null) {
+                if (log != null) {
+                    log.debug("{}: found a PreDestroyMethod {}", id, m);
+                }
+                try {
+                    m.invoke(obj);
+                } catch (final Exception e) {
+                    Logger theLog = log;
+                    if (theLog == null) {
+                        theLog = LoggerFactory.getLogger(AnnotationsSupport.class);
+                    }
+                    theLog.error("{}: Failed invoking {}", id, m, e);
+                }
+            }
+        }
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list