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");