You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/01/11 08:56:54 UTC

[camel] branch main updated: CAMEL-15724 light rework of CDI module to make it using CDI 2 API and have jta an… (#6705)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new fe1975d  CAMEL-15724 light rework of CDI module to make it using CDI 2 API and have jta an… (#6705)
fe1975d is described below

commit fe1975dda8eb8b7cdc70f89901af73f46115e695
Author: Romain Manni-Bucau <rm...@gmail.com>
AuthorDate: Tue Jan 11 09:54:44 2022 +0100

    CAMEL-15724 light rework of CDI module to make it using CDI 2 API and have jta an… (#6705)
    
    * rebase
    
    * CdiCamelFactory checkstyle fix
    
    * typo for txmgr lookup
    
    * review comment about catch
    
    * fixing com.arjuna.ats.jta.TransactionManager.transactionManager name
---
 .../java/org/apache/camel/cdi/CdiRouteBuilder.java | 18 +++-
 .../TransactionalJtaTransactionPolicy.java         | 40 +++++++++
 components/camel-cdi-main/pom.xml                  |  7 --
 .../src/main/java/org/apache/camel/cdi/Main.java   | 63 ++++++++++----
 components/camel-cdi/pom.xml                       |  8 ++
 .../org/apache/camel/cdi/CamelContextProducer.java |  8 +-
 .../apache/camel/cdi/CdiCamelBeanRepository.java   |  6 +-
 .../org/apache/camel/cdi/CdiCamelExtension.java    | 96 ++++++++++++++++++----
 .../java/org/apache/camel/cdi/CdiCamelFactory.java | 48 ++---------
 .../java/org/apache/camel/cdi/CdiSpiHelper.java    |  8 +-
 .../main/java/org/apache/camel/cdi/Startup.java    |  3 +
 .../src/main/java/org/apache/camel/cdi/Uri.java    |  1 -
 .../org/apache/camel/cdi/XmlCdiBeanFactory.java    | 24 +++---
 .../CdiJtaTransactionErrorHandlerBuilder.java}     | 16 +---
 .../CdiTransactionalErrorHandlerBuilder.java}      | 22 +++--
 15 files changed, 243 insertions(+), 125 deletions(-)

diff --git a/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/CdiRouteBuilder.java b/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/CdiRouteBuilder.java
index f5d7322..a695b0d 100644
--- a/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/CdiRouteBuilder.java
+++ b/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/CdiRouteBuilder.java
@@ -16,11 +16,15 @@
  */
 package org.apache.camel.cdi;
 
+import org.apache.camel.builder.DefaultErrorHandlerBuilder;
 import org.apache.camel.builder.RouteBuilder;
-import org.apache.camel.jta.JtaTransactionErrorHandlerBuilder;
+import org.apache.camel.cdi.transaction.CdiTransactionalErrorHandlerBuilder;
 
 /**
- * An extension of the {@link RouteBuilder} to provide some additional helper methods.
+ * An extension of the {@link RouteBuilder} to provide some additional JTA helper methods.
+ *
+ * You never really need it since {@code transactionErrorHandler()} can be replaced by
+ * {@code new JtaTransactionErrorHandlerBuilder()}.
  */
 public abstract class CdiRouteBuilder extends RouteBuilder {
 
@@ -29,7 +33,13 @@ public abstract class CdiRouteBuilder extends RouteBuilder {
      *
      * @return the created error handler
      */
-    public JtaTransactionErrorHandlerBuilder transactionErrorHandler() {
-        return new JtaTransactionErrorHandlerBuilder();
+    // IMPORTANT: don't leak CdiJtaTransactionErrorHandlerBuilder in the signature,
+    //            only things not depending on camel-jta
+    public <T extends DefaultErrorHandlerBuilder & CdiTransactionalErrorHandlerBuilder> T transactionErrorHandler() {
+        try {
+            return (T) new org.apache.camel.cdi.transaction.CdiJtaTransactionErrorHandlerBuilder();
+        } catch (final NoClassDefFoundError e) {
+            throw new IllegalStateException("JTA not available");
+        }
     }
 }
diff --git a/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/transaction/TransactionalJtaTransactionPolicy.java b/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/transaction/TransactionalJtaTransactionPolicy.java
index 680cc3a..2f57135 100644
--- a/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/transaction/TransactionalJtaTransactionPolicy.java
+++ b/components/camel-cdi-jta/src/main/java/org/apache/camel/cdi/transaction/TransactionalJtaTransactionPolicy.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.cdi.transaction;
 
+import java.util.Objects;
+import java.util.stream.Stream;
+
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
 import javax.transaction.HeuristicMixedException;
@@ -31,6 +34,8 @@ import org.apache.camel.jta.JtaTransactionPolicy;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.util.stream.Collectors.toList;
+
 /**
  * Helper methods for transaction handling
  *
@@ -47,6 +52,13 @@ public abstract class TransactionalJtaTransactionPolicy extends JtaTransactionPo
             "java:pm/TransactionManager",
             "java:/TransactionManager"
     };
+    private static final String[] METHODS = new String[] {
+            "org.openejb.OpenEJB.getTransactionManager",
+            "com.arjuna.ats.jta.TransactionManager.transactionManager",
+            "com.bluestone.jta.SaTransactionManagerFactory.SaGetTransactionManager",
+            "com.sun.jts.jta.TransactionManagerImpl.getTransactionManagerImpl",
+            "com.inprise.visitransact.jta.TransactionManagerImpl.getTransactionManagerImpl",
+    };
 
     protected TransactionManager transactionManager;
 
@@ -69,6 +81,7 @@ public abstract class TransactionalJtaTransactionPolicy extends JtaTransactionPo
         }
     }
 
+    // todo: see @openjpa:openjpa-kernel/src/main/java/org/apache/openjpa/ee/AutomaticManagedRuntime.java
     private TransactionManager lookupTransactionManager() {
         TransactionManager tm;
         for (String jndiName : TRANSACTION_MANAGER_JNDI_NAMES) {
@@ -81,6 +94,33 @@ public abstract class TransactionalJtaTransactionPolicy extends JtaTransactionPo
                 LOG.debug("No JTA TransactionManager found at JNDI location [{}]", jndiName, ex);
             }
         }
+        var loaders = Stream.of(Thread.currentThread().getContextClassLoader(), getClass().getClassLoader())
+                .filter(Objects::nonNull)
+                .distinct()
+                .collect(toList());
+        for (String method : METHODS) {
+            final int sep = method.lastIndexOf('.');
+            try {
+                Class<?> clazz = null;
+                for (final var loader : loaders) {
+                    try {
+                        clazz = loader.loadClass(method.substring(0, sep));
+                    } catch (final NoClassDefFoundError | ClassNotFoundException cnfe) {
+                        // continue
+                    }
+                }
+                if (clazz != null) {
+                    final var getter = clazz.getDeclaredMethod(method.substring(sep + 1));
+                    getter.setAccessible(true);
+                    final var txMgr = (TransactionManager) getter.invoke(null);
+                    if (txMgr != null) {
+                        return txMgr;
+                    }
+                }
+            } catch (final RuntimeException | ReflectiveOperationException | NoClassDefFoundError t) {
+                // no-op
+            }
+        }
         LOG.warn("Could not find the transaction manager through any of following locations: {}",
                 String.join(",", TRANSACTION_MANAGER_JNDI_NAMES));
         return null;
diff --git a/components/camel-cdi-main/pom.xml b/components/camel-cdi-main/pom.xml
index ef49c25..d9f8742 100644
--- a/components/camel-cdi-main/pom.xml
+++ b/components/camel-cdi-main/pom.xml
@@ -49,16 +49,9 @@
         </dependency>
 
         <dependency>
-            <groupId>org.apache.deltaspike.cdictrl</groupId>
-            <artifactId>deltaspike-cdictrl-api</artifactId>
-            <version>${deltaspike-version}</version>
-        </dependency>
-        <dependency>
             <groupId>javax.enterprise</groupId>
             <artifactId>cdi-api</artifactId>
             <version>${cdi-api-2.0-version}</version>
         </dependency>
-
     </dependencies>
-
 </project>
diff --git a/components/camel-cdi-main/src/main/java/org/apache/camel/cdi/Main.java b/components/camel-cdi-main/src/main/java/org/apache/camel/cdi/Main.java
index aed8e28..bfb8b21 100644
--- a/components/camel-cdi-main/src/main/java/org/apache/camel/cdi/Main.java
+++ b/components/camel-cdi-main/src/main/java/org/apache/camel/cdi/Main.java
@@ -19,21 +19,23 @@ package org.apache.camel.cdi;
 import java.util.Map;
 import java.util.Set;
 
+import javax.enterprise.context.control.RequestContextController;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.UnsatisfiedResolutionException;
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.main.MainCommandLineSupport;
-import org.apache.deltaspike.cdise.api.CdiContainer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.toMap;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
 import static org.apache.camel.cdi.BeanManagerHelper.getReference;
-import static org.apache.deltaspike.cdise.api.CdiContainerLoader.getCdiContainer;
 
 /**
  * Camel CDI boot integration. Allows Camel and CDI to be booted up on the command line as a JVM process.
@@ -45,19 +47,27 @@ public class Main extends MainCommandLineSupport {
         // Since version 2.3.0.Final and WELD-1915, Weld SE registers a shutdown hook that conflicts
         // with Camel main support. See WELD-2051. The system property above is available starting
         // Weld 2.3.1.Final to deactivate the registration of the shutdown hook.
-        System.setProperty("org.jboss.weld.se.shutdownHook", String.valueOf(Boolean.FALSE));
+        System.setProperty(
+                "org.jboss.weld.se.shutdownHook",
+                System.getProperty("org.jboss.weld.se.shutdownHook", String.valueOf(Boolean.FALSE)));
     }
 
     private static final Logger LOG = LoggerFactory.getLogger(Main.class);
 
     private static Main instance;
 
-    private CdiContainer cdiContainer;
+    private boolean startContexts = true;
+    private SeContainer cdiContainer;
+    private Runnable stopHook;
 
     public static void main(String... args) throws Exception {
         Main main = new Main();
         instance = main;
-        main.run(args);
+        try {
+            main.run(args);
+        } finally {
+            instance = null; // ensure main can be reused even if unlikely
+        }
     }
 
     /**
@@ -69,6 +79,11 @@ public class Main extends MainCommandLineSupport {
         return instance;
     }
 
+    public Main setStartContexts(final boolean startContexts) {
+        this.startContexts = startContexts;
+        return this;
+    }
+
     @Override
     protected ProducerTemplate findOrCreateCamelTemplate() {
         if (getCamelContext() == null) {
@@ -80,7 +95,7 @@ public class Main extends MainCommandLineSupport {
     @Override
     protected CamelContext createCamelContext() {
         BeanManager manager = cdiContainer.getBeanManager();
-        Map<String, CamelContext> camels = manager.getBeans(CamelContext.class, ANY).stream()
+        Map<String, CamelContext> camels = manager.getBeans(CamelContext.class, Any.Literal.INSTANCE).stream()
                 .map(bean -> getReference(manager, CamelContext.class, bean))
                 .collect(toMap(CamelContext::getName, identity()));
         if (camels.size() > 1) {
@@ -94,11 +109,9 @@ public class Main extends MainCommandLineSupport {
 
     @Override
     protected void doStart() throws Exception {
-        // TODO: Use standard CDI Java SE support when CDI 2.0 becomes a prerequisite
-        CdiContainer container = getCdiContainer();
-        container.boot();
-        container.getContextControl().startContexts();
-        cdiContainer = container;
+        final var container = SeContainerInitializer.newInstance();
+        cdiContainer = container.initialize();
+        startContexts();
         super.doStart();
         initCamelContext();
         warnIfNoCamelFound();
@@ -109,9 +122,28 @@ public class Main extends MainCommandLineSupport {
         // camel-cdi has already initialized and start CamelContext so we should not do this again
     }
 
+    protected void startContexts() {
+        if (!startContexts) {
+            LOG.debug("Context are not automatically started");
+            return;
+        }
+        try {
+            final var requestContextController = cdiContainer.select(RequestContextController.class).get();
+            if (requestContextController.activate()) {
+                LOG.debug("Request context started");
+                stopHook = requestContextController::deactivate;
+            } else {
+                LOG.debug("Request context already started");
+            }
+        } catch (final UnsatisfiedResolutionException e) {
+            // ignore, start without starting the contexts, will not impact much camel normally
+            LOG.debug("Didn't start request scope", e);
+        }
+    }
+
     private void warnIfNoCamelFound() {
         BeanManager manager = cdiContainer.getBeanManager();
-        Set<Bean<?>> contexts = manager.getBeans(CamelContext.class, ANY);
+        Set<Bean<?>> contexts = manager.getBeans(CamelContext.class, Any.Literal.INSTANCE);
         // Warn if there is no CDI Camel contexts
         if (contexts.isEmpty()) {
             LOG.warn("Camel CDI main has started with no Camel context!");
@@ -121,8 +153,11 @@ public class Main extends MainCommandLineSupport {
     @Override
     protected void doStop() throws Exception {
         super.doStop();
+        if (stopHook != null) {
+            stopHook.run();
+        }
         if (cdiContainer != null) {
-            cdiContainer.shutdown();
+            cdiContainer.close();
         }
     }
 }
diff --git a/components/camel-cdi/pom.xml b/components/camel-cdi/pom.xml
index d9722d3..8afad4d 100644
--- a/components/camel-cdi/pom.xml
+++ b/components/camel-cdi/pom.xml
@@ -73,7 +73,15 @@
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
+            <artifactId>camel-jta</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
             <artifactId>camel-mock</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
         </dependency>
 
         <!-- deprecated xml -->
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CamelContextProducer.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CamelContextProducer.java
index 553a68d..68b1958 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CamelContextProducer.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CamelContextProducer.java
@@ -20,6 +20,8 @@ import java.lang.annotation.Annotation;
 import java.util.Set;
 
 import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
 import javax.enterprise.inject.InjectionException;
 import javax.enterprise.inject.Vetoed;
 import javax.enterprise.inject.spi.Annotated;
@@ -41,11 +43,9 @@ import org.slf4j.LoggerFactory;
 import static java.beans.Introspector.decapitalize;
 import static java.util.stream.Collectors.toSet;
 import static org.apache.camel.RuntimeCamelException.wrapRuntimeCamelException;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
 import static org.apache.camel.cdi.CdiSpiHelper.createCamelContextWithTCCL;
 import static org.apache.camel.cdi.CdiSpiHelper.getRawType;
 import static org.apache.camel.cdi.CdiSpiHelper.isAnnotationType;
-import static org.apache.camel.cdi.DefaultLiteral.DEFAULT;
 
 @Vetoed
 final class CamelContextProducer<T extends CamelContext> extends DelegateProducer<T> {
@@ -90,9 +90,9 @@ final class CamelContextProducer<T extends CamelContext> extends DelegateProduce
                 .filter(isAnnotationType(Named.class).negate()
                         .and(q -> manager.isQualifier(q.annotationType())))
                 .collect(toSet());
-        qualifiers.add(ANY);
+        qualifiers.add(Any.Literal.INSTANCE);
         if (qualifiers.size() == 1) {
-            qualifiers.add(DEFAULT);
+            qualifiers.add(Default.Literal.INSTANCE);
         }
         qualifiers.retainAll(extension.getObserverEvents());
         if (!qualifiers.isEmpty()) {
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelBeanRepository.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelBeanRepository.java
index cac01f5..8fc7cc0 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelBeanRepository.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelBeanRepository.java
@@ -19,6 +19,7 @@ package org.apache.camel.cdi;
 import java.util.Map;
 import java.util.Set;
 
+import javax.enterprise.inject.Any;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
 
@@ -28,7 +29,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static java.util.stream.Collectors.toMap;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
 import static org.apache.camel.cdi.BeanManagerHelper.getReference;
 import static org.apache.camel.cdi.BeanManagerHelper.getReferenceByName;
 import static org.apache.camel.cdi.BeanManagerHelper.getReferencesByType;
@@ -72,7 +72,7 @@ final class CdiCamelBeanRepository implements BeanRepository {
     public <T> Map<String, T> findByTypeWithName(Class<T> type) {
         notNull(type, "type");
         logger.trace("Looking up named beans of type [{}]", type);
-        return manager.getBeans(type, ANY).stream()
+        return manager.getBeans(type, Any.Literal.INSTANCE).stream()
                 .filter(bean -> bean.getName() != null)
                 .collect(toMap(Bean::getName, bean -> getReference(manager, type, bean)));
     }
@@ -81,7 +81,7 @@ final class CdiCamelBeanRepository implements BeanRepository {
     public <T> Set<T> findByType(Class<T> type) {
         notNull(type, "type");
         logger.trace("Looking up beans of type [{}]", type);
-        return getReferencesByType(manager, type, ANY);
+        return getReferencesByType(manager, type, Any.Literal.INSTANCE);
     }
 
 }
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelExtension.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelExtension.java
index f766053..af84376 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelExtension.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelExtension.java
@@ -26,11 +26,15 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
 import java.util.stream.Stream;
 
+import javax.enterprise.context.Dependent;
 import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Default;
 import javax.enterprise.inject.InjectionException;
+import javax.enterprise.inject.Instance;
 import javax.enterprise.inject.Produces;
 import javax.enterprise.inject.spi.AfterBeanDiscovery;
 import javax.enterprise.inject.spi.AfterDeploymentValidation;
@@ -47,6 +51,7 @@ import javax.enterprise.inject.spi.ProcessObserverMethod;
 import javax.enterprise.inject.spi.ProcessProducer;
 import javax.enterprise.inject.spi.ProcessProducerField;
 import javax.enterprise.inject.spi.ProcessProducerMethod;
+import javax.enterprise.inject.spi.configurator.BeanConfigurator;
 import javax.inject.Named;
 
 import org.apache.camel.BeanInject;
@@ -72,22 +77,23 @@ import org.apache.camel.spi.CamelEvent;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static java.lang.ClassLoader.getSystemClassLoader;
 import static java.util.Collections.newSetFromMap;
 import static java.util.function.Predicate.isEqual;
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toSet;
 import static java.util.stream.Stream.concat;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
 import static org.apache.camel.cdi.ApplicationScopedLiteral.APPLICATION_SCOPED;
 import static org.apache.camel.cdi.BeanManagerHelper.getReference;
 import static org.apache.camel.cdi.BeanManagerHelper.getReferencesByType;
+import static org.apache.camel.cdi.CdiCamelFactory.getQualifierByType;
+import static org.apache.camel.cdi.CdiCamelFactory.selectContext;
 import static org.apache.camel.cdi.CdiEventEndpoint.eventEndpointUri;
 import static org.apache.camel.cdi.CdiSpiHelper.getQualifiers;
 import static org.apache.camel.cdi.CdiSpiHelper.getRawType;
 import static org.apache.camel.cdi.CdiSpiHelper.hasAnnotation;
 import static org.apache.camel.cdi.CdiSpiHelper.hasType;
 import static org.apache.camel.cdi.CdiSpiHelper.isAnnotationType;
-import static org.apache.camel.cdi.DefaultLiteral.DEFAULT;
 import static org.apache.camel.cdi.Excluded.EXCLUDED;
 import static org.apache.camel.cdi.ResourceHelper.getResource;
 import static org.apache.camel.cdi.Startup.Literal.STARTUP;
@@ -210,10 +216,10 @@ public class CdiCamelExtension implements Extension {
         if (type instanceof Class && CamelEvent.class.isAssignableFrom(Class.class.cast(type))) {
             Set<Annotation> qualifiers = pom.getObserverMethod().getObservedQualifiers();
             if (qualifiers.isEmpty()) {
-                eventQualifiers.add(ANY);
+                eventQualifiers.add(Any.Literal.INSTANCE);
             } else if (qualifiers.size() == 1 && qualifiers.stream()
                     .anyMatch(isAnnotationType(Named.class))) {
-                eventQualifiers.add(DEFAULT);
+                eventQualifiers.add(Default.Literal.INSTANCE);
             } else {
                 eventQualifiers.addAll(qualifiers);
             }
@@ -283,14 +289,15 @@ public class CdiCamelExtension implements Extension {
 
         if (contexts.isEmpty() && shouldDeployDefaultCamelContext(allBeans)) {
             // Add @Default Camel context bean if any
-            extraBeans.add(camelContextBean(manager, null, ANY, DEFAULT, APPLICATION_SCOPED));
+            extraBeans.add(camelContextBean(
+                    manager, null, Any.Literal.INSTANCE, Default.Literal.INSTANCE, APPLICATION_SCOPED));
         } else if (contexts.size() == 1) {
             // Add the @Default qualifier if there is only one Camel context bean
             Bean<?> context = contexts.iterator().next();
-            if (!context.getQualifiers().contains(DEFAULT)) {
+            if (!context.getQualifiers().contains(Default.Literal.INSTANCE)) {
                 // Only decorate if that's a programmatic bean
                 if (context instanceof SyntheticBean) {
-                    ((SyntheticBean<?>) context).addQualifier(DEFAULT);
+                    ((SyntheticBean<?>) context).addQualifier(Default.Literal.INSTANCE);
                 }
             }
         }
@@ -316,12 +323,71 @@ public class CdiCamelExtension implements Extension {
                                 : templateQualifiers))
                 .forEach(abd::addBean);
 
+        // optional mock support if camel-mock is there
+        try {
+            var loader = Thread.currentThread().getContextClassLoader();
+            if (loader == null) {
+                loader = getClass().getClassLoader();
+                if (loader == null) {
+                    loader = getSystemClassLoader();
+                }
+            }
+            final Class<? extends Endpoint> endpointType = loader
+                    .loadClass("org.apache.camel.component.mock.MockEndpoint")
+                    .asSubclass(Endpoint.class);
+            addCamelMockBeans(abd, endpointType, templateQualifiers);
+        } catch (final ClassNotFoundException | NoClassDefFoundError e) {
+            // not needed
+        }
+
         // Add CDI event endpoint observer methods
         cdiEventEndpoints.values().stream()
                 .map(ForwardingObserverMethod::new)
                 .forEach(abd::addObserverMethod);
     }
 
+    private <T extends Endpoint> void addCamelMockBeans(
+            final AfterBeanDiscovery afterBeanDiscovery, final Class<T> type,
+            final Set<Annotation> templateQualifiers) {
+        addBean(afterBeanDiscovery, type)
+                .id(getClass().getName() + "#mockEndpoint")
+                .qualifiers(Default.Literal.INSTANCE, Uri.Literal.of(""), Any.Literal.INSTANCE)
+                .addQualifiers(templateQualifiers)
+                .produceWith(instance -> newEndpoint(type, instance, ip -> getQualifierByType(ip, Uri.class)
+                        .map(Uri::value)
+                        .orElseGet(() -> "mock:" + ip.getMember().getName())));
+    }
+
+    private <T extends Endpoint> BeanConfigurator<T> addBean(
+            final AfterBeanDiscovery afterBeanDiscovery, final Class<T> type) {
+        return afterBeanDiscovery
+                .<T> addBean()
+                .scope(Dependent.class)
+                .beanClass(type)
+                .types(type, Object.class);
+    }
+
+    private <T extends Endpoint> T newEndpoint(
+            final Class<T> type,
+            final Instance<Object> instance,
+            final Function<InjectionPoint, String> uriFactory) {
+        final var ip = instance.select(InjectionPoint.class).get();
+        final var contexts = instance.select(CamelContext.class, Any.Literal.INSTANCE);
+        return lookupEndpoint(type, ip, contexts, uriFactory.apply(ip));
+    }
+
+    private <T extends Endpoint> T lookupEndpoint(
+            final Class<T> type,
+            final InjectionPoint ip,
+            final Instance<CamelContext> contexts,
+            final String uri) {
+        try {
+            return selectContext(ip, contexts, this).getEndpoint(uri, type);
+        } catch (Exception cause) {
+            throw new InjectionException("Error injecting mock endpoint into " + ip, cause);
+        }
+    }
+
     private boolean shouldDeployDefaultCamelContext(Set<Bean<?>> beans) {
         return beans.stream()
                 // Is there a Camel bean with the @Default qualifier?
@@ -331,7 +397,7 @@ public class CdiCamelExtension implements Extension {
                         .or(hasType(RouteContainer.class).or(hasType(RoutesBuilder.class))))
                 .map(Bean::getQualifiers)
                 .flatMap(Set::stream)
-                .anyMatch(isEqual(DEFAULT))
+                .anyMatch(isEqual(Default.Literal.INSTANCE))
                 // Or a bean with Camel annotations?
                 || concat(camelBeans.stream().map(AnnotatedType::getFields),
                         camelBeans.stream().map(AnnotatedType::getMethods))
@@ -352,7 +418,7 @@ public class CdiCamelExtension implements Extension {
                         .filter(ip -> getRawType(ip.getType()).getName().startsWith("org.apache.camel"))
                         .map(InjectionPoint::getQualifiers)
                         .flatMap(Set::stream)
-                        .anyMatch(isAnnotationType(Uri.class).or(isEqual(DEFAULT)));
+                        .anyMatch(isAnnotationType(Uri.class).or(isEqual(Default.Literal.INSTANCE)));
     }
 
     private SyntheticBean<?> camelContextBean(BeanManager manager, Class<?> beanClass, Annotation... qualifiers) {
@@ -372,7 +438,7 @@ public class CdiCamelExtension implements Extension {
         configuration.unmodifiable();
 
         Collection<CamelContext> contexts = new ArrayList<>();
-        for (Bean<?> context : manager.getBeans(CamelContext.class, ANY)) {
+        for (Bean<?> context : manager.getBeans(CamelContext.class, Any.Literal.INSTANCE)) {
             contexts.add(getReference(manager, CamelContext.class, context));
         }
 
@@ -387,9 +453,9 @@ public class CdiCamelExtension implements Extension {
         // Add routes to Camel contexts
         if (configuration.autoConfigureRoutes()) {
             boolean deploymentException = false;
-            Set<Bean<?>> routes = new HashSet<>(manager.getBeans(RoutesBuilder.class, ANY));
-            routes.addAll(manager.getBeans(RouteContainer.class, ANY));
-            for (Bean<?> context : manager.getBeans(CamelContext.class, ANY)) {
+            Set<Bean<?>> routes = new HashSet<>(manager.getBeans(RoutesBuilder.class, Any.Literal.INSTANCE));
+            routes.addAll(manager.getBeans(RouteContainer.class, Any.Literal.INSTANCE));
+            for (Bean<?> context : manager.getBeans(CamelContext.class, Any.Literal.INSTANCE)) {
                 for (Bean<?> route : routes) {
                     Set<Annotation> qualifiers = new HashSet<>(context.getQualifiers());
                     qualifiers.retainAll(route.getQualifiers());
@@ -408,8 +474,8 @@ public class CdiCamelExtension implements Extension {
         // the initialization of normal-scoped beans).
         // FIXME: This does not work with OpenWebBeans for bean whose bean type is an
         // interface as the Object methods does not get forwarded to the bean instances!
-        eagerBeans.forEach(type -> getReferencesByType(manager, type.getJavaClass(), ANY).toString());
-        manager.getBeans(Object.class, ANY, STARTUP)
+        eagerBeans.forEach(type -> getReferencesByType(manager, type.getJavaClass(), Any.Literal.INSTANCE).toString());
+        manager.getBeans(Object.class, Any.Literal.INSTANCE, STARTUP)
                 .forEach(bean -> getReference(manager, bean.getBeanClass(), bean).toString());
 
         // Start Camel contexts
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java
index c4cf75f..1abad39 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiCamelFactory.java
@@ -29,7 +29,6 @@ import javax.enterprise.inject.Default;
 import javax.enterprise.inject.InjectionException;
 import javax.enterprise.inject.Instance;
 import javax.enterprise.inject.Produces;
-import javax.enterprise.inject.Typed;
 import javax.enterprise.inject.spi.InjectionPoint;
 
 import org.apache.camel.CamelContext;
@@ -38,13 +37,14 @@ import org.apache.camel.Endpoint;
 import org.apache.camel.FluentProducerTemplate;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.TypeConverter;
-import org.apache.camel.component.mock.MockEndpoint;
 
 import static org.apache.camel.cdi.CdiEventEndpoint.eventEndpointUri;
 import static org.apache.camel.cdi.CdiSpiHelper.isAnnotationType;
-import static org.apache.camel.cdi.DefaultLiteral.DEFAULT;
 
-final class CdiCamelFactory {
+class CdiCamelFactory {
+    protected CdiCamelFactory() {
+        // no-op
+    }
 
     @Produces
     private static TypeConverter typeConverter(
@@ -128,37 +128,6 @@ final class CdiCamelFactory {
         }
     }
 
-    @Produces
-    @Typed(MockEndpoint.class)
-    // Qualifiers are dynamically added in CdiCamelExtension
-    private static MockEndpoint mockEndpointFromMember(
-            InjectionPoint ip, @Any Instance<CamelContext> instance, CdiCamelExtension extension) {
-        String uri = "mock:" + ip.getMember().getName();
-        try {
-            return selectContext(ip, instance, extension).getEndpoint(uri, MockEndpoint.class);
-        } catch (Exception cause) {
-            throw new InjectionException("Error injecting mock endpoint into " + ip, cause);
-        }
-    }
-
-    @Uri("")
-    @Produces
-    @Typed(MockEndpoint.class)
-    // Qualifiers are dynamically added in CdiCamelExtension
-    private static MockEndpoint mockEndpointFromUri(
-            InjectionPoint ip, @Any Instance<CamelContext> instance, CdiCamelExtension extension) {
-        Uri uri = getQualifierByType(ip, Uri.class).get();
-        try {
-            CamelContext context = selectContext(ip, instance, extension);
-            return context.getEndpoint(uri.value(), MockEndpoint.class);
-        } catch (Exception cause) {
-            throw new InjectionException(
-                    "Error injecting mock endpoint annotated with " + uri
-                                         + " into " + ip,
-                    cause);
-        }
-    }
-
     @Uri("")
     @Produces
     // Qualifiers are dynamically added in CdiCamelExtension
@@ -190,17 +159,16 @@ final class CdiCamelFactory {
         return context.getEndpoint(uri, CdiEventEndpoint.class);
     }
 
-    private static <
-            T extends CamelContext> T selectContext(InjectionPoint ip, Instance<T> instance, CdiCamelExtension extension) {
+    static CamelContext selectContext(InjectionPoint ip, Instance<CamelContext> instance, CdiCamelExtension extension) {
         Collection<Annotation> qualifiers = new HashSet<>(ip.getQualifiers());
         qualifiers.retainAll(extension.getContextQualifiers());
-        if (qualifiers.isEmpty() && !instance.select(DEFAULT).isUnsatisfied()) {
-            return instance.select(DEFAULT).get();
+        if (qualifiers.isEmpty() && !instance.select(Default.Literal.INSTANCE).isUnsatisfied()) {
+            return instance.select(Default.Literal.INSTANCE).get();
         }
         return instance.select(qualifiers.toArray(new Annotation[0])).get();
     }
 
-    private static <T extends Annotation> Optional<T> getQualifierByType(InjectionPoint ip, Class<T> type) {
+    static <T extends Annotation> Optional<T> getQualifierByType(InjectionPoint ip, Class<T> type) {
         return ip.getQualifiers().stream()
                 .filter(isAnnotationType(type))
                 .findAny()
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiSpiHelper.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiSpiHelper.java
index cda4e85..0ebaf86 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiSpiHelper.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/CdiSpiHelper.java
@@ -34,6 +34,8 @@ import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
 
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Default;
 import javax.enterprise.inject.spi.Annotated;
 import javax.enterprise.inject.spi.AnnotatedConstructor;
 import javax.enterprise.inject.spi.AnnotatedField;
@@ -53,8 +55,6 @@ import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.joining;
 import static java.util.stream.Collectors.toSet;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
-import static org.apache.camel.cdi.DefaultLiteral.DEFAULT;
 
 @Vetoed
 final class CdiSpiHelper {
@@ -132,9 +132,9 @@ final class CdiSpiHelper {
                 .collect(collectingAndThen(toSet(),
                         qualifiers -> {
                             if (qualifiers.isEmpty()) {
-                                qualifiers.add(DEFAULT);
+                                qualifiers.add(Default.Literal.INSTANCE);
                             }
-                            qualifiers.add(ANY);
+                            qualifiers.add(Any.Literal.INSTANCE);
                             return qualifiers;
                         }));
     }
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/Startup.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/Startup.java
index d49e3a6..7c7564d 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/Startup.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/Startup.java
@@ -24,6 +24,9 @@ import java.lang.annotation.Target;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.inject.Qualifier;
 
+/**
+ * Can be replaced by an observer: {@code void onStart(@Observes @Initialized(ApplicationScoped) Object start)}.
+ */
 @Qualifier
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/Uri.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/Uri.java
index c38b459..9cb5494 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/Uri.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/Uri.java
@@ -71,6 +71,5 @@ public @interface Uri {
         public String value() {
             return uri;
         }
-
     }
 }
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
index 4c7c515..705429e 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/XmlCdiBeanFactory.java
@@ -25,7 +25,9 @@ import java.util.List;
 import java.util.Set;
 import java.util.stream.Stream;
 
+import javax.enterprise.inject.Any;
 import javax.enterprise.inject.CreationException;
+import javax.enterprise.inject.Default;
 import javax.enterprise.inject.Vetoed;
 import javax.enterprise.inject.spi.AnnotatedType;
 import javax.enterprise.inject.spi.Bean;
@@ -59,10 +61,8 @@ import static java.lang.String.format;
 import static java.util.Collections.*;
 import static java.util.Objects.requireNonNull;
 import static java.util.stream.Collectors.toSet;
-import static org.apache.camel.cdi.AnyLiteral.ANY;
 import static org.apache.camel.cdi.ApplicationScopedLiteral.APPLICATION_SCOPED;
 import static org.apache.camel.cdi.CdiSpiHelper.createCamelContextWithTCCL;
-import static org.apache.camel.cdi.DefaultLiteral.DEFAULT;
 import static org.apache.camel.cdi.ResourceHelper.getResource;
 import static org.apache.camel.util.ObjectHelper.isNotEmpty;
 
@@ -163,11 +163,11 @@ final class XmlCdiBeanFactory {
 
     private SyntheticBean<?> camelContextBean(CamelContextFactoryBean factory, URL url, AnnotatedType annotatedType) {
         Set<Annotation> annotations = new HashSet<>();
-        annotations.add(ANY);
+        annotations.add(Any.Literal.INSTANCE);
         if (hasId(factory)) {
             addAll(annotations, NamedLiteral.of(factory.getId()));
         } else {
-            annotations.add(DEFAULT);
+            annotations.add(Default.Literal.INSTANCE);
             factory.setImplicitId(true);
             factory.setId(new CdiCamelContextNameStrategy().getNextName());
         }
@@ -245,8 +245,8 @@ final class XmlCdiBeanFactory {
         }
 
         Set<Annotation> annotations = new HashSet<>();
-        annotations.add(ANY);
-        annotations.add(hasId(factory) ? NamedLiteral.of(factory.getId()) : DEFAULT);
+        annotations.add(Any.Literal.INSTANCE);
+        annotations.add(hasId(factory) ? NamedLiteral.of(factory.getId()) : Default.Literal.INSTANCE);
 
         // TODO: should that be @Singleton to enable injection points with bean instance type?
         if (factory.isSingleton()) {
@@ -277,7 +277,7 @@ final class XmlCdiBeanFactory {
                         List.class,
                         Stream.of(List.class, new ListParameterizedType(RestDefinition.class))
                                 .collect(toSet()),
-                        ANY, NamedLiteral.of(definition.getId())),
+                        Any.Literal.INSTANCE, NamedLiteral.of(definition.getId())),
                 List.class,
                 new SyntheticInjectionTarget<>(definition::getRests), bean -> "imported rest context with "
                                                                               + "id [" + definition.getId() + "] "
@@ -296,7 +296,7 @@ final class XmlCdiBeanFactory {
                         List.class,
                         Stream.of(List.class, new ListParameterizedType(RouteTemplateDefinition.class))
                                 .collect(toSet()),
-                        ANY, NamedLiteral.of(definition.getId())),
+                        Any.Literal.INSTANCE, NamedLiteral.of(definition.getId())),
                 List.class,
                 new SyntheticInjectionTarget<>(definition::getRouteTemplates), bean -> "imported route template context with "
                                                                                        + "id [" + definition.getId() + "] "
@@ -316,7 +316,7 @@ final class XmlCdiBeanFactory {
                         List.class,
                         Stream.of(List.class, new ListParameterizedType(RouteConfigurationDefinition.class))
                                 .collect(toSet()),
-                        ANY, NamedLiteral.of(definition.getId())),
+                        Any.Literal.INSTANCE, NamedLiteral.of(definition.getId())),
                 List.class,
                 new SyntheticInjectionTarget<>(definition::getRouteConfigurations),
                 bean -> "imported route configuration context with "
@@ -337,7 +337,7 @@ final class XmlCdiBeanFactory {
                         List.class,
                         Stream.of(List.class, new ListParameterizedType(RouteDefinition.class))
                                 .collect(toSet()),
-                        ANY, NamedLiteral.of(definition.getId())),
+                        Any.Literal.INSTANCE, NamedLiteral.of(definition.getId())),
                 List.class,
                 new SyntheticInjectionTarget<>(definition::getRoutes), bean -> "imported route context with "
                                                                                + "id [" + definition.getId() + "] "
@@ -352,7 +352,7 @@ final class XmlCdiBeanFactory {
                 new SyntheticAnnotated(
                         RoutesDefinition.class,
                         manager.createAnnotatedType(RoutesDefinition.class).getTypeClosure(),
-                        ANY, DEFAULT),
+                        Any.Literal.INSTANCE, Default.Literal.INSTANCE),
                 RoutesDefinition.class,
                 new SyntheticInjectionTarget<>(() -> definition), bean -> "imported routes definition "
                                                                           + (hasId(definition)
@@ -438,7 +438,7 @@ final class XmlCdiBeanFactory {
                 new SyntheticAnnotated(
                         clazz,
                         manager.createAnnotatedType(clazz).getTypeClosure(),
-                        ANY, NamedLiteral.of(definition.getId())),
+                        Any.Literal.INSTANCE, NamedLiteral.of(definition.getId())),
                 clazz, bean -> "imported error handler with "
                                + "id [" + definition.getId() + "] "
                                + "from resource [" + url + "] "
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/AnyLiteral.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiJtaTransactionErrorHandlerBuilder.java
similarity index 71%
rename from components/camel-cdi/src/main/java/org/apache/camel/cdi/AnyLiteral.java
rename to components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiJtaTransactionErrorHandlerBuilder.java
index 2e0d6d3..6b0e7e2 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/AnyLiteral.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiJtaTransactionErrorHandlerBuilder.java
@@ -14,18 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.cdi;
+package org.apache.camel.cdi.transaction;
 
-import javax.enterprise.inject.Any;
-import javax.enterprise.util.AnnotationLiteral;
+import org.apache.camel.jta.JtaTransactionErrorHandlerBuilder;
 
-@Vetoed
-final class AnyLiteral extends AnnotationLiteral<Any> implements Any {
-
-    static final Any ANY = new AnyLiteral();
-
-    private static final long serialVersionUID = 1L;
-
-    private AnyLiteral() {
-    }
+public class CdiJtaTransactionErrorHandlerBuilder extends JtaTransactionErrorHandlerBuilder
+        implements CdiTransactionalErrorHandlerBuilder {
 }
diff --git a/components/camel-cdi/src/main/java/org/apache/camel/cdi/DefaultLiteral.java b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiTransactionalErrorHandlerBuilder.java
similarity index 55%
rename from components/camel-cdi/src/main/java/org/apache/camel/cdi/DefaultLiteral.java
rename to components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiTransactionalErrorHandlerBuilder.java
index e701a89..5b8a8ee 100644
--- a/components/camel-cdi/src/main/java/org/apache/camel/cdi/DefaultLiteral.java
+++ b/components/camel-cdi/src/main/java/org/apache/camel/cdi/transaction/CdiTransactionalErrorHandlerBuilder.java
@@ -14,18 +14,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.apache.camel.cdi;
+package org.apache.camel.cdi.transaction;
 
-import javax.enterprise.inject.Default;
-import javax.enterprise.util.AnnotationLiteral;
+import org.apache.camel.LoggingLevel;
+import org.apache.camel.jta.JtaTransactionErrorHandlerBuilder;
+import org.apache.camel.jta.JtaTransactionPolicy;
 
-@Vetoed
-final class DefaultLiteral extends AnnotationLiteral<Default> implements Default {
+public interface CdiTransactionalErrorHandlerBuilder {
+    String getPolicyRef();
 
-    static final Default DEFAULT = new DefaultLiteral();
+    JtaTransactionErrorHandlerBuilder setTransactionPolicy(String ref);
 
-    private static final long serialVersionUID = 1L;
+    JtaTransactionPolicy getTransactionPolicy();
 
-    private DefaultLiteral() {
-    }
+    JtaTransactionErrorHandlerBuilder setTransactionPolicy(JtaTransactionPolicy transactionPolicy);
+
+    LoggingLevel getRollbackLoggingLevel();
+
+    JtaTransactionErrorHandlerBuilder setRollbackLoggingLevel(LoggingLevel rollbackLoggingLevel);
 }