[java-shib-shared] 02/05: JSSH-71 Remove the impact of the DestructableComponent Interface
Codeberg
noreply at shibboleth.net
Tue May 26 13:21:48 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/7dface7150b765c95fed661f953300eea64b445b
commit 7dface7150b765c95fed661f953300eea64b445b
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.
---
shib-security/pom.xml | 10 +--
shib-service/pom.xml | 10 +--
.../service/AbstractServiceableComponent.java | 10 ++-
.../service/ReloadableSpringServiceTest.java | 9 +--
shib-support/pom.xml | 4 ++
.../shared/primitive/AnnotationsSupport.java | 78 +++++++++++++++++++++
.../shared/primitive/AnnotationsSupportTest.java | 79 ++++++++++++++++++++++
7 files changed, 183 insertions(+), 17 deletions(-)
diff --git a/shib-security/pom.xml b/shib-security/pom.xml
index 604eef51..07a5c09d 100644
--- a/shib-security/pom.xml
+++ b/shib-security/pom.xml
@@ -59,17 +59,17 @@
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ </dependency>
+
<!-- Provided Dependencies -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>jakarta.annotation</groupId>
- <artifactId>jakarta.annotation-api</artifactId>
- <scope>provided</scope>
- </dependency>
<!-- Runtime Dependencies -->
diff --git a/shib-service/pom.xml b/shib-service/pom.xml
index f7c795b2..681e2284 100644
--- a/shib-service/pom.xml
+++ b/shib-service/pom.xml
@@ -73,17 +73,17 @@
<artifactId>spring-core</artifactId>
</dependency>
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ </dependency>
+
<!-- Provided Dependencies -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
- <dependency>
- <groupId>jakarta.annotation</groupId>
- <artifactId>jakarta.annotation-api</artifactId>
- <scope>provided</scope>
- </dependency>
<!-- Runtime Dependencies -->
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..c781591d 100644
--- a/shib-support/pom.xml
+++ b/shib-support/pom.xml
@@ -29,6 +29,10 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
+ <dependency>
+ <groupId>jakarta.annotation</groupId>
+ <artifactId>jakarta.annotation-api</artifactId>
+ </dependency>
<!-- Provided 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..ba21be49
--- /dev/null
+++ b/shib-support/src/main/java/net/shibboleth/shared/primitive/AnnotationsSupport.java
@@ -0,0 +1,78 @@
+/*
+ * 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 (final 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);
+ }
+ }
+ }
+ }
+ /** Call the {@link @PreDestroy} methods.
+ * @param obj The object to introspect
+ */
+ static public void callPreDestroyAnnotation(@Nullable final Object obj) {
+ callPreDestroyAnnotation(obj, null, null);
+ }
+ /** Mostly for testing - does this object carry a {@link @PreDestroy} annotated
+ * method?
+ * @param obj The object to introspect
+ * @return whether it is tear-downable.
+ */
+ static public boolean hasPreDestroyAnnotation(@Nullable final Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ for (final Method m: obj.getClass().getMethods()) {
+ if (m.getParameterCount() == 0 && m.getAnnotation(PreDestroy.class) != null) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/shib-support/src/test/java/net/shibboleth/shared/primitive/AnnotationsSupportTest.java b/shib-support/src/test/java/net/shibboleth/shared/primitive/AnnotationsSupportTest.java
new file mode 100644
index 00000000..daac8f76
--- /dev/null
+++ b/shib-support/src/test/java/net/shibboleth/shared/primitive/AnnotationsSupportTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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 static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import jakarta.annotation.PreDestroy;
+
+/** Tests for {@link AnnotationsSupport}. */
+public class AnnotationsSupportTest {
+
+ private boolean withCalled;
+ private boolean withParamCalled;
+
+ @BeforeMethod public void reset() {
+ withCalled = false;
+ withParamCalled = false;
+ }
+
+ @Test public void withTest() {
+ final var what = new With();
+ assertTrue(AnnotationsSupport.hasPreDestroyAnnotation(what));
+ AnnotationsSupport.callPreDestroyAnnotation(what);
+ assertTrue(withCalled);
+ assertFalse(withParamCalled);
+ }
+
+ @Test public void withParamTest() {
+ final var what = new WithParam();
+ assertFalse(AnnotationsSupport.hasPreDestroyAnnotation(what));
+ AnnotationsSupport.callPreDestroyAnnotation(what);
+ assertFalse(withCalled);
+ assertFalse(withParamCalled);
+ }
+
+ @Test public void withOutTest() {
+ final var what = new Without();
+ assertFalse(AnnotationsSupport.hasPreDestroyAnnotation(what));
+ AnnotationsSupport.callPreDestroyAnnotation(what);
+ assertFalse(withCalled);
+ assertFalse(withParamCalled);
+ }
+
+ private class With {
+
+ @PreDestroy public void teardown() {
+ withCalled = true;
+ }
+ }
+
+ private class WithParam {
+
+ @PreDestroy public void teardown(final int param) {
+ withParamCalled = true;
+ }
+ }
+
+ private class Without {
+
+ public void teardown() {
+ }
+ }
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list