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

org.axonframework.spring.config.SpringAggregateConfigurer Maven / Gradle / Ivy

Go to download

Module providing Spring specific helper functionality to ease configuration / set-up of an Axon application, as well as some Spring specific infrastructure components.

The newest version!
/*
 * Copyright (c) 2010-2023. Axon Framework
 *
 * 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 org.axonframework.spring.config;

import org.axonframework.common.annotation.AnnotationUtils;
import org.axonframework.common.caching.Cache;
import org.axonframework.common.jpa.EntityManagerProvider;
import org.axonframework.common.lock.LockFactory;
import org.axonframework.common.lock.NullLockFactory;
import org.axonframework.config.AggregateConfigurer;
import org.axonframework.config.Configurer;
import org.axonframework.config.ConfigurerModule;
import org.axonframework.eventsourcing.AggregateFactory;
import org.axonframework.eventsourcing.SnapshotTriggerDefinition;
import org.axonframework.eventsourcing.snapshotting.SnapshotFilter;
import org.axonframework.modelling.command.CommandTargetResolver;
import org.axonframework.modelling.command.GenericJpaRepository;
import org.axonframework.modelling.command.Repository;
import org.axonframework.modelling.command.RepositorySpanFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.Set;
import javax.annotation.Nonnull;

/**
 * A {@link ConfigurerModule} implementation that will configure an Aggregate with the Axon {@link
 * org.axonframework.config.Configuration}.
 *
 * @param  The type of Aggregate to configure
 *
 * @author Allard Buijze
 * @since 4.6.0
 */
public class SpringAggregateConfigurer implements ConfigurerModule, ApplicationContextAware {

    private final Class aggregateType;
    private final Set> subTypes;

    private String snapshotFilter;
    private String aggregateRepository;
    private String snapshotTriggerDefinition;
    private String cache;
    private String lockFactory;
    private String commandTargetResolver;
    private boolean filterEventsByType;
    private ApplicationContext applicationContext;
    private String aggregateFactory;

    /**
     * Initializes a {@link ConfigurerModule} for given {@code aggregateType} and possible {@code subTypes}.
     *
     * @param aggregateType The declared type of the aggregate.
     * @param subTypes      The possible subtypes of this aggregate.
     */
    public SpringAggregateConfigurer(Class aggregateType, Set> subTypes) {
        this.aggregateType = aggregateType;
        this.subTypes = subTypes;
    }

    /**
     * Sets the bean name of the {@link Repository} to configure for this Aggregate.
     *
     * @param aggregateRepository The bean name of the {@link Repository} for this Aggregate.
     */
    public void setRepository(String aggregateRepository) {
        this.aggregateRepository = aggregateRepository;
    }

    /**
     * Sets the bean name of the {@link SnapshotFilter} to configure for this Aggregate.
     *
     * @param snapshotFilter The bean name of the {@link SnapshotFilter} to configure for this Aggregate.
     */
    public void setSnapshotFilter(String snapshotFilter) {
        this.snapshotFilter = snapshotFilter;
    }

    /**
     * Sets the bean name of the {@link SnapshotTriggerDefinition} to use for this Aggregate.
     *
     * @param snapshotTriggerDefinition The bean name of the {@link SnapshotTriggerDefinition} to use for this
     *                                  Aggregate.
     */
    public void setSnapshotTriggerDefinition(String snapshotTriggerDefinition) {
        this.snapshotTriggerDefinition = snapshotTriggerDefinition;
    }

    /**
     * Sets the bean name of the {@link CommandTargetResolver} to use for this Aggregate.
     *
     * @param commandTargetResolver The bean name of the {@link CommandTargetResolver} to use for this Aggregate.
     */
    public void setCommandTargetResolver(String commandTargetResolver) {
        this.commandTargetResolver = commandTargetResolver;
    }

    /**
     * Indicates whether to enable "filter events by type" for this Aggregate. When {@code true}, only Domain Event
     * Messages with a "type" that match the Aggregate type will be read. This is useful when multiple aggregates with
     * different types but equal identifiers share the same event store.  Will be ignored if a Repository is also
     * configured.
     *
     * @param filterEventsByType Whether to enable "filter events by type" for this Aggregate.
     */
    public void setFilterEventsByType(boolean filterEventsByType) {
        this.filterEventsByType = filterEventsByType;
    }

    /**
     * Sets the bean name of the {@link Cache} to use for this Aggregate. Will be ignored if a {@link Repository} is
     * also configured.
     *
     * @param cache The bean name of the {@link Cache} to use for this Aggregate.
     */
    public void setCache(String cache) {
        this.cache = cache;
    }

    /**
     * Sets the bean name of the {@link LockFactory} to use for this Aggregate. Will be ignored if a {@link Repository}
     * is also configured.
     *
     * @param lockFactory The bean name of the {@link LockFactory} to use for this Aggregate.
     */
    public void setLockFactory(String lockFactory) {
        this.lockFactory = lockFactory;
    }

    /**
     * Sets the bean name of the {@link AggregateFactory} to use for this Aggregate. Will be ignored if a {@link
     * Repository} is also configured.
     *
     * @param aggregateFactory The bean name of the AggregateFactory to use for this Aggregate.
     */
    public void setAggregateFactory(String aggregateFactory) {
        this.aggregateFactory = aggregateFactory;
    }

    @Override
    public void configureModule(@Nonnull Configurer configurer) {
        AggregateConfigurer aggregateConfigurer = AggregateConfigurer.defaultConfiguration(aggregateType)
                                                                        .withSubtypes(subTypes);
        if (snapshotFilter != null) {
            aggregateConfigurer.configureSnapshotFilter(
                    c -> applicationContext.getBean(snapshotFilter, SnapshotFilter.class)
            );
        }
        if (aggregateRepository != null) {
            //noinspection unchecked
            aggregateConfigurer.configureRepository(
                    c -> applicationContext.getBean(aggregateRepository, Repository.class)
            );
        } else if (isEntityManagerAnnotationPresent(aggregateType)) {
            aggregateConfigurer.configureRepository(c -> GenericJpaRepository.builder(aggregateType)
                                                                             .parameterResolverFactory(c.parameterResolverFactory())
                                                                             .handlerDefinition(c.handlerDefinition(aggregateType))
                                                                             .lockFactory(c.getComponent(
                                                                                     LockFactory.class, () -> NullLockFactory.INSTANCE
                                                                             ))
                                                                             .entityManagerProvider(c.getComponent(EntityManagerProvider.class))
                                                                             .eventBus(c.eventBus())
                                                                             .repositoryProvider(c::repository)
                                                                             .spanFactory(c.getComponent(RepositorySpanFactory.class))
                                                                             .build());
        }

        if (snapshotTriggerDefinition != null) {
            aggregateConfigurer.configureSnapshotTrigger(
                    c -> applicationContext.getBean(snapshotTriggerDefinition, SnapshotTriggerDefinition.class)
            );
        }
        if (commandTargetResolver != null) {
            aggregateConfigurer.configureCommandTargetResolver(
                    c -> applicationContext.getBean(commandTargetResolver, CommandTargetResolver.class)
            );
        }
        if (cache != null) {
            aggregateConfigurer.configureCache(c -> applicationContext.getBean(cache, Cache.class));
        }
        if (lockFactory != null) {
            aggregateConfigurer.configureLockFactory(c -> applicationContext.getBean(lockFactory, LockFactory.class));
        }
        if (aggregateFactory != null) {
            //noinspection unchecked
            aggregateConfigurer.configureAggregateFactory(
                    c -> applicationContext.getBean(aggregateFactory, AggregateFactory.class)
            );
        }
        aggregateConfigurer.configureFilterEventsByType(c -> filterEventsByType);
        configurer.configureAggregate(aggregateConfigurer);
    }

    private boolean isEntityManagerAnnotationPresent(Class type) {
        return AnnotationUtils.isAnnotationPresent(type, "javax.persistence.Entity")
                || AnnotationUtils.isAnnotationPresent(type, "jakarta.persistence.Entity");
    }

    @Override
    public void setApplicationContext(@Nonnull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy