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

davsclaus pushed a commit to branch init-destroy
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 43ed04d8b77bc8593a175f315fbad7756a050368
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Thu Aug 29 13:30:40 2024 +0200

    CAMEL-21140: camel-core - Add init/destroy method support for registry bind
---
 .../main/java/org/apache/camel/spi/Registry.java   | 33 ++++++++++++++++
 .../org/apache/camel/support/DefaultRegistry.java  | 45 ++++++++++++++++++++++
 .../org/apache/camel/support/SimpleRegistry.java   |  7 ++++
 3 files changed, 85 insertions(+)

diff --git a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
index 12dd42208e7..be0d24b4e7e 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/Registry.java
@@ -41,6 +41,23 @@ public interface Registry extends BeanRepository {
         }
     }
 
+    /**
+     * Binds the bean to the repository (if possible).
+     *
+     * If the bean is {@link CamelContextAware} then the registry will 
automatic inject the context if possible.
+     *
+     * @param  id                    the id of the bean
+     * @param  bean                  the bean
+     * @param  initMethod            optional init method (invoked at bind)
+     * @param  destroyMethod         optional destroy method (invoked at 
unbind or stopping Camel)
+     * @throws RuntimeCamelException is thrown if binding is not possible
+     */
+    default void bind(String id, Object bean, String initMethod, String 
destroyMethod) throws RuntimeCamelException {
+        if (bean != null) {
+            bind(id, bean.getClass(), bean, initMethod, destroyMethod);
+        }
+    }
+
     /**
      * Binds the bean to the repository (if possible).
      * <p/>
@@ -55,6 +72,22 @@ public interface Registry extends BeanRepository {
      */
     void bind(String id, Class<?> type, Object bean) throws 
RuntimeCamelException;
 
+    /**
+     * Binds the bean to the repository (if possible).
+     * <p/>
+     * Binding by id and type allows to bind multiple entries with the same id 
but with different type.
+     *
+     * If the bean is {@link CamelContextAware} then the registry will 
automatic inject the context if possible.
+     *
+     * @param  id                    the id of the bean
+     * @param  type                  the type of the bean to associate the 
binding
+     * @param  bean                  the bean
+     * @param  initMethod            optional init method (invoked at bind)
+     * @param  destroyMethod         optional destroy method (invoked at 
unbind or stopping Camel)
+     * @throws RuntimeCamelException is thrown if binding is not possible
+     */
+    void bind(String id, Class<?> type, Object bean, String initMethod, String 
destroyMethod) throws RuntimeCamelException;
+
     /**
      * Binds the bean (via a supplier) to the repository (if possible).
      * <p/>
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
index 89181a36964..521762ea480 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
@@ -37,7 +37,10 @@ import org.apache.camel.spi.Registry;
 import org.apache.camel.support.service.ServiceHelper;
 import org.apache.camel.support.service.ServiceSupport;
 import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.KeyValueHolder;
 import org.apache.camel.util.function.Suppliers;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * The default {@link Registry} which supports using a given first-choice 
repository to lookup the beans, such as
@@ -49,12 +52,14 @@ import org.apache.camel.util.function.Suppliers;
  */
 public class DefaultRegistry extends ServiceSupport implements Registry, 
LocalBeanRepositoryAware, CamelContextAware {
 
+    private static final Logger LOG = 
LoggerFactory.getLogger(DefaultRegistry.class);
     protected CamelContext camelContext;
     protected final ThreadLocal<BeanRepository> localRepository = new 
ThreadLocal<>();
     protected volatile boolean localRepositoryEnabled; // flag to keep track 
if local is in use or not
     protected List<BeanRepository> repositories;
     protected Registry fallbackRegistry = new SimpleRegistry();
     protected Registry supplierRegistry = new SupplierRegistry();
+    protected final Map<String, KeyValueHolder<Object, String>> beansToDestroy 
= new LinkedHashMap<>();
 
     /**
      * Creates a default registry that uses {@link SimpleRegistry} as the 
fallback registry. The fallback registry can
@@ -182,6 +187,26 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, LocalBe
         }
     }
 
+    @Override
+    public void bind(String id, Class<?> type, Object bean, String initMethod, 
String destroyMethod)
+            throws RuntimeCamelException {
+        if (bean != null) {
+            // automatic inject camel context in bean if its aware
+            CamelContextAware.trySetCamelContext(bean, camelContext);
+            if (initMethod != null) {
+                try {
+                    
org.apache.camel.support.ObjectHelper.invokeMethodSafe(initMethod, bean);
+                } catch (Exception e) {
+                    throw RuntimeCamelException.wrapRuntimeCamelException(e);
+                }
+            }
+            fallbackRegistry.bind(id, type, bean);
+            if (destroyMethod != null) {
+                beansToDestroy.put(id, new KeyValueHolder<>(bean, 
destroyMethod));
+            }
+        }
+    }
+
     @Override
     public void bind(String id, Class<?> type, Supplier<Object> bean) throws 
RuntimeCamelException {
         if (bean != null) {
@@ -201,6 +226,21 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, LocalBe
     public void unbind(String id) {
         supplierRegistry.unbind(id);
         fallbackRegistry.unbind(id);
+        destroyBean(id, true);
+    }
+
+    protected void destroyBean(String name, boolean remove) {
+        var holder = remove ? beansToDestroy.remove(name) : 
beansToDestroy.get(name);
+        if (holder != null) {
+            String destroyMethod = holder.getValue();
+            Object target = holder.getKey();
+            try {
+                
org.apache.camel.support.ObjectHelper.invokeMethodSafe(destroyMethod, target);
+            } catch (Exception e) {
+                LOG.warn("Error invoking destroy method: {} on bean: {} due 
to: {}. This exception is ignored.",
+                        destroyMethod, target, e.getMessage(), e);
+            }
+        }
     }
 
     @Override
@@ -391,5 +431,10 @@ public class DefaultRegistry extends ServiceSupport 
implements Registry, LocalBe
             IOHelper.close(closeable);
         }
         ServiceHelper.stopAndShutdownServices(supplierRegistry, 
fallbackRegistry);
+        // beans should trigger destroy methods on shutdown
+        for (String name : beansToDestroy.keySet()) {
+            destroyBean(name, false);
+        }
+        beansToDestroy.clear();
     }
 }
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java 
b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
index f3541dc6699..0018f9937a5 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/SimpleRegistry.java
@@ -25,6 +25,7 @@ import java.util.Set;
 import java.util.function.Supplier;
 
 import org.apache.camel.NoSuchBeanException;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.spi.Registry;
 
 /**
@@ -106,6 +107,12 @@ public class SimpleRegistry extends LinkedHashMap<String, 
Map<Class<?>, Object>>
         }
     }
 
+    @Override
+    public void bind(String id, Class<?> type, Object bean, String initMethod, 
String destroyMethod)
+            throws RuntimeCamelException {
+        throw new UnsupportedOperationException("Use DefaultRegistry");
+    }
+
     @Override
     public void bind(String id, Class<?> type, Supplier<Object> bean) {
         throw new UnsupportedOperationException("Use SupplierRegistry");

Reply via email to