/* Copyright 2014 Danish Maritime Authority. * * 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 net.maritimecloud.portal.config; import net.maritimecloud.portal.audit.axon.ShiroAuditDataProvider; import java.io.File; import java.util.ArrayList; import java.util.List; import net.maritimecloud.identityregistry.command.user.ConfirmEmailAddressSaga; import net.maritimecloud.identityregistry.command.user.ResetPasswordSaga; import net.maritimecloud.identityregistry.command.user.User; import net.maritimecloud.common.eventsourcing.axon.NoReplayedEvents; import net.maritimecloud.common.eventsourcing.axon.ReplayableFileSystemEventStore; import net.maritimecloud.serviceregistry.command.organization.AttachOrganizationAliasSaga; import org.axonframework.commandhandling.CommandBus; import org.axonframework.commandhandling.SimpleCommandBus; import org.axonframework.commandhandling.gateway.CommandGatewayFactoryBean; import org.axonframework.commandhandling.annotation.AggregateAnnotationCommandHandler; import org.axonframework.contextsupport.spring.AnnotationDriven; import org.axonframework.eventhandling.EventBus; import org.axonframework.eventsourcing.EventSourcingRepository; import org.axonframework.eventstore.EventStore; import org.axonframework.repository.Repository; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import net.maritimecloud.serviceregistry.command.organization.Organization; import net.maritimecloud.serviceregistry.command.organization.SetupOrganizationOwnerMemberSaga; import net.maritimecloud.serviceregistry.command.organization.membership.Membership; import net.maritimecloud.serviceregistry.command.serviceinstance.ServiceInstance; import net.maritimecloud.serviceregistry.command.servicespecification.ServiceSpecification; import org.axonframework.auditing.AuditDataProvider; import org.axonframework.auditing.AuditingInterceptor; import org.axonframework.commandhandling.CommandHandlerInterceptor; import org.axonframework.eventhandling.AnnotationClusterSelector; import org.axonframework.eventhandling.ClusterSelector; import org.axonframework.eventhandling.ClusteringEventBus; import org.axonframework.eventhandling.CompositeClusterSelector; import org.axonframework.eventhandling.DefaultClusterSelector; import org.axonframework.eventhandling.SimpleCluster; import org.axonframework.eventhandling.replay.BackloggingIncomingMessageHandler; import org.axonframework.eventhandling.replay.ReplayingCluster; import org.axonframework.eventstore.management.EventStoreManagement; import org.axonframework.saga.GenericSagaFactory; import org.axonframework.saga.ResourceInjector; import org.axonframework.saga.SagaFactory; import org.axonframework.saga.SagaManager; import org.axonframework.saga.SagaRepository; import org.axonframework.saga.annotation.AnnotatedSagaManager; import org.axonframework.saga.repository.inmemory.InMemorySagaRepository; import org.axonframework.saga.spring.SpringResourceInjector; import org.axonframework.unitofwork.SpringTransactionManager; import org.springframework.transaction.PlatformTransactionManager; /** * @author Christoffer Børrild */ @Configuration @ComponentScan(basePackages = {"net.maritimecloud.serviceregistry", "net.maritimecloud.identityregistry"}) @AnnotationDriven public class AxonConfig { @Bean public CommandBus commandBus() { final SimpleCommandBus commandBus = new SimpleCommandBus(); commandBus.setHandlerInterceptors(commandHandlerInterceptors()); return commandBus; } private List<CommandHandlerInterceptor> commandHandlerInterceptors() { List<CommandHandlerInterceptor> commandHandlerInterceptors = new ArrayList<>(); commandHandlerInterceptors.add(auditingInterceptor()); return commandHandlerInterceptors; } @Bean public AuditingInterceptor auditingInterceptor() { final AuditingInterceptor auditingInterceptor = new AuditingInterceptor(); // Attach user info to all events: auditingInterceptor.setAuditDataProvider(auditDataProvider()); return auditingInterceptor; } @Bean public AuditDataProvider auditDataProvider() { return new ShiroAuditDataProvider(); } @Bean public EventBus eventBus() { // return new SimpleEventBus(); List<ClusterSelector> clusterSelectors = new ArrayList<>(); clusterSelectors.add(new AnnotationClusterSelector(NoReplayedEvents.class, sagaCluster())); clusterSelectors.add(new DefaultClusterSelector(simpleCluster())); final ClusteringEventBus eventBus = new ClusteringEventBus(new CompositeClusterSelector(clusterSelectors)); eventBus.subscribe(sagaManager()); return eventBus; } @Bean public EventStore eventStore() { // return new FileSystemEventStore(new SimpleEventFileResolver(new File("./target/events"))); return new ReplayableFileSystemEventStore(new File("./target/events")); } @Bean public SimpleCluster simpleCluster() { return new SimpleCluster("defaultCluster"); } @Bean public SimpleCluster sagaCluster() { return new SimpleCluster("sagaCluster"); } @Bean public SpringTransactionManager springTransactionManager(PlatformTransactionManager platformTransactionManager) { return new SpringTransactionManager(platformTransactionManager); } @Bean public ReplayingCluster replayingCluster(PlatformTransactionManager platformTransactionManager) { return new ReplayingCluster(simpleCluster(), (EventStoreManagement) eventStore(), springTransactionManager(platformTransactionManager), 10, backloggingIncomingMessageHandler()); } @Bean public BackloggingIncomingMessageHandler backloggingIncomingMessageHandler() { return new BackloggingIncomingMessageHandler(); } @Bean public CommandGatewayFactoryBean commandGateway() { CommandGatewayFactoryBean factory = new CommandGatewayFactoryBean(); factory.setCommandBus(commandBus()); return factory; } @Bean public SagaRepository sagaRepository() { return new InMemorySagaRepository(); } @Bean public ResourceInjector resourceInjector() { return new SpringResourceInjector(); } @Bean public SagaFactory sagaFactory() { GenericSagaFactory sagaFactory = new GenericSagaFactory(); sagaFactory.setResourceInjector(resourceInjector()); return sagaFactory; } @Bean public SagaManager sagaManager() { AnnotatedSagaManager sagaManager = new AnnotatedSagaManager(sagaRepository(), sagaFactory(), AttachOrganizationAliasSaga.class, SetupOrganizationOwnerMemberSaga.class, ConfirmEmailAddressSaga.class, ResetPasswordSaga.class ); return sagaManager; } // @Bean // AnnotationCommandHandlerBeanPostProcessor annotationCommandHandlerBeanPostProcessor() { // return new AnnotationCommandHandlerBeanPostProcessor(); // } // // @Bean // AnnotationEventListenerBeanPostProcessor annotationEventListenerBeanPostProcessor() { // return new AnnotationEventListenerBeanPostProcessor(); // } @Bean public Repository<User> userAggregateRepository() { EventSourcingRepository repository = new EventSourcingRepository<>(User.class, eventStore()); repository.setEventBus(eventBus()); return repository; } @Bean public Repository<Organization> organizationRepository() { EventSourcingRepository repository = new EventSourcingRepository<>(Organization.class, eventStore()); repository.setEventBus(eventBus()); return repository; } @Bean public Repository<ServiceSpecification> serviceSpecificationRepository() { EventSourcingRepository repository = new EventSourcingRepository<>(ServiceSpecification.class, eventStore()); repository.setEventBus(eventBus()); return repository; } @Bean public Repository<ServiceInstance> serviceInstanceRepository() { EventSourcingRepository repository = new EventSourcingRepository<>(ServiceInstance.class, eventStore()); repository.setEventBus(eventBus()); return repository; } @Bean public Repository<Membership> organizationMembershipRepository() { EventSourcingRepository repository = new EventSourcingRepository<>(Membership.class, eventStore()); repository.setEventBus(eventBus()); return repository; } // ------------------------------------------------------------------------ // Currently Axon does not have spring support for discovering // command handlers on Aggregates, so we have to subscribe them // manually: // ------------------------------------------------------------------------ @Bean public AggregateAnnotationCommandHandler<User> userAggregateCommandHandler() { return AggregateAnnotationCommandHandler.subscribe(User.class, userAggregateRepository(), commandBus()); } @Bean public AggregateAnnotationCommandHandler<Organization> organizationAggregateCommandHandler() { return AggregateAnnotationCommandHandler.subscribe(Organization.class, organizationRepository(), commandBus()); } @Bean public AggregateAnnotationCommandHandler<Membership> organizationMembershipCommandHandler() { return AggregateAnnotationCommandHandler.subscribe(Membership.class, organizationMembershipRepository(), commandBus()); } @Bean public AggregateAnnotationCommandHandler<ServiceSpecification> serviceSpecificationAggregateCommandHandler() { return AggregateAnnotationCommandHandler.subscribe(ServiceSpecification.class, serviceSpecificationRepository(), commandBus()); } @Bean public AggregateAnnotationCommandHandler<ServiceInstance> serviceInstanceAggregateCommandHandler() { return AggregateAnnotationCommandHandler.subscribe(ServiceInstance.class, serviceInstanceRepository(), commandBus()); } }