diff --git a/.gitignore b/.gitignore
index 5f2dbe1..67d0d9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,7 @@ buildNumber.properties
# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
!/.mvn/wrapper/maven-wrapper.jar
+
+# IntelliJ stuff
+.idea/
+*.iml
diff --git a/README.md b/README.md
index 1091391..5bdf3f6 100644
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ You can provide configuration overrides for the following Axon artifacts by crea
For more details on these objects and the Axon Framework, please consult the [Axon Framework Reference Guide](https://docs.axonframework.org).
### Aggregates
-You can define aggregate roots by placing a simple annotation `org.axonframework.cdi.stereotype.Aggregate` on your class. It will be automatically collected by the CDI container and registered.
+You can define aggregate roots by placing a simple annotation `org.axonframework.extensions.cdi.stereotype.Aggregate` on your class. It will be automatically collected by the CDI container and registered.
### Event Handlers and Query Handlers
Event handlers and query handlers must be CDI beans. They will be automatically registered with Axon for you.
diff --git a/cdi/pom.xml b/cdi/pom.xml
index 4a26050..b279b77 100644
--- a/cdi/pom.xml
+++ b/cdi/pom.xml
@@ -15,9 +15,7 @@
~ limitations under the License.
-->
-
+
4.0.0
axon-cdi-parent
@@ -27,16 +25,10 @@
axon-cdi
- Axon Framework CDI Extension
-
- This module contains components that integrate with CDI.
-
-
- jar
+ Axon Framework CDI Support
+ Provides official Axon support for the CDI programming model.
- 1.1.11
- 1.8.2
@@ -44,67 +36,35 @@
org.axonframework
axon-configuration
- ${axon.version}
-
-
-
- javax.enterprise
- cdi-api
- provided
- javax.transaction
- javax.transaction-api
- provided
-
-
-
- org.apache.commons
- commons-lang3
- 3.8.1
+ org.axonframework
+ axon-test
+ test
-
- org.apache.deltaspike.core
- deltaspike-core-api
- ${deltaspike.version}
-
-
- org.apache.deltaspike.core
- deltaspike-core-impl
- ${deltaspike.version}
+ javax
+ javaee-api
+ provided
-
-
- ch.qos.logback
- logback-classic
- test
-
-
- org.slf4j
- jul-to-slf4j
- test
-
org.slf4j
- slf4j-log4j12
- test
+ slf4j-api
+
+
org.slf4j
- jcl-over-slf4j
+ slf4j-simple
test
- log4j
- log4j
+ junit
+ junit
test
-
-
-
org.jboss.weld.se
weld-se-core
@@ -115,26 +75,6 @@
weld-junit4
test
-
-
- junit
- junit
- test
-
-
-
- org.mockito
- mockito-core
- test
-
-
-
- commons-io
- commons-io
- 1.3.2
- test
-
-
-
\ No newline at end of file
+
diff --git a/cdi/src/main/java/org/axonframework/extensions/cdi/AggregateDefinition.java b/cdi/src/main/java/org/axonframework/extensions/cdi/AggregateDefinition.java
index bb3d25d..9efad70 100644
--- a/cdi/src/main/java/org/axonframework/extensions/cdi/AggregateDefinition.java
+++ b/cdi/src/main/java/org/axonframework/extensions/cdi/AggregateDefinition.java
@@ -1,7 +1,6 @@
package org.axonframework.extensions.cdi;
import org.axonframework.extensions.cdi.stereotype.Aggregate;
-import org.axonframework.extensions.cdi.util.StringUtilities;
import java.lang.annotation.Annotation;
import java.util.Arrays;
diff --git a/cdi/src/main/java/org/axonframework/extensions/cdi/AxonCdiExtension.java b/cdi/src/main/java/org/axonframework/extensions/cdi/AxonCdiExtension.java
index 8ac4220..01809ea 100644
--- a/cdi/src/main/java/org/axonframework/extensions/cdi/AxonCdiExtension.java
+++ b/cdi/src/main/java/org/axonframework/extensions/cdi/AxonCdiExtension.java
@@ -1,25 +1,31 @@
package org.axonframework.extensions.cdi;
-import org.apache.commons.lang3.reflect.TypeUtils;
-import org.apache.deltaspike.core.util.bean.BeanBuilder;
-import org.apache.deltaspike.core.util.metadata.AnnotationInstanceProvider;
+import org.axonframework.extensions.cdi.stereotype.Aggregate;
+import org.axonframework.extensions.cdi.stereotype.Saga;
+import org.axonframework.commandhandling.CommandBus;
import org.axonframework.common.jpa.EntityManagerProvider;
import org.axonframework.common.lock.LockFactory;
import org.axonframework.common.lock.NullLockFactory;
import org.axonframework.common.transaction.TransactionManager;
import org.axonframework.config.*;
+import org.axonframework.deadline.DeadlineManager;
+import org.axonframework.eventhandling.ErrorHandler;
import org.axonframework.eventhandling.EventBus;
+import org.axonframework.eventhandling.ListenerInvocationErrorHandler;
+import org.axonframework.eventhandling.tokenstore.TokenStore;
import org.axonframework.eventsourcing.SnapshotTriggerDefinition;
import org.axonframework.eventsourcing.eventstore.EventStorageEngine;
-import org.axonframework.extensions.cdi.config.ConfigurerProducer;
-import org.axonframework.extensions.cdi.config.IfNoneDefined;
-import org.axonframework.extensions.cdi.messagehandling.MessageHandlingBeanDefinition;
-import org.axonframework.extensions.cdi.stereotype.Aggregate;
-import org.axonframework.extensions.cdi.util.CdiUtilities;
-import org.axonframework.extensions.cdi.util.SupplierBasedLifeCycle;
+import org.axonframework.messaging.correlation.CorrelationDataProvider;
import org.axonframework.modelling.command.CommandTargetResolver;
import org.axonframework.modelling.command.GenericJpaRepository;
import org.axonframework.modelling.command.Repository;
+import org.axonframework.modelling.saga.ResourceInjector;
+import org.axonframework.modelling.saga.repository.SagaStore;
+import org.axonframework.queryhandling.QueryBus;
+import org.axonframework.queryhandling.QueryGateway;
+import org.axonframework.queryhandling.QueryUpdateEmitter;
+import org.axonframework.serialization.Serializer;
+import org.axonframework.serialization.upcasting.event.EventUpcaster;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -27,24 +33,20 @@
import javax.enterprise.context.Destroyed;
import javax.enterprise.context.Initialized;
import javax.enterprise.event.Observes;
-import javax.enterprise.inject.Default;
import javax.enterprise.inject.spi.*;
-import javax.inject.Singleton;
+import javax.inject.Named;
import java.lang.invoke.MethodHandles;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.*;
-import java.util.function.Function;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import java.util.function.Supplier;
-
-import static org.axonframework.extensions.cdi.util.CdiUtilities.*;
-import static org.axonframework.extensions.cdi.util.StringUtilities.lowerCaseFirstLetter;
-
+import java.util.stream.Collectors;
/**
- * @author Bert Laverman
+ * Main CDI extension class responsible for collecting CDI beans and setting up
+ * Axon configuration.
*/
-@Singleton
public class AxonCdiExtension implements Extension {
private static final Logger logger = LoggerFactory.getLogger(
@@ -55,212 +57,418 @@ public class AxonCdiExtension implements Extension {
private final Map> snapshotTriggerDefinitionProducerMap = new HashMap<>();
private final Map> commandTargetResolverProducerMap = new HashMap<>();
+ private final List sagas = new ArrayList<>();
+ private final Map> sagaStoreProducerMap = new HashMap<>();
+ private final Map>> sagaConfigurationProducerMap = new HashMap<>();
+
private final List messageHandlers = new ArrayList<>();
+ private Producer eventStorageEngineProducer;
+ private Producer serializerProducer;
+ private Producer eventSerializerProducer;
+ private Producer messageSerializerProducer;
+ private Producer eventBusProducer;
+ private Producer commandBusProducer;
+// private Producer commandGatewayProducer;
+ private Producer configurerProducer;
+ private Producer transactionManagerProducer;
+ private Producer entityManagerProviderProducer;
+ private Producer tokenStoreProducer;
+ private Producer listenerInvocationErrorHandlerProducer;
+ private Producer errorHandlerProducer;
+ private final List> correlationDataProviderProducers = new ArrayList<>();
+ private Producer queryBusProducer;
+ private Producer queryGatewayProducer;
+ private Producer queryUpdateEmitterProducer;
+ private final List> moduleConfigurationProducers = new ArrayList<>();
+ private final List> configurerModuleProducers = new ArrayList<>();
+ private final List> eventUpcasterProducers = new ArrayList<>();
+ private Producer deadlineManagerProducer;
+ private Producer eventProcessingModuleProducer;
+ private Producer eventProcessingConfigurationProducer;
+ private Producer resourceInjectorProducer;
+
+ // Mark: Many of the beans and producers I am processing may use
+ // container resources such as entity managers, etc. I believe this means
+ // I should be handling them as late as possible to avoid initialization
+ // timing issues. Right now things are processed as they make
+ // "semantic" sense. Do you think this could be improved to do the same
+ // processing later?
+ //X @struberg: it will work. But probably might be better to observe ProcessBeanAttributes pba and use pba.getAnnotated
+ //X that way you will also have the ability to pick up modifications of those classes via ProcessAnnotatedType.
+ //X Not sure if this is really needed for your users though.
/**
- * Produce a bean, using the given {@link BeanManager} and {@link Producer}.
+ * Scans all annotated types with the {@link Aggregate} annotation and
+ * collects them for registration.
*
- * @param beanManager the CDI BeanManager to provide the context.
- * @param producer the (registered) producer for this bean class.
- * @param The class of the bean.
- * @return the requested instance.
+ * @param processAnnotatedType annotated type processing event.
*/
- private T produce(BeanManager beanManager, Producer producer) {
- return producer.produce(beanManager.createCreationalContext(null));
+ // Mark: All I need to do here is look up what the aggregate classes are
+ // and what the value of the @Aggregate annotation is. This feels a little
+ // overkill. That said, currently I do need these values in afterBeanDiscovery
+ // and this might be the most efficient way of collecting these anyway.
+ // Other than being a bit ugly, this is not anything that is causing any
+ // functional issues.
+ void processAggregate(@Observes @WithAnnotations({Aggregate.class})
+ final ProcessAnnotatedType processAnnotatedType) {
+ // TODO Aggregate classes may need to be vetoed so that CDI does not
+ // actually try to manage them.
+
+ final Class> clazz = processAnnotatedType.getAnnotatedType().getJavaClass();
+
+ logger.debug("Found aggregate: {}.", clazz);
+
+ aggregates.add(new AggregateDefinition(clazz));
}
- private Map, AnnotatedType>> defaultBeans = new HashMap<>();
- private Map> defaultProducers = new HashMap<>();
- private Map> defaultProducerBeanClasses = new HashMap<>();
- private Set nonDefaultProducers = new HashSet<>();
+ // Mark: Same issues with the stuff below. A bit ugly but functional. I may
+ // be able to get rid of most fo this by doing BeanManager look ups right
+ // after afterBeanDiscovery or later.
+ void processAggregateRepositoryProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Found producer for repository: {}.", processProducer.getProducer());
+
+ String repositoryName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+
+ this.aggregateRepositoryProducerMap.put(repositoryName, processProducer.getProducer());
+ }
+
+ void processSnapshotTriggerDefinitionProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Found producer for snapshot trigger definition: {}.",
+ processProducer.getProducer());
+
+ String triggerDefinitionName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+
+ this.snapshotTriggerDefinitionProducerMap.put(triggerDefinitionName, processProducer.getProducer());
+ }
+
+ void processCommandTargetResolverProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Found producer for command target resolver: {}.", processProducer.getProducer());
+
+ String resolverName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+
+ this.commandTargetResolverProducerMap.put(resolverName, processProducer.getProducer());
+ }
+
+ void processSaga(@Observes @WithAnnotations({Saga.class})
+ final ProcessAnnotatedType processAnnotatedType) {
+ // TODO Saga classes may need to be vetoed so that CDI does not
+ // actually try to manage them.
+
+ final Class> clazz = processAnnotatedType.getAnnotatedType().getJavaClass();
+
+ logger.debug("Found saga: {}.", clazz);
+
+ sagas.add(new SagaDefinition(clazz));
+ }
/**
- * Collect bean classes marked with the {code @IfNoneDefined} annotation.
+ * Scans for an event storage engine producer.
*
- * @param pat the {@link ProcessAnnotatedType} event.
- * @param the class of the bean.
+ * @param processProducer process producer event.
*/
- void processDefaultBeans(@Observes final ProcessAnnotatedType pat) {
- AnnotatedType at = pat.getAnnotatedType();
- IfNoneDefined noneDefined = at.getAnnotation(IfNoneDefined.class);
-
- if (noneDefined != null) {
- logger.info("processAnnotatedType(): Found default bean. Vetoing it for now.");
- defaultBeans.put(noneDefined.value(), at);
- pat.veto();
- }
+ // Mark: I know these seem especially frivolous and looks like they may be
+ // replaced with post deployment look-ups or injection of some kind.
+ // Unfortunately I don't think it is that straightforwards for reasons
+ // explained a bit later. That said, I do want to discuss these with you.
+ void processEventStorageEngineProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for event storage engine found: {}.",
+ processProducer.getProducer());
+
+ this.eventStorageEngineProducer = processProducer.getProducer();
+ }
+
+ void processSagaConfigurationProducer(
+ @Observes final ProcessProducer> processProducer) {
+ logger.debug("Producer for saga configuration found: {}.",
+ processProducer.getProducer());
+
+ String sagaConfigurationName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+
+ sagaConfigurationProducerMap.put(sagaConfigurationName, processProducer.getProducer());
}
/**
- * Collect the producers marked with the {@code @IfNoneDefined} qualifier.
+ * Scans for a configurer producer.
*
- * @param processProducer the {@link ProcessProducer} event.
- * @param the bean class of the bean that declares the producer.
- * @param the return type of the producer.
+ * @param processProducer process producer event.
*/
- void processDefaultProducers(@Observes final ProcessProducer processProducer) {
- AnnotatedMember member = processProducer.getAnnotatedMember();
- if (member instanceof AnnotatedMethod) {
- final AnnotatedMethod> am = (AnnotatedMethod)member;
- final Type returnType = am.getBaseType();
-
- final IfNoneDefined noneDefined = am.getAnnotation(IfNoneDefined.class);
-
- if (noneDefined != null) {
- logger.info("processAnnotatedType(): Found default producer for {}. \"{}::{}\".",
- returnType,
- am.getDeclaringType().getJavaClass().getName(),
- am.getJavaMember().getName());
- defaultProducers.put(returnType, processProducer.getProducer());
- defaultProducerBeanClasses.put(returnType, am.getJavaMember().getReturnType());
- }
- else {
- nonDefaultProducers.add(returnType);
- }
- }
-// else if (member instanceof AnnotatedField) {
-// logger.info("processDefaultProducers(): Ignoring @Produces on a {}.", member.getClass().getName());
-// }
-// else {
-// logger.info("processDefaultProducers(): Ignoring @Produces on a {}.", member.getClass().getName());
-// }
+ void processConfigurerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for configurer found: {}.", processProducer.getProducer());
+
+ this.configurerProducer = processProducer.getProducer();
}
/**
- * Add beans from all {@code @IfNoneDefined} marked producers, if none is already avilable.
+ * Scans for a transaction manager producer.
*
- * @param afterBeanDiscovery the {@link AfterBeanDiscovery} event.
- * @param mgr the {@link BeanManager}.
+ * @param processProducer process producer event.
*/
- private void addMissingProducers(final AfterBeanDiscovery afterBeanDiscovery, final BeanManager mgr) {
- logger.info("addMissingProducers(): Checking for missing producers.");
- for (Type tp: defaultProducers.keySet()) {
- if (!nonDefaultProducers.contains(tp)) {
- if (defaultProducers.containsKey(tp)) {
- final Class> beanClass = defaultProducerBeanClasses.get(tp);
- logger.info("addMissingProducers(): Enabling our default producer for \"{}\" (beanClass \"{}\".", tp, beanClass);
- afterBeanDiscovery.addBean(new BeanBuilder<>(mgr)
- .beanClass(beanClass)
- .types(tp)
- .scope(ApplicationScoped.class)
- .qualifiers(AnnotationInstanceProvider.of(Default.class))
- .beanLifecycle(new SupplierBasedLifeCycle<>(() -> produce(mgr, defaultProducers.get(tp))))
- .create());
- }
- else {
- logger.warn("addMissingProducers(): We seem to lack a producer for \"{}\".", tp);
- }
- }
- }
- logger.info("addMissingProducers(): Done");
+ void processTransactionManagerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for transaction manager found: {}.",
+ processProducer.getProducer());
+
+ this.transactionManagerProducer = processProducer.getProducer();
}
- private Bean defineBean(BeanManager beanManager, AnnotatedType annotatedType) {
- BeanAttributes beanAttributes = beanManager.createBeanAttributes(annotatedType);
- InjectionTargetFactory injectionTargetFactory = beanManager.getInjectionTargetFactory(annotatedType);
- return beanManager.createBean(beanAttributes, annotatedType.getJavaClass(), injectionTargetFactory);
+ /**
+ * Scans for a serializer producer.
+ *
+ * @param processProducer process producer event.
+ */
+ void processSerializerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple serializer definitions of the same type.
+
+ AnnotatedMember annotatedMember = processProducer.getAnnotatedMember();
+ Named named = annotatedMember.getAnnotation(Named.class);
+
+ if (named != null) {
+ String namedValue = named.value();
+ String serializerName = "".equals(namedValue)
+ ? annotatedMember.getJavaMember().getName()
+ : namedValue;
+ switch (serializerName) {
+ case "eventSerializer":
+ logger.debug("Producer for event serializer found: {}.",
+ processProducer.getProducer());
+ eventSerializerProducer = processProducer.getProducer();
+ break;
+ case "messageSerializer":
+ logger.debug("Producer for message serializer found: {}.",
+ processProducer.getProducer());
+ messageSerializerProducer = processProducer.getProducer();
+ break;
+ case "serializer":
+ logger.debug("Producer for serializer found: {}.",
+ processProducer.getProducer());
+ this.serializerProducer = processProducer.getProducer();
+ break;
+ default:
+ logger.warn("Unknown named serializer configured: " + serializerName);
+ }
+ } else {
+ logger.debug("Producer for serializer found: {}.", processProducer.getProducer());
+ this.serializerProducer = processProducer.getProducer();
+ }
}
- private void addMissingBeans(final AfterBeanDiscovery afterBeanDiscovery, final BeanManager mgr) {
- logger.info("addMissingBeans(): Checking for missing beans.");
+ /**
+ * Scans for an event bus producer.
+ *
+ * @param processProducer process producer event.
+ */
+ void processEventBusProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
- defaultBeans.entrySet().stream()
- .filter(e -> mgr.getBeans(e.getKey()).isEmpty())
- .map(e -> defineBean(mgr, e.getValue()))
- .forEach(afterBeanDiscovery::addBean);
+ logger.debug("Producer for event bus found: {}.", processProducer.getProducer());
- logger.info("addMissingBeans(): Done");
+ this.eventBusProducer = processProducer.getProducer();
}
/**
- * Collect all classes annotated with {@link Aggregate}.
+ * Scans for a command bus producer.
*
- * @param processAnnotatedType the CDI wrapper for the class.
- * @param the class itself.
+ * @param processProducer process producer event.
*/
- void processAggregate(@Observes @WithAnnotations({Aggregate.class})
- final ProcessAnnotatedType processAnnotatedType) {
- // TODO Aggregate classes may need to be vetoed so that CDI does not
- // actually try to manage them.
+ void processCommandBusProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
- final Class clazz = processAnnotatedType.getAnnotatedType().getJavaClass();
-
- logger.info("Found aggregate: {}.", clazz);
+ logger.debug("Producer for command bus found: {}.",
+ processProducer.getProducer());
- aggregates.add(new AggregateDefinition(clazz));
+ this.commandBusProducer = processProducer.getProducer();
}
+// void processCommandGatewayProducer(
+// @Observes final ProcessProducer processProducer) {
+// // TODO Handle multiple producer definitions.
+//
+// logger.debug("Producer for command gateway found: {}.",
+// processProducer.getProducer());
+//
+// this.commandGatewayProducer = processProducer.getProducer();
+// }
+
/**
- * Collect {@link Repository} producers.
+ * Scans for an entity manager provider producer.
*
- * @param processProducer the CDI wrapper for the producer.
- * @param the producer's class.
+ * @param processProducer process producer event.
*/
- void processAggregateRepositoryProducer(
- @Observes final ProcessProducer processProducer) {
- logger.info("Found producer for repository: {}.", processProducer.getProducer());
-
- AnnotatedMember member = processProducer.getAnnotatedMember();
- if (member instanceof AnnotatedMethod) {
- logger.info("processAggregateRepositoryProducer(): Checking @Produces on a method.");
- AnnotatedMethod> am = (AnnotatedMethod)member;
- final Type type = am.getBaseType();
- logger.info("processAggregateRepositoryProducer(): The baseType is {}. ({})", type.toString(), type.getClass().getName());
- if (type instanceof ParameterizedType) {
- ParameterizedType pType = (ParameterizedType) type;
- logger.info("processAggregateRepositoryProducer(): It is a ParameterizedType.");
- for (Type tp: pType.getActualTypeArguments()) {
- logger.info("processAggregateRepositoryProducer(): - {}", tp.toString());
- }
- }
- }
- else if (member instanceof AnnotatedField) {
- logger.info("processAggregateRepositoryProducer(): Ignoring @Produces on a {}.", member.getClass().getName());
- }
- else {
- logger.info("processAggregateRepositoryProducer(): Ignoring @Produces on a {}.", member.getClass().getName());
- }
- String repositoryName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+ void processEntityManagerProviderProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Investigate if there is a way to look up the entity manager
+ // from the environment. There likely isn't.
+ // TODO Handle multiple producer definitions.
- this.aggregateRepositoryProducerMap.put(repositoryName, processProducer.getProducer());
+ logger.debug("Producer for entity manager provider found: {}.",
+ processProducer.getProducer());
+
+ this.entityManagerProviderProducer = processProducer.getProducer();
}
/**
- * Collect {@link SnapshotTriggerDefinition} producers.
+ * Scans for a token store producer.
*
- * @param processProducer the CDI wrapper for the producer.
- * @param the producer's class.
+ * @param processProducer process producer event.
*/
- void processSnapshotTriggerDefinitionProducer(
- @Observes final ProcessProducer processProducer) {
- logger.info("Found producer for snapshot trigger definition: {}.",
+ void processTokenStoreProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for token store found: {}.", processProducer.getProducer());
+
+ this.tokenStoreProducer = processProducer.getProducer();
+ }
+
+ void processErrorHandlerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for error handler found: {}.", processProducer.getProducer());
+
+ this.errorHandlerProducer = processProducer.getProducer();
+ }
+
+ void processListenerInvocationErrorHandlerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for listener invocation error handler found: {}.",
processProducer.getProducer());
- String triggerDefinitionName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+ this.listenerInvocationErrorHandlerProducer = processProducer.getProducer();
+ }
- this.snapshotTriggerDefinitionProducerMap.put(triggerDefinitionName, processProducer.getProducer());
+ void processCorrelationDataProviderProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Producer for correlation data provider found: {}.",
+ processProducer.getProducer());
+
+ this.correlationDataProviderProducers.add(processProducer.getProducer());
}
- /**
- * Collect {@link CommandTargetResolver} producers.
- *
- * @param processProducer the CDI wrapper for the producer.
- * @param the producer's class.
- */
- void processCommandTargetResolverProducer(
- @Observes final ProcessProducer processProducer) {
- logger.info("Found producer for command target resolver: {}.", processProducer.getProducer());
+ void processQueryBusProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
- String resolverName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+ logger.debug("Producer for query bus found: {}.",
+ processProducer.getProducer());
- this.commandTargetResolverProducerMap.put(resolverName, processProducer.getProducer());
+ this.queryBusProducer = processProducer.getProducer();
+ }
+
+ void processQueryGatewayProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for query gateway found: {}.",
+ processProducer.getProducer());
+
+ this.queryGatewayProducer = processProducer.getProducer();
+ }
+
+ void processQueryUpdateEmitterProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for query update emitter found: {}.", processProducer.getProducer());
+
+ this.queryUpdateEmitterProducer = processProducer.getProducer();
+ }
+
+ void processDeadlineManagerProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for deadline manager found: {}.", processProducer.getProducer());
+
+ this.deadlineManagerProducer = processProducer.getProducer();
+ }
+
+ void processModuleConfigurationProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Producer for module configuration found: {}.",
+ processProducer.getProducer());
+
+ this.moduleConfigurationProducers.add(processProducer.getProducer());
+ }
+
+ void processEventHandlingConfigurationProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for event handling configuration found: {}.",
+ processProducer.getProducer());
+
+ this.eventProcessingModuleProducer = processProducer.getProducer();
+ }
+
+ void processEventProcessingConfigurationProducer(
+ @Observes final ProcessProducer processProducer) {
+ // TODO Handle multiple producer definitions.
+
+ logger.debug("Producer for event processing configuration found: {}.",
+ processProducer.getProducer());
+
+ this.eventProcessingConfigurationProducer = processProducer.getProducer();
+ }
+
+ void processConfigurerModuleProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Producer for configurer module found: {}.", processProducer.getProducer());
+
+ this.configurerModuleProducers.add(processProducer.getProducer());
+ }
+
+ void processSagaStoreProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Producer for saga store found: {}.", processProducer.getProducer());
+
+ String sagaStoreName = CdiUtilities.extractBeanName(processProducer.getAnnotatedMember());
+
+ this.sagaStoreProducerMap.put(sagaStoreName, processProducer.getProducer());
+ }
+
+ void processEventUpcasterProducer(
+ @Observes final ProcessProducer processProducer) {
+ logger.debug("Producer for event upcaster found: {}.", processProducer.getProducer());
+
+ this.eventUpcasterProducers.add(processProducer.getProducer());
+ }
+
+ void resourceInjectorProducer(
+ @Observes final ProcessProducer processProducer) {
+
+ logger.debug("Producer for resource injector found: {}.", processProducer.getProducer());
+
+ this.resourceInjectorProducer = processProducer.getProducer();
}
/**
- * Collect message handlers for later processing.
- * @param processBean the CDI wrapper for the bean.
- * @param the class of the bean.
+ * Scans all beans and collects beans with message handlers.
+ *
+ * @param processBean bean processing event.
*/
+ // Mark: This one is especally tricky. I am looking for the existance
+ // of annotations and methods and collecting bean definitions.
+ // I suspect this is the most efficient way to do this and I can use
+ // the bean defenitions to look up via BeanManager later.
+ //X @struberg it's fine. Although I would use processBean.getAnnotated() instead of bean.getBeanClass() in the 'inspect' code
+ //X I'fe quickly fixed this method. Please verify if it works as expected. And you still need to change the tests to AnnotatedType!
void processBean(@Observes final ProcessBean processBean) {
MessageHandlingBeanDefinition.inspect(processBean.getBean(), processBean.getAnnotated())
.ifPresent(bean -> {
@@ -269,268 +477,473 @@ void processBean(@Observes final ProcessBean processBean) {
});
}
- @SuppressWarnings("unchecked")
- private void registerAggregates(final AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager, Configurer configurer) {
- aggregates.forEach(aggregateDefinition -> {
- logger.info("registerAggregates(): Registering aggregate: {}.", aggregateDefinition.aggregateType().getSimpleName());
+ /**
+ * Registration of Axon components in CDI registry.
+ */
+ void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery,
+ final BeanManager beanManager) {
+ logger.info("Starting Axon Framework configuration.");
+
+ Configurer configurer;
+
+ if (this.configurerProducer != null) {
+ // Mark: this is one of the biggest headaches I am facing. What I
+ // need is the actual bean instance that I need to move forward with.
+ // Right now what I am doing is just having the producer create it.
+ // The problem with this is that CDI and the Java EE runtime is just
+ // not fullly ready to do that at this stage.
+
+ //X @struberg: don't understand why exactly. Miss the context.
+ //X I fear I'd need a way better understanding of Axon
+
+ // In addition, the
+ // bean may be referencing definitions I have not had a chance
+ // to register with CDI yet since they can only be produced after the
+ // Axon configuration is done.
+ //
+ // The only solution I can think of is register any bean
+ // definitions I've detected I absolutely need and avoid actual
+ // bean reference until later, create the beans like configurer
+ // that I say in the API cannot have circular dependencies and move the
+ // configuration steps itself to be as lazily loaded as possible.
+ // Can you think of a better strategy to deal with this problem?
+ configurer = produce(beanManager, configurerProducer);
+ logger.info("Starting with an application provided configurer: {}.",
+ configurer.getClass().getSimpleName());
+ } else {
+ logger.info("Starting with the Axon default configuration.");
+
+ configurer = DefaultConfigurer.defaultConfiguration();
+ }
- AggregateConfigurer> aggregateConfigurer
- = AggregateConfigurer.defaultConfiguration(aggregateDefinition.aggregateType());
+ if (this.entityManagerProviderProducer != null) {
+ final EntityManagerProvider entityManagerProvider
+ = produce(beanManager, entityManagerProviderProducer);
- if (aggregateDefinition.repository().isPresent()) {
+ logger.info("Registering entity manager provider: {}.",
+ entityManagerProvider.getClass().getSimpleName());
- final String repoBeanName = aggregateDefinition.repository().get();
- logger.info("registerAggregates(): This aggregate has a repository specified by name (\"{}\").", repoBeanName);
+ configurer.registerComponent(EntityManagerProvider.class, c -> entityManagerProvider);
+ }
- aggregateConfigurer.configureRepository(c -> produce(beanManager, aggregateRepositoryProducerMap
- .get(repoBeanName)));
- } else {
- logger.info("registerAggregates(): This aggregate has a no repository specified.");
+ if (this.serializerProducer != null) {
+ final Serializer serializer = produce(beanManager, serializerProducer);
- final String repoName = aggregateDefinition.repositoryName();
- if (aggregateRepositoryProducerMap.containsKey(repoName)) {
- logger.info("registerAggregates(): We have a producer for \"{}\".", repoName);
+ logger.info("Registering serializer: {}.", serializer.getClass().getSimpleName());
- aggregateConfigurer.configureRepository(
- c -> produce(beanManager, aggregateRepositoryProducerMap.get(repoName)));
- } else {
- logger.info("registerAggregates(): This aggregate has a no repository and no producer specified.");
-
- String repositoryName = lowerCaseFirstLetter(aggregateDefinition.aggregateType().getSimpleName()) + "Repository";
- String factoryName = lowerCaseFirstLetter(aggregateDefinition.aggregateType().getName()) + "AggregateFactory";
- logger.info("registerAggregates(): Repository beanName = \"{}\", factory name = \"{}\".", repoName, factoryName);
-
- Optional repo = getInstance(beanManager, repositoryName, Repository.class);
- if (!repo.isPresent()) {
- logger.info("registerAggregates(): We have no registered bean for \"{}\".", repositoryName);
-
- final ParameterizedType repoType = TypeUtils.parameterize(Repository.class, aggregateDefinition.aggregateType());
- logger.info("registerAggregates(): Adding a bean with type {}", repoType);
-
- afterBeanDiscovery.addBean(new BeanBuilder<>(beanManager)
- .beanClass(Repository.class)
- .types(repoType)
- .qualifiers(AnnotationInstanceProvider.of(Default.class))
- .scope(ApplicationScoped.class)
- .beanLifecycle(new SupplierBasedLifeCycle<>(() -> aggregateConfigurer.repository()))
- .create());
- }
- else {
- logger.info("registerAggregates(): We have a registered bean named \"{}\".", repositoryName);
- }
+ configurer.configureSerializer(c -> serializer);
+ }
- // TODO: 8/29/2018 check how to do in CDI world: aggregate factory
- aggregateDefinition.snapshotTriggerDefinition().ifPresent(triggerDefinition -> aggregateConfigurer
- .configureSnapshotTrigger(
- c -> produce(beanManager, snapshotTriggerDefinitionProducerMap
- .get(triggerDefinition))));
- if (aggregateDefinition.isJpaAggregate()) {
- aggregateConfigurer.configureRepository(
- c -> (Repository) GenericJpaRepository.builder(aggregateDefinition.aggregateType())
- // TODO: 8/29/2018 what to do about default EntityManagerProvider (check spring impl)
- .entityManagerProvider(c.getComponent(EntityManagerProvider.class))
- .eventBus(c.eventBus())
- .repositoryProvider(c::repository)
- .lockFactory(c.getComponent(LockFactory.class, () -> NullLockFactory.INSTANCE))
- .parameterResolverFactory(c.parameterResolverFactory())
- .handlerDefinition(c.handlerDefinition(aggregateDefinition.aggregateType()))
- .build());
- }
- }
- }
+ if (this.eventSerializerProducer != null) {
+ final Serializer serializer = produce(beanManager, eventSerializerProducer);
- if (aggregateDefinition.commandTargetResolver().isPresent()) {
- aggregateConfigurer.configureCommandTargetResolver(
- c -> produce(beanManager,
- commandTargetResolverProducerMap.get(aggregateDefinition.commandTargetResolver().get())));
- } else {
- commandTargetResolverProducerMap.keySet()
- .stream()
- .filter(resolver -> aggregates.stream()
- .filter(a -> a.commandTargetResolver().isPresent())
- .map(a -> a.commandTargetResolver().get())
- .noneMatch(resolver::equals))
- .findFirst() // TODO: 8/29/2018 what if there are more "default" resolvers
- .ifPresent(resolver -> aggregateConfigurer.configureCommandTargetResolver(
- c -> produce(beanManager,
- commandTargetResolverProducerMap.get(resolver))));
- }
+ logger.info("Registering event serializer: {}.", serializer.getClass().getSimpleName());
- configurer.configureAggregate(aggregateConfigurer);
- });
- }
+ configurer.configureEventSerializer(c -> serializer);
+ }
- private void registerMessageHandlers(final BeanManager beanManager, final Configurer configurer) {
- final EventProcessingConfigurer eventProcessingConfigurer = configurer.eventProcessing();
+ if (this.messageSerializerProducer != null) {
+ final Serializer serializer = produce(beanManager, messageSerializerProducer);
- messageHandlers.stream().filter(MessageHandlingBeanDefinition::isMessageHandler).forEach(handler -> {
- switch (handler.getScope()) {
- case SINGLETON:
- case APPLICATION_SCOPED: {
- final Function handlerBuilder = c -> getInstance(handler.getBean().getBeanClass());
- if (handler.isEventSourcingHandler()) {
- logger.warn("registerMessageHandlers(): Odd, an @EventSourcingHandler that is not an Aggregate? Ignoring for now.");
- }
- else if (handler.isEventHandler()) {
- logger.info("registerMessageHandlers(): Registering \"{}\" as event handler.", handler.getBean().getBeanClass().getName());
+ logger.info("Registering message serializer: {}.", serializer.getClass().getSimpleName());
- eventProcessingConfigurer.registerEventHandler(handlerBuilder);
- }
- if (handler.isCommandHandler()) {
- logger.info("registerMessageHandlers(): Registering \"{}\" as command handler.", handler.getBean().getBeanClass().getName());
+ configurer.configureMessageSerializer(c -> serializer);
+ }
- configurer.registerCommandHandler(handlerBuilder);
- }
- if (handler.isQueryHandler()) {
- logger.info("registerMessageHandlers(): Registering \"{}\" as query handler.", handler.getBean().getBeanClass().getName());
+ if (this.transactionManagerProducer != null) {
+ final TransactionManager transactionManager
+ = produce(beanManager, transactionManagerProducer);
- configurer.registerQueryHandler(handlerBuilder);
- }
- break;
- }
- case SESSION_SCOPED:
- case CONVERSATION_SCOPED:
- case REQUEST_SCOPED:
- case DEPENDENT:
- case UNKNOWN: {
- logger.error("registerMessageHandlers(): Only dealing with @ApplicationScoped and @Singleton for now. Ignoring \"{}\".", handler.getBean().getBeanClass().getName());
- }
- }
- });
- }
+ logger.info("Registering transaction manager: {}.", transactionManager.getClass().getSimpleName());
- private void registerModules(final BeanManager mgr, Configurer configurer) {
- registerConfigurerModules(mgr, configurer);
- registerModuleConfigurations(mgr, configurer);
- }
+ configurer.configureTransactionManager(c -> transactionManager);
+ }
+
+ if (this.commandBusProducer != null) {
+ final CommandBus commandBus = produce(beanManager, commandBusProducer);
+
+ logger.info("Registering command bus: {}.", commandBus.getClass().getSimpleName());
+
+ configurer.configureCommandBus(c -> commandBus);
+ }
+
+ // Module configurations registration.
+ // TODO: 8/30/2018 :
+ // There is a possible issue with following construct:
+ // @Produce
+ // public ModuleConfiguration eventHandlingConfiguration() {
+ // return new EventHandlingConfiguration();
+ // }
+ // It will be registered as module configuration only and not as EventHandlingConfiguration!
+ // This will result in having double EventHandlingConfiguration within Configuration.
+ // The same applies to EventProcessingConfiguration.
+ // Milan: I need to understand this a bit more from you, but I think the solution
+ // is to simply mandate the presence of @Named for EventHandlingConfiguration
+ // and EventProcessingConfiguration that is produced as type ModuleConfiguration
+ // but is not really a module configuration.
+ for (Producer producer : moduleConfigurationProducers) {
+ // Milan: This looks very interesting. I would like to understand why
+ // we are doing this and whether we should do this more globally,
+ // perhaps moving the entire Axon configuration to AfterDeploymentValidation
+ // instead of AfterBeanDiscovery.
+ // Antoine: Do you have any thoughts on this? Could this approach
+ // help solve any potential initialization issues? What's the easiest
+ // way to do this if so?
+ configurer.registerModule(new LazyRetrievedModuleConfiguration(() -> {
+ ModuleConfiguration moduleConfiguration
+ = producer.produce(beanManager.createCreationalContext(null));
+ logger.info("Registering module configuration: {}.",
+ moduleConfiguration.getClass().getSimpleName());
+ return moduleConfiguration;
+ }));
+ }
+
+ if (eventProcessingModuleProducer != null) {
+ EventProcessingModule mod = produce(beanManager, eventProcessingModuleProducer);
+
+ logger.info("Registering event processing configuration: {}.", mod.getClass().getSimpleName());
+
+ configurer.registerModule(mod);
+ }
+
+ configurerModuleProducers.forEach(producer -> {
+ ConfigurerModule configurerModule = produce(beanManager, producer);
+
+ logger.info("Configuring module: {}.", configurerModule.getClass().getSimpleName());
- private void registerConfigurerModules(final BeanManager mgr, Configurer configurer) {
- Set> configurerModules = mgr.getBeans(ConfigurerModule.class);
- for (Bean> configurerModuleBean : configurerModules) {
- ConfigurerModule configurerModule = (ConfigurerModule) configurerModuleBean.create(mgr.createCreationalContext(null));
configurerModule.configureModule(configurer);
+ });
+
+ if (this.eventBusProducer != null) {
+ final EventBus eventBus = produce(beanManager, eventBusProducer);
+
+ logger.info("Registering event bus: {}.", eventBus.getClass().getSimpleName());
+
+ configurer.configureEventBus(c -> eventBus);
}
- }
- private void registerModuleConfigurations(final BeanManager mgr, Configurer configurer) {
- Set> moduleConfigurations = mgr.getBeans(ModuleConfiguration.class);
- for (Bean> moduleConfigurationBean : moduleConfigurations) {
- configurer.registerModule(new LazyRetrievedModuleConfiguration(
- () -> (ModuleConfiguration) moduleConfigurationBean.create(mgr.createCreationalContext(null)),
- moduleConfigurationBean.getBeanClass())
- );
+ if (this.tokenStoreProducer != null) {
+ final TokenStore tokenStore = produce(beanManager, tokenStoreProducer);
+
+ logger.info("Registering token store: {}.", tokenStore.getClass().getSimpleName());
+
+ configurer.registerComponent(TokenStore.class, c -> tokenStore);
}
- }
- private Configuration buildConfiguration(Configurer configurer) {
- logger.info("Starting Axon configuration.");
+ if (this.listenerInvocationErrorHandlerProducer != null) {
+ ListenerInvocationErrorHandler listenerInvocationErrorHandler
+ = produce(beanManager, listenerInvocationErrorHandlerProducer);
- return configurer.buildConfiguration();
- }
+ logger.info("Registering listener invocation error handler: {}.",
+ listenerInvocationErrorHandler.getClass().getSimpleName());
- private void afterTypeDiscovery(@Observes final AfterTypeDiscovery afterTypeDiscovery) {
- logger.info("******* AfterTypeDiscovery");
- }
+ configurer.registerComponent(ListenerInvocationErrorHandler.class,
+ c -> listenerInvocationErrorHandler);
+ }
- private void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery beforeBeanDiscovery) {
- logger.info("******* BeforeBeanDiscovery");
- }
+ if (this.errorHandlerProducer != null) {
+ ErrorHandler errorHandler = produce(beanManager, errorHandlerProducer);
- private void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterBeanDiscovery,
- final BeanManager beanManager) {
- logger.info("******* AfterBeanDiscovery");
+ logger.info("Registering error handler: {}.", errorHandler.getClass().getSimpleName());
- final Configurer configurer = ConfigurerProducer.instance();
+ configurer.registerComponent(ErrorHandler.class, c -> errorHandler);
+ }
- registerModules(beanManager, configurer);
+ // Correlation data providers registration
+ List correlationDataProviders = this.correlationDataProviderProducers
+ .stream()
+ .map(producer -> {
+ CorrelationDataProvider correlationDataProvider = produce(beanManager, producer);
+
+ logger.info("Registering correlation data provider: {}.",
+ correlationDataProvider.getClass().getSimpleName());
+
+ return correlationDataProvider;
+ })
+ .collect(Collectors.toList());
+ configurer.configureCorrelationDataProviders(c -> correlationDataProviders);
+
+ this.eventUpcasterProducers
+ .forEach(producer -> {
+ EventUpcaster eventUpcaster = produce(beanManager, producer);
+ logger.info("Registering event upcaster: {}.",
+ eventUpcaster.getClass().getSimpleName());
+ configurer.registerEventUpcaster(c -> eventUpcaster);
+ });
- registerAggregates(afterBeanDiscovery, beanManager, configurer);
- registerMessageHandlers(beanManager, configurer);
+ if (this.queryBusProducer != null) {
+ QueryBus queryBus = produce(beanManager, queryBusProducer);
+
+ logger.info("Registering query bus: {}.", queryBus.getClass().getSimpleName());
+
+ configurer.configureQueryBus(c -> queryBus);
+ }
- addMissingProducers(afterBeanDiscovery, beanManager);
- addMissingBeans(afterBeanDiscovery, beanManager);
+ if (this.queryGatewayProducer != null) {
+ QueryGateway queryGateway = produce(beanManager, queryGatewayProducer);
- resolveBean(beanManager, EventStorageEngine.class)
- .ifPresent(bean -> configurer.configureEmbeddedEventStore(c -> getBean(beanManager, bean, EventStorageEngine.class).get()));
- resolveBean(beanManager, TransactionManager.class)
- .ifPresent(bean -> configurer.configureTransactionManager(c -> getBean(beanManager, bean, TransactionManager.class).get()));
- resolveBean(beanManager, EventBus.class)
- .ifPresent(bean -> configurer.configureEventBus(c -> getBean(beanManager, bean, EventBus.class).get()));
+ logger.info("Registering query gateway: {}.", queryGateway.getClass().getSimpleName());
- afterBeanDiscovery.addBean(new BeanBuilder<>(beanManager)
- .beanClass(Configuration.class)
- .types(Configuration.class)
- .qualifiers(AnnotationInstanceProvider.of(Default.class))
- .scope(ApplicationScoped.class)
- .beanLifecycle(new SupplierBasedLifeCycle<>(() -> buildConfiguration(configurer)))
- .create());
+ configurer.registerComponent(QueryGateway.class, c -> queryGateway);
+ }
+
+ if (this.queryUpdateEmitterProducer != null) {
+ QueryUpdateEmitter queryUpdateEmitter = produce(beanManager, queryUpdateEmitterProducer);
+
+ logger.info("Registering query update emitter: {}.", queryUpdateEmitter.getClass().getSimpleName());
+
+ configurer.configureQueryUpdateEmitter(c -> queryUpdateEmitter);
+ }
+
+ if (this.deadlineManagerProducer != null) {
+ DeadlineManager deadlineManager = produce(beanManager, deadlineManagerProducer);
+
+ logger.info("Registering deadline manager: {}.", deadlineManager.getClass().getSimpleName());
+
+ configurer.registerComponent(DeadlineManager.class, c -> deadlineManager);
+ }
+
+ if (this.eventStorageEngineProducer != null) {
+ final EventStorageEngine eventStorageEngine = produce(beanManager, eventStorageEngineProducer);
+
+ logger.info("Registering event storage: {}.", eventStorageEngine.getClass().getSimpleName());
+
+ configurer.configureEmbeddedEventStore(c -> eventStorageEngine);
+ }
+
+ if (this.resourceInjectorProducer != null) {
+ ResourceInjector resourceInjector = produce(beanManager, resourceInjectorProducer);
+
+ logger.info("Registering resource injector: {}.", resourceInjector.getClass().getSimpleName());
+
+ configurer.registerComponent(ResourceInjector.class, c -> resourceInjector);
+ }
+
+ // Now need to begin registering application components rather than
+ // configuration components.
+ registerAggregates(beanManager, configurer);
+ registerSagaStore(beanManager, configurer);
+ registerSagas(beanManager, afterBeanDiscovery, configurer);
+ registerMessageHandlers(beanManager, configurer);
+
+ logger.info("Axon Framework configuration complete.");
+
+ logger.info("Registering Axon APIs with CDI.");
+
+
+ // Mark: This is one of the key parts that is forcing me to do anything at all
+ // in the afterBeanDiscovery phase. Once the Axon configuration completes,
+ // including taking into account user defined overrides, I need to bind some
+ // bean definitions with CDI. Aside from these relatively static definitions,
+ // there are and will be loops where I need to register things that look like
+ // Repository...Repository. I think this means
+ // I absolutely need to make sure of and thus finish my Axon configuration somehow very
+ // close to afterBeanDiscovery, in a programmatic fashion.
+
+ //X @struberg: do you know that you can send CDI events between CDI Extensions already during bootstrap?
+ //X That might help here.
+ //X So you effectively can send out a ConfigurationEvent and anybody could write an own CDI Extension where
+ //X this gets observed. That way you can effectively have configuration and inter-CDI communication already before
+ //X the CDI container is booted.
+ //X I think I need a better explanation what problem you want to solve by it though.
+
+ //
+ // That said, you'll notice the lambdas below that are my effort to defer
+ // actual instantiation to as late as possible. The only other way I can
+ // think of to defer actual bean referencing any further is by using
+ // byte code proxies that look up bean references on each method call.
+ // Can you think of a better way to further defer the actual configution start and
+ // bean referencing?
+ //
+ // Even with this deferring, I am running into issues like EJBs not
+ // instantiated and JPA registries not done yet on certain containers like
+ // Payara. When I refer to application scoped beans at this stage, it seems I am gettting
+ // my own copy and then the application creates another copy when the
+ // application code actually bootstraps. All related to referncing beans too
+ // early I believe.
+
+ afterBeanDiscovery.addBean(
+ new BeanWrapper<>(Configuration.class, () -> startConfiguration(configurer)));
+ // Mark: I tried removing some of this code in favor of globally enabled alternatives.
+ // These are in AxonDefaultConfiguration. Howver, I immidiately ran into
+ // circular reference issues. I do not think alternatives are really
+ // a viable solution for this use case and I need to keep sticking to something
+ // similar to this unless you know of a way.
+ addIfNotConfigured(CommandBus.class, commandBusProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).commandBus(),
+ afterBeanDiscovery);
+ addIfNotConfigured(QueryBus.class, queryBusProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).queryBus(),
+ afterBeanDiscovery);
+ addIfNotConfigured(QueryGateway.class, queryGatewayProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).queryGateway(),
+ afterBeanDiscovery);
+ addIfNotConfigured(QueryUpdateEmitter.class,
+ queryUpdateEmitterProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).queryUpdateEmitter(),
+ afterBeanDiscovery);
+ addIfNotConfigured(EventBus.class, eventBusProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).eventBus(),
+ afterBeanDiscovery);
+ addIfNotConfigured(Serializer.class, serializerProducer,
+ () -> CdiUtilities.getReference(beanManager, Configuration.class).serializer(),
+ afterBeanDiscovery);
}
- private void afterDeploymentValidation(
+ void afterDeploymentValidation(
@Observes final AfterDeploymentValidation afterDeploymentValidation,
final BeanManager beanManager) {
- logger.info("******* AfterDeploymentValidation");
+ // Ensure the configuration is started.
+ CdiUtilities.getReference(beanManager, Configuration.class).commandBus();
}
- private void init(@Observes @Initialized(ApplicationScoped.class) Object initialized) {
- logger.info("init(): ApplicationScoped is @Initialized!");
+ void init(@Observes @Initialized(ApplicationScoped.class) Object initialized) {
}
- private void destroy(@Observes @Destroyed(ApplicationScoped.class) final Object destroyed) {
- logger.info("init(): ApplicationScoped is @Destroyed!");
+ void destroy(@Observes @Destroyed(ApplicationScoped.class) final Object destroyed) {
}
- private void beforeShutdown(@Observes BeforeShutdown event, BeanManager beanManager) {
- logger.info("beforeShutdown()");
+ void beforeShutdown(@Observes BeforeShutdown event, BeanManager beanManager) {
}
- private static class LazyRetrievedModuleConfiguration implements ModuleConfiguration {
+ private Configuration startConfiguration(Configurer configurer) {
+ logger.info("Starting Axon configuration.");
- private final Supplier delegateSupplier;
- private final Class> moduleType;
- private ModuleConfiguration delegate;
+ return configurer.start();
+ }
- LazyRetrievedModuleConfiguration(Supplier delegateSupplier, Class> moduleType) {
- this.delegateSupplier = delegateSupplier;
- this.moduleType = moduleType;
- }
+ private void registerMessageHandlers(BeanManager beanManager, Configurer configurer) {
+ for (MessageHandlingBeanDefinition messageHandler : messageHandlers) {
+ Component
@@ -96,7 +96,7 @@
exec-maven-plugin
1.6.0
- org.axonframework.cdi.example.javase.AccountApplication
+ org.axonframework.extensions.cdi.example.javase.AccountApplication
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/AccountApplication.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/AccountApplication.java
index 7f2c923..a296705 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/AccountApplication.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/AccountApplication.java
@@ -1,10 +1,10 @@
-package org.axonframework.cdi.example.javase;
+package org.axonframework.extensions.cdi.example.javase;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
import javax.inject.Inject;
-import org.axonframework.cdi.example.javase.command.CreateAccountCommand;
+import org.axonframework.extensions.cdi.example.javase.command.CreateAccountCommand;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.interceptors.EventLoggingInterceptor;
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/Account.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/Account.java
index aa09755..8afb0e2 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/Account.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/Account.java
@@ -1,9 +1,9 @@
-package org.axonframework.cdi.example.javase.command;
+package org.axonframework.extensions.cdi.example.javase.command;
import java.lang.invoke.MethodHandles;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.axonframework.cdi.stereotype.Aggregate;
+import org.axonframework.extensions.cdi.stereotype.Aggregate;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.commandhandling.model.AggregateIdentifier;
import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/AccountCreatedEvent.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/AccountCreatedEvent.java
index e26cd0b..1f9df6e 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/AccountCreatedEvent.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/AccountCreatedEvent.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.command;
+package org.axonframework.extensions.cdi.example.javase.command;
public class AccountCreatedEvent {
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/CreateAccountCommand.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/CreateAccountCommand.java
index 45b429a..23b4c2e 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/CreateAccountCommand.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/command/CreateAccountCommand.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.command;
+package org.axonframework.extensions.cdi.example.javase.command;
import org.axonframework.commandhandling.TargetAggregateIdentifier;
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/configuration/AxonConfiguration.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/configuration/AxonConfiguration.java
index 35ae0b2..8f06245 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/configuration/AxonConfiguration.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/configuration/AxonConfiguration.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.configuration;
+package org.axonframework.extensions.cdi.example.javase.configuration;
import java.io.Serializable;
import javax.enterprise.context.ApplicationScoped;
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/AccountProjection.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/AccountProjection.java
index 61bfccc..6a37243 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/AccountProjection.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/AccountProjection.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.query;
+package org.axonframework.extensions.cdi.example.javase.query;
import java.lang.invoke.MethodHandles;
import java.util.HashMap;
@@ -6,7 +6,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.ApplicationScoped;
-import org.axonframework.cdi.example.javase.command.AccountCreatedEvent;
+import org.axonframework.extensions.cdi.example.javase.command.AccountCreatedEvent;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.queryhandling.QueryHandler;
diff --git a/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/GenericEventListener.java b/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/GenericEventListener.java
index ab990b7..075f548 100644
--- a/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/GenericEventListener.java
+++ b/example/javase/src/main/java/org/axonframework/cdi/example/javase/query/GenericEventListener.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.query;
+package org.axonframework.extensions.cdi.example.javase.query;
import java.lang.invoke.MethodHandles;
import java.util.logging.Level;
diff --git a/example/javase/src/test/java/org/axonframework/cdi/example/javase/command/AccountTest.java b/example/javase/src/test/java/org/axonframework/cdi/example/javase/command/AccountTest.java
index f9e5c39..5259c50 100644
--- a/example/javase/src/test/java/org/axonframework/cdi/example/javase/command/AccountTest.java
+++ b/example/javase/src/test/java/org/axonframework/cdi/example/javase/command/AccountTest.java
@@ -1,4 +1,4 @@
-package org.axonframework.cdi.example.javase.command;
+package org.axonframework.extensions.cdi.example.javase.command;
import org.axonframework.test.aggregate.AggregateTestFixture;
import org.junit.Test;
diff --git a/example/thorntail/src/main/java/org/axonframework/extension/example/swarm/aggregate/Customer.java b/example/thorntail/src/main/java/org/axonframework/extension/example/swarm/aggregate/Customer.java
index ef2561f..1a49da7 100644
--- a/example/thorntail/src/main/java/org/axonframework/extension/example/swarm/aggregate/Customer.java
+++ b/example/thorntail/src/main/java/org/axonframework/extension/example/swarm/aggregate/Customer.java
@@ -2,7 +2,7 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
-import org.axonframework.cdi.stereotype.Aggregate;
+import org.axonframework.extensions.cdi.stereotype.Aggregate;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.commandhandling.model.AggregateIdentifier;
import org.axonframework.eventsourcing.EventSourcingHandler;
diff --git a/pom.xml b/pom.xml
index 969aae3..163793b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,9 +15,7 @@
~ limitations under the License.
-->
-
+
org.axonframework.extensions.cdi
axon-cdi-parent
@@ -48,70 +46,35 @@
https://github.com/AxonFramework/extension-cdi/issues
-
-
- release-sign-artifacts
-
-
- performRelease
- true
-
-
-
-
-
- org.apache.maven.plugins
- maven-gpg-plugin
- 1.6
-
-
- sign-artifacts
- verify
-
-
- sign
-
-
-
-
-
-
-
-
-
- coverage
-
-
-
- org.jacoco
- jacoco-maven-plugin
- 0.8.1
-
-
-
-
- prepare-agent
-
-
-
- report
- prepare-package
-
- report
-
-
-
-
-
-
-
-
-
-
UTF-8
- 4.1
+
+ 1.8
+ 7.0
+
+
+
+
+ 3.1.0
+ 3.8.1
+ 3.1.0
+ 3.1.1
+ 3.1.2
+ 3.1.1
+ 3.0.0-M1
+ 3.0.0-M1
+ 2.5.3
+ 3.8.2
+ 3.1.0
+ 3.0.0-M3
+ 0.8.4
+ 2.7
+ 3.0.0-M2
+ 1.6
+
+
+ 4.2
1.7.25
1.2.17
@@ -119,13 +82,8 @@
4.12
2.15.0
-
-
- 2.0
- 1.3
-
- 3.0.5.Final
- 1.3.1.Final
+ 2.4.7.Final
+ 1.3.0.Final
@@ -137,21 +95,32 @@
axon-configuration
${axon.version}
-
-
- javax.enterprise
- cdi-api
- ${cdi-api.version}
+ org.axonframework
+ axon-test
+ ${axon.version}
-
- javax.transaction
- javax.transaction-api
- ${transaction.version}
+ javax
+ javaee-api
+ ${javaee-api.version}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
org.jboss.weld.se
@@ -180,6 +149,16 @@
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ org.slf4j
+ slf4j-simple
+ ${slf4j.version}
+
org.slf4j
jul-to-slf4j
@@ -232,52 +211,141 @@
-
- javax.enterprise
- cdi-api
- provided
-
+
+
+
+
+
+
+ maven-enforcer-plugin
+ ${maven-enforcer-plugin.version}
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+ ${maven-versions-plugin.version}
+
maven-clean-plugin
- 3.0.0
+ ${maven-clean-plugin.version}
maven-install-plugin
- 2.5.2
+ ${maven-install-plugin.version}
+
+
+ maven-site-plugin
+ ${maven-site-plugin.version}
+
+
+ maven-resources-plugin
+ ${maven-resources-plugin.version}
+
+
+ maven-deploy-plugin
+ ${maven-deploy-plugin.version}
+
+
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ maven-assembly-plugin
+ ${maven-assemply-plugin.version}
+
+
+ maven-release-plugin
+ ${maven-release-plugin.version}
+
+
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${maven-jacoco-plugin.version}
+
+
+ maven-javadoc-plugin
+ ${maven-javadoc-plugin.version}
+
+
+ maven-jar-plugin
+ ${maven-jar-plugin.version}
+
+
+ maven-source-plugin
+ ${maven-source-plugin.version}
+
+
+ maven-gpg-plugin
+ ${maven-gpg-version}
+
+
- maven-resources-plugin
- 3.0.2
+ maven-enforcer-plugin
+
+
+
+ enforce-maven
+
+ enforce
+
+
+
+
+ ${java.version}
+
+
+ 3.5
+
+
+
+
+
+
+
+
+ org.codehaus.mojo
+ versions-maven-plugin
+
- UTF-8
+ false
+
- maven-deploy-plugin
- 2.8.2
+ maven-resources-plugin
+
+
+ UTF-8
+
+
maven-compiler-plugin
- 3.5.1
+
- 1.8
- 1.8
+ ${java.version}
+ ${java.version}
UTF-8
+
- org.apache.maven.plugins
maven-assembly-plugin
- 2.6
+
assembly
@@ -285,18 +353,20 @@
+
maven-release-plugin
- 2.5.3
+
forked-path
true
false
+
maven-surefire-plugin
- 2.19.1
+
**/*Test.java
@@ -310,9 +380,10 @@
+
maven-javadoc-plugin
- 2.10.4
+
attach-javadoc
@@ -323,12 +394,13 @@
- -Xdoclint:none
+ none
+
maven-jar-plugin
- 3.0.2
+
@@ -337,9 +409,10 @@
+
maven-source-plugin
- 3.0.1
+
attach-sources
@@ -350,33 +423,68 @@
-
-
- maven-enforcer-plugin
- 1.4.1
-
-
- enforce-java
- deploy
-
- enforce
-
-
-
-
- 1.8
-
-
- 3.5
-
-
-
-
-
-
+
+
+
+ release-sign-artifacts
+
+
+ performRelease
+ true
+
+
+
+
+
+ maven-gpg-plugin
+
+
+
+ sign-artifacts
+ verify
+
+
+ sign
+
+
+
+
+
+
+
+
+
+ coverage
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+
+ prepare-agent
+
+
+
+ report
+ prepare-package
+
+ report
+
+
+
+
+
+
+
+
+
+
sonatype
@@ -398,8 +506,8 @@
- scm:git:git://github.com/AxonFramework/extension-mongo.git
- scm:git:git@github.com:AxonFramework/extension-mongo.git
+ scm:git:git://github.com/AxonFramework/extension-cdi.git
+ scm:git:git@github.com:AxonFramework/extension-cdi.git
https://github.com/AxonFramework/extension-cdi
HEAD