All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scalified.axonframework.cdi.CdiExtension Maven / Gradle / Ivy

There is a newer version: 4.10.3
Show newest version
/*
 * Copyright 2019 Scalified
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.scalified.axonframework.cdi;

import com.scalified.axonframework.cdi.api.*;
import com.scalified.axonframework.cdi.api.annotation.Aggregate;
import com.scalified.axonframework.cdi.api.annotation.AxonComponent;
import com.scalified.axonframework.cdi.api.annotation.Saga;
import com.scalified.axonframework.cdi.commons.CdiUtils;
import com.scalified.axonframework.cdi.commons.ReflectionUtils;
import com.scalified.axonframework.cdi.component.Component;
import com.scalified.axonframework.cdi.component.ComponentResolver;
import com.scalified.axonframework.cdi.component.ConfigurableComponentResolver;
import com.scalified.axonframework.cdi.configuration.LazyRetrievedModuleConfiguration;
import com.scalified.axonframework.cdi.configuration.transaction.JtaTransactionManager;
import com.scalified.axonframework.cdi.event.AxonConfiguredEvent;
import com.scalified.axonframework.cdi.event.AxonStartedEvent;
import com.scalified.axonframework.cdi.event.AxonStoppedEvent;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.CommandHandler;
import org.axonframework.common.AxonConfigurationException;
import org.axonframework.common.transaction.TransactionManager;
import org.axonframework.config.*;
import org.axonframework.eventhandling.ErrorHandler;
import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.EventHandler;
import org.axonframework.eventhandling.ListenerInvocationErrorHandler;
import org.axonframework.eventsourcing.eventstore.EventStorageEngine;
import org.axonframework.messaging.MessageDispatchInterceptor;
import org.axonframework.messaging.correlation.CorrelationDataProvider;
import org.axonframework.messaging.interceptors.CorrelationDataInterceptor;
import org.axonframework.modelling.saga.ResourceInjector;
import org.axonframework.queryhandling.QueryBus;
import org.axonframework.queryhandling.QueryHandler;
import org.axonframework.queryhandling.QueryUpdateEmitter;
import org.axonframework.serialization.Serializer;
import org.axonframework.serialization.upcasting.event.EventUpcaster;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;

/**
 * {@link Extension} for Axon configuration
 *
 * @author shell
 * @since 2019-04-12
 */
@Slf4j
@ApplicationScoped
public class CdiExtension implements Extension {

	/**
	 * Underlying {@code configurer}
	 */
	private Configurer configurer = DefaultConfigurer.defaultConfiguration(false);

	/**
	 * Underlying {@code configuration}
	 */
	@Getter(AccessLevel.PACKAGE)
	private Configuration configuration;

	/**
	 * Axon configuration properties component
	 */
	private Component axonPropertiesComponent;

	/**
	 * {@link org.axonframework.modelling.command.Aggregate} types
	 */
	private List> aggregateTypes = new LinkedList<>();

	/**
	 * Default {@link AggregateConfigurator} component
	 */
	private Component defaultAggregateConfiguratorComponent;

	/**
	 * {@link AggregateConfigurator} components
	 */
	private Map, Component> aggregateConfiguratorComponents = new HashMap<>();

	/**
	 * {@link org.axonframework.modelling.saga.Saga} types
	 */
	private List> sagaTypes = new LinkedList<>();

	/**
	 * Default {@link SagaConfigurator} component
	 */
	private Component defaultSagaConfiguratorComponent;

	/**
	 * {@link SagaConfigurator} components
	 */
	private Map, Component> sagaConfiguratorComponents = new HashMap<>();

	/**
	 * {@link EventProcessingConfigurator} component
	 */
	private Component eventProcessingConfiguratorComponent;

	/**
	 * {@link Serializer} components
	 */
	private Map serializerComponents = new HashMap<>();

	/**
	 * CommandHandler types
	 */
	private List commandHandlerTypes = new LinkedList<>();

	/**
	 * EventHandler types
	 */
	private List eventHandlerTypes = new LinkedList<>();

	/**
	 * QueryHandler types
	 */
	private List queryHandlerTypes = new LinkedList<>();

	/**
	 * {@link TransactionManager} component
	 */
	private Component transactionManagerComponent;

	/**
	 * {@link CommandBus} component
	 */
	private Component commandBusComponent;

	/**
	 * {@link EventStorageEngine} component
	 */
	private Component eventStorageEngineComponent;

	/**
	 * {@link EventBus} component
	 */
	private Component eventBusComponent;

	/**
	 * {@link QueryBus} component
	 */
	private Component queryBusComponent;

	/**
	 * {@link ResourceInjector} component
	 */
	private Component resourceInjectorComponent;

	/**
	 * {@link QueryUpdateEmitter} component
	 */
	private Component queryUpdateEmitterComponent;

	/**
	 * {@link ErrorHandler} component
	 */
	private Component errorHandlerComponent;

	/**
	 * {@link ListenerInvocationErrorHandler} component
	 */
	private Component listenerInvocationErrorHandlerComponent;

	/**
	 * {@link CommandDispatchInterceptor} components
	 */
	private List commandDispatchInterceptorComponents = new LinkedList<>();

	/**
	 * {@link EventDispatchInterceptor} components
	 */
	private List eventDispatchInterceptorComponents = new LinkedList<>();

	/**
	 * {@link EventUpcaster} components
	 */
	private List eventUpcasterComponents = new LinkedList<>();

	/**
	 * {@link CorrelationDataProvider} components
	 */
	private List correlationDataProviderComponents = new LinkedList<>();

	/**
	 * {@link ModuleConfiguration} components
	 */
	private List moduleConfigurationComponents = new LinkedList<>();

	/**
	 * {@link ConfigurerModule} components
	 */
	private List configurerModuleComponents = new LinkedList<>();

	/**
	 * Custom components
	 */
	private List customComponents = new LinkedList<>();

	/**
	 * Processes the given {@link AxonProperties} annotated {@code type}
	 *
	 * @param processAnnotatedType to process
	 * @param                   {@link AxonProperties} type
	 */
	 void processAxonPropertiesAnnotatedType(
			@Observes ProcessAnnotatedType processAnnotatedType) {
		Type type = processAnnotatedType.getAnnotatedType().getBaseType();
		axonPropertiesComponent = new Component(type);
		log.trace("Initialized AxonProperties component: {} ", axonPropertiesComponent);
	}

	/**
	 * Processes the given {@link AxonProperties} {@code processProducer}
	 *
	 * @param processProducer to process
	 * @param              the bean class of the bean that declares the producer
	 *                        method or field
	 * @param              {@link AxonProperties} type
	 */
	 void processAxonPropertiesProducer(@Observes ProcessProducer processProducer) {
		Producer producer = processProducer.getProducer();
		AnnotatedMember annotatedMember = processProducer.getAnnotatedMember();
		Type type = annotatedMember.getBaseType();
		axonPropertiesComponent = new Component(type, producer);
		log.trace("Initialized AxonProperties component: {} ", axonPropertiesComponent);
	}

	/**
	 * Processes the given {@code type} annotated with {@code Aggregate} annotation
	 *
	 * @param type {@link ProcessAnnotatedType} to process
	 * @param   the class being annotated
	 */
	 void processAggregateAnnotated(@Observes @WithAnnotations({Aggregate.class}) ProcessAnnotatedType type) {
		Class aggregateType = type.getAnnotatedType().getJavaClass();
		aggregateTypes.add(aggregateType);
		log.trace("Initialized Aggregate class: {}", aggregateType);
	}

	/**
	 * Processes the given {@code type} annotated with {@code Saga} annotation
	 *
	 * @param type {@link ProcessAnnotatedType} to process
	 * @param   the class being annotated
	 */
	 void processSagaAnnotated(@Observes @WithAnnotations({Saga.class}) ProcessAnnotatedType type) {
		Class sagaType = type.getAnnotatedType().getJavaClass();
		sagaTypes.add(sagaType);
		log.trace("Initialized Saga class: {}", sagaType);
	}

	/**
	 * Processes the given {@code processAnnotatedType} annotated with
	 * {@code AxonComponent} annotation
	 *
	 * @param processAnnotatedType {@link ProcessAnnotatedType} to process
	 * @param                   the class being annotated
	 */
	 void processAxonComponentAnnotatedType(
			@Observes @WithAnnotations({AxonComponent.class}) ProcessAnnotatedType processAnnotatedType) {
		if (CdiUtils.hasAnnotation(processAnnotatedType, AxonComponent.class)) {
			AnnotatedType annotatedType = processAnnotatedType.getAnnotatedType();
			AxonComponent annotation = annotatedType.getAnnotation(AxonComponent.class);
			Type type = annotatedType.getBaseType();
			Component component = new Component(type);
			initAxonComponent(annotation, component);
		}
	}

	/**
	 * Processes the given {@code processProducer}
	 *
	 * @param processProducer {@link ProcessProducer} to process
	 * @param              the bean class of the bean that declares the producer method or field
	 * @param              the return type of the producer method or the type of the producer field
	 */
	 void processAxonComponentProducer(@Observes ProcessProducer processProducer) {
		if (CdiUtils.hasAnnotation(processProducer, AxonComponent.class)) {
			Producer producer = processProducer.getProducer();
			AnnotatedMember annotatedMember = processProducer.getAnnotatedMember();
			AxonComponent annotation = annotatedMember.getAnnotation(AxonComponent.class);
			Type type = annotatedMember.getBaseType();
			Component component = new Component(type, producer);
			initAxonComponent(annotation, component);
		}
	}

	/**
	 * Initializes Axon {@code component} based on its type and the given
	 * {@code annotated} annotation initialization data
	 *
	 * @param annotation annotation use to obtain additional initialization data
	 * @param component  component to initialize
	 */
	private void initAxonComponent(AxonComponent annotation, Component component) {
		Type actualType = Optional.ofNullable(ReflectionUtils.getTypeArgument(component.getType(), Configurable.class))
				.orElse(component.getType());

		boolean initialized = false;

		if (TypeUtils.isAssignable(actualType, AggregateConfigurator.class)) {
			initialized = initAggregateConfiguratorComponent(annotation.ref(), component);
		}
		if (TypeUtils.isAssignable(actualType, SagaConfigurator.class)) {
			initialized = initSagaConfiguratorComponent(annotation.ref(), component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, EventProcessingConfigurator.class)) {
			initialized = initEventProcessingConfiguratorComponent(component) || initialized;
		}

		if (TypeUtils.isAssignable(actualType, Serializer.class)) {
			initialized = initSerializerComponent(annotation.value(), component) || initialized;
		}

		if (ReflectionUtils.hasAnnotatedMethod(actualType, CommandHandler.class)) {
			initialized = initCommandHandlerType(actualType) || initialized;
		}
		if (ReflectionUtils.hasAnnotatedMethod(actualType, EventHandler.class)) {
			initialized = initEventHandlerType(actualType) || initialized;
		}
		if (ReflectionUtils.hasAnnotatedMethod(actualType, QueryHandler.class)) {
			initialized = initQueryHandlerType(actualType) || initialized;
		}

		if (TypeUtils.isAssignable(actualType, TransactionManager.class)) {
			initialized = initTransactionManagerComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, CommandBus.class)) {
			initialized = initCommandBusComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, EventStorageEngine.class)) {
			initialized = initEventStorageEngineComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, EventBus.class)) {
			initialized = initEventBusComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, QueryBus.class)) {
			initialized = initQueryBusComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, ResourceInjector.class)) {
			initialized = initResourceInjectorComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, QueryUpdateEmitter.class)) {
			initialized = initQueryUpdateEmitterComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, ErrorHandler.class)) {
			initialized = initErrorHandlerComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, ListenerInvocationErrorHandler.class)) {
			initialized = initListenerInvocationErrorHandlerComponent(component) || initialized;
		}

		if (TypeUtils.isAssignable(actualType, CommandDispatchInterceptor.class)) {
			initialized = initCommandDispatchInterceptorComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, EventDispatchInterceptor.class)) {
			initialized = initEventDispatchInterceptorComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, EventUpcaster.class)) {
			initialized = initEventUpcasterComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, CorrelationDataProvider.class)) {
			initialized = initCorrelationDataProviderComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, ModuleConfiguration.class)) {
			initialized = initModuleConfigurationComponent(component) || initialized;
		}
		if (TypeUtils.isAssignable(actualType, ConfigurerModule.class)) {
			initialized = initConfigurerModuleComponent(component) || initialized;
		}

		if (!initialized) {
			initCustomComponent(component);
		}
	}

	/**
	 * Initializes {@code defaultAggregateConfiguratorComponent} if the given
	 * {@code aggregateType} is not specific (default), otherwise adds the given
	 * {@code component} to the {@code aggregateConfiguratorComponents} by the given
	 * {@code aggregateType}
	 *
	 * @param aggregateType {@link org.axonframework.modelling.command.Aggregate} type
	 * @param component     component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initAggregateConfiguratorComponent(Class aggregateType, Component component) {
		if (!Objects.equals(Object.class, aggregateType)) {
			if (aggregateConfiguratorComponents.containsKey(aggregateType)) {
				throw new AxonConfigurationException(String.format("Multiple AggregateConfigurator components " +
						"for the same '%s' aggregate declared", aggregateType));
			}
			aggregateConfiguratorComponents.put(aggregateType, component);
			log.trace("Initialized AggregateConfigurator component: {}", component);
		} else {
			if (nonNull(defaultAggregateConfiguratorComponent)) {
				throw new AxonConfigurationException("Multiple default AggregateConfigurator components " +
						"declared. Please specify referenced aggregate to distinguish configurations");
			}
			defaultAggregateConfiguratorComponent = component;
			log.trace("Initialized default AggregateConfigurator component: {}", defaultAggregateConfiguratorComponent);
		}
		return true;
	}

	/**
	 * Initializes {@code defaultSagaConfiguratorComponent} if the given {@code sagaType}
	 * is not specific (default), otherwise adds the given {@code component} to the
	 * {@code sagaConfiguratorComponents} by the given {@code sagaType}
	 *
	 * @param sagaType  {@link org.axonframework.modelling.saga.Saga} type
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initSagaConfiguratorComponent(Class sagaType, Component component) {
		if (!Objects.equals(Object.class, sagaType)) {
			if (sagaConfiguratorComponents.containsKey(sagaType)) {
				throw new AxonConfigurationException(String.format("Multiple SagaConfigurator components " +
						"for the same '%s' saga declared", sagaType));
			}
			sagaConfiguratorComponents.put(sagaType, component);
			log.trace("Initialized SagaConfigurator component: {}", component);
		} else {
			if (nonNull(defaultSagaConfiguratorComponent)) {
				throw new AxonConfigurationException("Multiple default SagaConfigurator components declared. " +
						"Please specify referenced saga to distinguish configurations");
			}
			defaultSagaConfiguratorComponent = component;
			log.trace("Initialized default SagaConfigurator component: {}", defaultSagaConfiguratorComponent);
		}
		return true;
	}

	/**
	 * Initializes {@code eventProcessingConfiguratorComponent} from the given
	 * {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initEventProcessingConfiguratorComponent(Component component) {
		if (nonNull(eventProcessingConfiguratorComponent)) {
			throw new AxonConfigurationException("Multiple EventProcessingConfigurator components declared");
		}
		eventProcessingConfiguratorComponent = component;
		log.trace("Initialized EventProcessingConfigurator component: {}", eventProcessingConfiguratorComponent);
		return true;
	}

	/**
	 * Adds the given {@code component} to {@code serializerComponents} by its
	 * {@code type}
	 *
	 * @param type      {@link SerializerType} qualifier value
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initSerializerComponent(String type, Component component) {
		String assignedSerializerType = StringUtils.isBlank(type) ? SerializerType.DEFAULT : type;
		String[] serializerTypes = new String[]{SerializerType.DEFAULT, SerializerType.EVENT, SerializerType.MESSAGE};
		if (!ArrayUtils.contains(serializerTypes, assignedSerializerType)) {
			throw new AxonConfigurationException(String.format("Unknown Serializer '%s' name declared. " +
					"Please choose one among SerializerType", assignedSerializerType));
		}
		if (serializerComponents.containsKey(assignedSerializerType)) {
			throw new AxonConfigurationException(String.format("Multiple Serializer components declared " +
					"for %s serializer", assignedSerializerType));
		}
		serializerComponents.put(assignedSerializerType, component);
		log.trace("Initialized Serializer component: {}", component);
		return true;
	}

	/**
	 * Adds the given CommandHandler {@code type} to {@code commandHandlerTypes}
	 *
	 * @param type CommandHandler type to add
	 * @return {@code true} if the CommandHandler {@code type} was added,
	 * {@code false} otherwise
	 */
	private boolean initCommandHandlerType(Type type) {
		commandHandlerTypes.add(type);
		log.trace("Initialized CommandHandler class: {}", type);
		return true;
	}

	/**
	 * Adds the given EventHandler {@code type} to {@code eventHandlerTypes}
	 *
	 * @param type EventHandler type to add
	 * @return {@code true} if the EventHandler {@code type} was added,
	 * {@code false} otherwise
	 */
	private boolean initEventHandlerType(Type type) {
		eventHandlerTypes.add(type);
		log.trace("Initialized EventHandler class: {}", type);
		return true;
	}

	/**
	 * Adds the given QueryHandler {@code type} to {@code queryHandlerTypes}
	 *
	 * @param type QueryHandler type to add
	 * @return {@code true} if the QueryHandler {@code type} was added,
	 * {@code false} otherwise
	 */
	private boolean initQueryHandlerType(Type type) {
		queryHandlerTypes.add(type);
		log.trace("Initialized QueryHandler class: {}", type);
		return true;
	}

	/**
	 * Initializes {@code transactionManagerComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initTransactionManagerComponent(Component component) {
		if (nonNull(transactionManagerComponent)) {
			throw new AxonConfigurationException("Multiple TransactionManager components declared");
		}
		transactionManagerComponent = component;
		log.trace("Initialized TransactionManager component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code commandBusComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initCommandBusComponent(Component component) {
		if (nonNull(commandBusComponent)) {
			throw new AxonConfigurationException("Multiple CommandBus components declared");
		}
		commandBusComponent = component;
		log.trace("Initialized CommandBus component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code eventStorageEngineComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initEventStorageEngineComponent(Component component) {
		if (nonNull(eventStorageEngineComponent)) {
			throw new AxonConfigurationException("Multiple EventStorageEngine components declared");
		}
		eventStorageEngineComponent = component;
		log.trace("Initialized EventStorageEngine component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code eventBusComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initEventBusComponent(Component component) {
		if (nonNull(eventBusComponent)) {
			throw new AxonConfigurationException("Multiple EventBus components declared");
		}
		eventBusComponent = component;
		log.trace("Initialized EventBus component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code queryBusComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initQueryBusComponent(Component component) {
		if (nonNull(queryBusComponent)) {
			throw new AxonConfigurationException("Multiple QueryBus components declared");
		}
		queryBusComponent = component;
		log.trace("Initialized QueryBus component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code resourceInjectorComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initResourceInjectorComponent(Component component) {
		if (nonNull(resourceInjectorComponent)) {
			throw new AxonConfigurationException("Multiple ResourceInjector components declared");
		}
		resourceInjectorComponent = component;
		log.trace("Initialized ResourceInjector component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code queryUpdateEmitterComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initQueryUpdateEmitterComponent(Component component) {
		if (nonNull(queryUpdateEmitterComponent)) {
			throw new AxonConfigurationException("Multiple QueryUpdateEmitter components declared");
		}
		queryUpdateEmitterComponent = component;
		log.trace("Initialized QueryUpdateEmitter component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code errorHandlerComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initErrorHandlerComponent(Component component) {
		if (nonNull(errorHandlerComponent)) {
			throw new AxonConfigurationException("Multiple ErrorHandler components declared");
		}
		errorHandlerComponent = component;
		log.trace("Initialized ErrorHandler component: {}", component);
		return true;
	}

	/**
	 * Initializes {@code listenerInvocationErrorHandlerComponent} from the given {@code component}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 * @throws AxonConfigurationException in case of initialization error
	 */
	private boolean initListenerInvocationErrorHandlerComponent(Component component) {
		if (nonNull(listenerInvocationErrorHandlerComponent)) {
			throw new AxonConfigurationException("Multiple ListenerInvocationErrorHandler components declared");
		}
		listenerInvocationErrorHandlerComponent = component;
		log.trace("Initialized ListenerInvocationErrorHandler component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code commandDispatchInterceptorComponents}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initCommandDispatchInterceptorComponent(Component component) {
		commandDispatchInterceptorComponents.add(component);
		log.trace("Initialized CommandDispatchInterceptor component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code eventDispatchInterceptorComponents}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initEventDispatchInterceptorComponent(Component component) {
		eventDispatchInterceptorComponents.add(component);
		log.trace("Initialized EventDispatchInterceptor component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code eventUpcasterComponents}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initEventUpcasterComponent(Component component) {
		eventUpcasterComponents.add(component);
		log.trace("Initialized EventUpcaster component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code correlationDataProviderComponents}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initCorrelationDataProviderComponent(Component component) {
		correlationDataProviderComponents.add(component);
		log.trace("Initialized CorrelationDataProvider component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code moduleConfiguration}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initModuleConfigurationComponent(Component component) {
		moduleConfigurationComponents.add(component);
		log.trace("Initialized ModuleConfiguration component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code configurerModuleComponents}
	 *
	 * @param component component to initialize
	 * @return {@code true} if the {@code component} was initialized, {@code false} otherwise
	 */
	private boolean initConfigurerModuleComponent(Component component) {
		configurerModuleComponents.add(component);
		log.trace("Initialized ConfigurerModule component: {}", component);
		return true;
	}

	/**
	 * Adds the given {@code component} to the {@code customComponents}
	 *
	 * @param component component to initialize
	 */
	private void initCustomComponent(Component component) {
		customComponents.add(component);
		log.trace("Initialized custom component: {}", component);
	}

	/**
	 * Invoked after container has validated that there are no deployment problems
	 * and before creating contexts or processing requests
	 *
	 * 

* Fires {@link AxonConfiguredEvent} * *

* May fire {@link AxonStartedEvent} if {@link AxonProperties#isAutoStartEnabled()} * is {@code true} * * @param event an event fired after deployment validated * @param beanManager current {@link BeanManager} * @see AxonProperties * @see AxonConfiguredEvent * @see AxonStartedEvent */ void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager beanManager) { log.debug("Configuring Axon application"); AxonProperties axonProperties = resolveProperties(beanManager); configureAggregates(beanManager); configureSagas(beanManager); configureEventProcessing(beanManager); configureSerializer(beanManager); configureCommandHandlers(beanManager); configureEventHandlers(beanManager); configureQueryHandlers(beanManager); configureTransactionManager(beanManager); configureCommandBus(beanManager); configureEventBus(beanManager); configureEventStorageEngine(beanManager); configureQueryBus(beanManager); configureResourceInjector(beanManager); configureQueryUpdateEmitter(beanManager); configureErrorHandler(beanManager); configureListenerInvocationErrorHandler(beanManager); configureEventUpcasters(beanManager); configureModules(beanManager); configureConfigurerModules(beanManager); configureCorrelationDataProviders(beanManager); configureCustomComponents(beanManager); configuration = configurer.buildConfiguration(); configureCommandDispatchInterceptors(beanManager); configureEventDispatchInterceptors(beanManager); log.info("Axon application configured"); beanManager.fireEvent(new AxonConfiguredEvent(configuration)); if (axonProperties.isAutoStartEnabled()) { log.debug("Starting Axon application"); configuration.start(); log.info("Axon application started"); beanManager.fireEvent(new AxonStartedEvent()); } else { log.info("Skipping Axon auto start since disabled"); } } /** * Resolves Axon configuration properties * * @param beanManager current {@link BeanManager} * @return Axon configuration properties */ private AxonProperties resolveProperties(BeanManager beanManager) { return Optional.ofNullable(axonPropertiesComponent) .map(component -> ComponentResolver.of(component).resolve(beanManager)) .orElseGet(() -> AxonProperties.builder().build()); } /** * Configures Axon {@link org.axonframework.modelling.command.Aggregate} instances * * @param beanManager current {@link BeanManager} * @see Configurer#configureAggregate(Class) * @see Configurer#configureAggregate(AggregateConfiguration) */ private void configureAggregates(BeanManager beanManager) { List> unknownAggregateReferences = aggregateConfiguratorComponents.keySet() .stream() .filter(type -> !aggregateTypes.contains(type)) .collect(Collectors.toList()); if (!unknownAggregateReferences.isEmpty()) { throw new AxonConfigurationException(String.format("Unknown AggregateConfigurator components for " + "aggregates declared: %s", unknownAggregateReferences)); } for (Class aggregateType : aggregateTypes) { Component component = aggregateConfiguratorComponents.getOrDefault( aggregateType, defaultAggregateConfiguratorComponent); if (isNull(component)) { configurer = configurer.configureAggregate(aggregateType); } else { AggregateConfigurator configurator = ComponentResolver.of(component).resolve(beanManager); configurer = configurer.configureAggregate( configurator.apply(ReflectionUtils.getRawType(aggregateType))); } log.debug("Configured Aggregate: {}", aggregateType); } } /** * Configures Axon {@link org.axonframework.modelling.saga.Saga} instances * * @param beanManager current {@link BeanManager} * @see EventProcessingConfigurer#registerSaga(Class) * @see EventProcessingConfigurer#registerSaga(Class, Consumer) */ private void configureSagas(BeanManager beanManager) { List> unknownSagaReferences = sagaConfiguratorComponents.keySet() .stream() .filter(type -> !sagaTypes.contains(type)) .collect(Collectors.toList()); if (!unknownSagaReferences.isEmpty()) { throw new AxonConfigurationException(String.format("Unknown SagaConfigurator references to " + "sagas declared: %s", unknownSagaReferences)); } for (Class sagaType : sagaTypes) { Component component = sagaConfiguratorComponents.getOrDefault(sagaType, defaultSagaConfiguratorComponent); if (isNull(component)) { configurer = configurer.eventProcessing(eventProcessingConfigurer -> eventProcessingConfigurer.registerSaga(sagaType)); } else { SagaConfigurator configurator = ComponentResolver.of(component).resolve(beanManager); configurer = configurer.eventProcessing(eventProcessingConfigurer -> eventProcessingConfigurer.registerSaga(ReflectionUtils.getRawType(sagaType), configurator)); } log.debug("Configured Saga: {}", sagaType); } } /** * Configures Axon {@link EventProcessingConfigurer} * * @param beanManager current {@link BeanManager} * @see Configurer#eventProcessing(Consumer) */ private void configureEventProcessing(BeanManager beanManager) { if (nonNull(eventProcessingConfiguratorComponent)) { EventProcessingConfigurator configurator = ComponentResolver.of(eventProcessingConfiguratorComponent).resolve(beanManager); configurer = configurer.eventProcessing(configurator); log.debug("Configured EventProcessing component: {}", eventProcessingConfiguratorComponent); } } /** * Configures Axon {@link Serializer} instances * * @param beanManager current {@link BeanManager} * @see Configurer#configureSerializer(Function) * @see Configurer#configureMessageSerializer(Function) * @see Configurer#configureEventSerializer(Function) */ private void configureSerializer(BeanManager beanManager) { if (!serializerComponents.isEmpty()) { Component defaultSerializerComponent = serializerComponents.get(SerializerType.DEFAULT); if (nonNull(defaultSerializerComponent)) { ConfigurableComponentResolver resolver = ConfigurableComponentResolver.of(defaultSerializerComponent); Configurable defaultSerializer = resolver.resolve(beanManager); configurer = configurer.configureSerializer(defaultSerializer); log.debug("Configured default Serializer: {}", defaultSerializerComponent); } Component messageSerializerComponent = serializerComponents.get(SerializerType.MESSAGE); if (nonNull(messageSerializerComponent)) { Configurable messageSerializer = ConfigurableComponentResolver.of(messageSerializerComponent).resolve(beanManager); configurer = configurer.configureMessageSerializer(messageSerializer); log.debug("Configured message Serializer: {}", messageSerializerComponent); } Component eventSerializerComponent = serializerComponents.get(SerializerType.EVENT); if (nonNull(eventSerializerComponent)) { Configurable eventSerializer = ConfigurableComponentResolver.of(eventSerializerComponent).resolve(beanManager); configurer = configurer.configureEventSerializer(eventSerializer); log.debug("Configured event Serializer: {}", eventSerializerComponent); } } } /** * Configures Axon CommandHandler instances * * @param beanManager current {@link BeanManager} * @see Configurer#registerCommandHandler(Function) */ private void configureCommandHandlers(BeanManager beanManager) { for (Type commandHandlerType : commandHandlerTypes) { Object commandHandler = CdiUtils.getReference(beanManager, commandHandlerType); configurer = configurer.registerCommandHandler(conf -> commandHandler); log.debug("Configured CommandHandler: {}", commandHandlerType); } } /** * Configures Axon EventHandler instances * * @param beanManager current {@link BeanManager} * @see Configurer#registerEventHandler(Function) */ private void configureEventHandlers(BeanManager beanManager) { for (Type eventHandlerType : eventHandlerTypes) { Object eventHandler = CdiUtils.getReference(beanManager, eventHandlerType); configurer = configurer.registerEventHandler(conf -> eventHandler); log.debug("Configured EventHandler: {}", eventHandlerType); } } /** * Configures Axon QueryHandler instances * * @param beanManager current {@link BeanManager} * @see Configurer#registerQueryHandler(Function) */ private void configureQueryHandlers(BeanManager beanManager) { for (Type queryHandlerType : queryHandlerTypes) { Object queryHandler = CdiUtils.getReference(beanManager, queryHandlerType); configurer = configurer.registerQueryHandler(conf -> queryHandler); log.debug("Configured QueryHandler: {}", queryHandlerType); } } /** * Configures Axon {@link TransactionManager} * * @param beanManager current {@link BeanManager} * @see Configurer#configureTransactionManager(Function) */ private void configureTransactionManager(BeanManager beanManager) { if (nonNull(transactionManagerComponent)) { Configurable configurable = ConfigurableComponentResolver.of(transactionManagerComponent).resolve(beanManager); configurer = configurer.configureTransactionManager(configurable); log.debug("Configured TransactionManager component: {}", transactionManagerComponent); } else { configurer = configurer.configureTransactionManager(conf -> new JtaTransactionManager()); log.debug("Configured default JtaTransactionManager"); } } /** * Configures Axon {@link CommandBus} * * @param beanManager current {@link BeanManager} * @see Configurer#configureCommandBus(Function) */ private void configureCommandBus(BeanManager beanManager) { if (nonNull(commandBusComponent)) { Configurable configurable = ConfigurableComponentResolver.of(commandBusComponent).resolve(beanManager); configurer = configurer.configureCommandBus(conf -> { CommandBus commandBus = configurable.apply(conf); commandBus.registerHandlerInterceptor( new CorrelationDataInterceptor<>(conf.correlationDataProviders())); return commandBus; }); log.debug("Configured CommandBus: {}", commandBusComponent); } } /** * Configures Axon {@link EventStorageEngine} * * @param beanManager current {@link BeanManager} * @see Configurer#configureEmbeddedEventStore(Function) */ private void configureEventStorageEngine(BeanManager beanManager) { if (nonNull(eventStorageEngineComponent)) { Configurable configurable = ConfigurableComponentResolver.of(eventStorageEngineComponent).resolve(beanManager); configurer = configurer.configureEmbeddedEventStore(configurable); log.debug("Configured EventStorageEngine: {}", eventStorageEngineComponent); } } /** * Configures Axon {@link EventBus} * * @param beanManager current {@link BeanManager} * @see Configurer#configureEventBus(Function) */ private void configureEventBus(BeanManager beanManager) { if (nonNull(eventBusComponent)) { Configurable configurable = ConfigurableComponentResolver.of(eventBusComponent).resolve(beanManager); configurer = configurer.configureEventBus(configurable); log.debug("Configured EventBus: {}", eventStorageEngineComponent); } } /** * Configures Axon {@link QueryBus} * * @param beanManager current {@link BeanManager} * @see Configurer#configureQueryBus(Function) */ private void configureQueryBus(BeanManager beanManager) { if (nonNull(queryBusComponent)) { Configurable configurable = ConfigurableComponentResolver.of(queryBusComponent).resolve(beanManager); configurer = configurer.configureQueryBus(configurable); log.debug("Configured QueryBus: {}", queryBusComponent); } } /** * Configures Axon {@link ResourceInjector} * * @param beanManager current {@link BeanManager} * @see Configurer#configureResourceInjector(Function) */ private void configureResourceInjector(BeanManager beanManager) { if (nonNull(resourceInjectorComponent)) { Configurable configurable = ConfigurableComponentResolver.of(resourceInjectorComponent).resolve(beanManager); configurer = configurer.configureResourceInjector(configurable); log.debug("Configured ResourceInjector: {}", resourceInjectorComponent); } } /** * Configures Axon {@link QueryUpdateEmitter} * * @param beanManager current {@link BeanManager} * @see Configurer#configureQueryUpdateEmitter(Function) */ private void configureQueryUpdateEmitter(BeanManager beanManager) { if (nonNull(queryUpdateEmitterComponent)) { Configurable configurable = ConfigurableComponentResolver.of(queryUpdateEmitterComponent).resolve(beanManager); configurer = configurer.configureQueryUpdateEmitter(configurable); log.debug("Configured QueryUpdateEmitter: {}", queryUpdateEmitterComponent); } } /** * Configures Axon default {@link ErrorHandler} * * @param beanManager current {@link BeanManager} * @see EventProcessingConfigurer#registerDefaultErrorHandler(Function) */ private void configureErrorHandler(BeanManager beanManager) { if (nonNull(errorHandlerComponent)) { Configurable configurable = ConfigurableComponentResolver.of(errorHandlerComponent).resolve(beanManager); configurer = configurer.eventProcessing(eventProcessingConfigurer -> eventProcessingConfigurer.registerDefaultErrorHandler(configurable)); log.debug("Configured default ErrorHandler: {}", errorHandlerComponent); } } /** * Configures Axon default {@link ListenerInvocationErrorHandler} * * @param beanManager current {@link BeanManager} * @see EventProcessingConfigurer#registerDefaultListenerInvocationErrorHandler(Function) */ private void configureListenerInvocationErrorHandler(BeanManager beanManager) { if (nonNull(listenerInvocationErrorHandlerComponent)) { Configurable configurable = ConfigurableComponentResolver.of(listenerInvocationErrorHandlerComponent).resolve(beanManager); configurer = configurer.eventProcessing(eventProcessingConfigurer -> eventProcessingConfigurer.registerDefaultListenerInvocationErrorHandler(configurable)); log.debug("Configured default ListenerInvocationErrorHandler: {}", listenerInvocationErrorHandlerComponent); } } /** * Configures Axon {@link EventUpcaster} * * @param beanManager current {@link BeanManager} * @see Configurer#registerEventUpcaster(Function) */ private void configureEventUpcasters(BeanManager beanManager) { for (Component component : eventUpcasterComponents) { Configurable configurable = ConfigurableComponentResolver.of(component).resolve(beanManager); configurer = configurer.registerEventUpcaster(configurable); log.debug("Configured EventUpcaster: {}", component); } } /** * Configures Axon {@link CorrelationDataProvider} instances * * @param beanManager current {@link BeanManager} * @see Configurer#configureCorrelationDataProviders(Function) */ private void configureCorrelationDataProviders(BeanManager beanManager) { List correlationDataProviders = correlationDataProviderComponents.stream() .map(component -> ComponentResolver.of(component).resolve(beanManager)) .collect(Collectors.toList()); if (!correlationDataProviders.isEmpty()) { configurer.configureCorrelationDataProviders(conf -> correlationDataProviders); log.debug("Configured CorrelationDataProvider instances: {}", correlationDataProviderComponents); } } /** * Configures Axon {@link ModuleConfiguration} instances * * @param beanManager current {@link BeanManager} * @see Configurer#registerModule(ModuleConfiguration) */ private void configureModules(BeanManager beanManager) { for (Component component : moduleConfigurationComponents) { ModuleConfiguration moduleConfiguration = ComponentResolver.of(component).resolve(beanManager); configurer = configurer.registerModule(new LazyRetrievedModuleConfiguration(() -> moduleConfiguration, component.getType())); log.debug("Configured ModuleConfiguration: {}", component); } } /** * Configures Axon {@link ConfigurerModule} instances * * @param beanManager current {@link BeanManager} * @see ConfigurerModule#configureModule(Configurer) */ private void configureConfigurerModules(BeanManager beanManager) { for (Component component : configurerModuleComponents) { ConfigurerModule configurerModule = ComponentResolver.of(component).resolve(beanManager); configurerModule.configureModule(configurer); log.debug("Configured ConfigurerModule: {}", configurerModule); } } /** * Configures Axon custom components * * @param beanManager current {@link BeanManager} * @param custom component type * @see Configurer#registerComponent(Class, Function) */ private void configureCustomComponents(BeanManager beanManager) { for (Component component : customComponents) { Configurable configurable = ConfigurableComponentResolver.of(component).resolve(beanManager); Type actualType = Optional.ofNullable( ReflectionUtils.getTypeArgument(component.getType(), Configurable.class)) .orElse(component.getType()); configurer = configurer.registerComponent(ReflectionUtils.getRawType(actualType), configurable); log.debug("Configured custom component: {}", component); } } /** * Configures Axon command {@link MessageDispatchInterceptor} instances * *

* Must be called after {@code configuration} initialization and before * {@code configuration} start * * @param beanManager current {@link BeanManager} * @see CommandBus#registerDispatchInterceptor(MessageDispatchInterceptor) */ private void configureCommandDispatchInterceptors(BeanManager beanManager) { CommandBus commandBus = configuration.commandBus(); for (Component component : commandDispatchInterceptorComponents) { CommandDispatchInterceptor interceptor = ComponentResolver.of(component).resolve(beanManager); commandBus.registerDispatchInterceptor(interceptor); log.debug("Configured CommandDispatchInterceptor: {}", component); } } /** * Configures Axon event {@link MessageDispatchInterceptor} instances * *

* Must be called after {@code configuration} initialization and before * {@code configuration} start * * @param beanManager current {@link BeanManager} * @see EventBus#registerDispatchInterceptor(MessageDispatchInterceptor) */ private void configureEventDispatchInterceptors(BeanManager beanManager) { EventBus eventBus = configuration.eventBus(); for (Component component : eventDispatchInterceptorComponents) { EventDispatchInterceptor interceptor = ComponentResolver.of(component).resolve(beanManager); eventBus.registerDispatchInterceptor(interceptor); log.debug("Configured EventDispatchInterceptor: {}", component); } } /** * Invoked after container has finished processing requests and destroyed all contexts * *

* Fires {@link AxonStoppedEvent} * * @param event an event fired after deployment validated * @param beanManager current {@link BeanManager} * @see AxonStoppedEvent */ void beforeShutdown(@Observes BeforeShutdown event, BeanManager beanManager) { log.debug("Stopping Axon application"); configuration.shutdown(); log.info("Axon application stopped"); beanManager.fireEvent(new AxonStoppedEvent()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy