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 <rmannibu...@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); }