/** * Registers the given {@code aggregateFactory} with this snapshotter. If a factory for this type was already * registered, it is overwritten with this one. * * @param aggregateFactory the AggregateFactory to register */ protected void registerAggregateFactory(AggregateFactory<?> aggregateFactory) { aggregateFactories.put(aggregateFactory.getAggregateType(), aggregateFactory); }
/** * Perform the actual loading of an aggregate. The necessary locks have been obtained. * * @param aggregateIdentifier the identifier of the aggregate to load * @param expectedVersion The expected version of the loaded aggregate * @return the fully initialized aggregate * * @throws AggregateDeletedException in case an aggregate existed in the past, but has been deleted * @throws AggregateNotFoundException when an aggregate with the given identifier does not exist */ @Override protected EventSourcedAggregate<T> doLoadWithLock(String aggregateIdentifier, Long expectedVersion) { DomainEventStream eventStream = readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); } EventSourcedAggregate<T> aggregate = EventSourcedAggregate .initialize(aggregateFactory.createAggregateRoot(aggregateIdentifier, eventStream.peek()), aggregateModel(), eventStore, repositoryProvider, trigger); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { throw new AggregateDeletedException(aggregateIdentifier); } return aggregate; }
@Override public T createAggregateRoot(String aggregateIdentifier, DomainEventMessage<?> firstEvent) { return delegate.createAggregateRoot(aggregateIdentifier, firstEvent); }
@SuppressWarnings("unchecked") @Override protected DomainEventMessage createSnapshot(Class<?> aggregateType, String aggregateIdentifier, DomainEventStream eventStream) { DomainEventMessage firstEvent = eventStream.peek(); AggregateFactory<?> aggregateFactory = getAggregateFactory(aggregateType); if (aggregateFactory == null) { throw new IllegalArgumentException( "Aggregate Type is unknown in this snapshotter: " + aggregateType.getName() ); } aggregateModels.computeIfAbsent(aggregateType, k -> AnnotatedAggregateMetaModelFactory .inspectAggregate(k, parameterResolverFactory, handlerDefinition)); Object aggregateRoot = aggregateFactory.createAggregateRoot(aggregateIdentifier, firstEvent); SnapshotAggregate<Object> aggregate = new SnapshotAggregate(aggregateRoot, aggregateModels.get(aggregateType), repositoryProvider); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { return null; } return new GenericDomainEventMessage<>(aggregate.type(), aggregate.identifierAsString(), aggregate.version(), aggregate.getAggregateRoot()); }
private DisruptorRepository(AggregateFactory<T> aggregateFactory, Cache cache, EventStore eventStore, ParameterResolverFactory parameterResolverFactory, SnapshotTriggerDefinition snapshotTriggerDefinition, RepositoryProvider repositoryProvider) { this.aggregateFactory = aggregateFactory; this.cache = cache; this.eventStore = eventStore; this.snapshotTriggerDefinition = snapshotTriggerDefinition; this.model = AnnotatedAggregateMetaModelFactory.inspectAggregate(aggregateFactory.getAggregateType(), parameterResolverFactory); this.repositoryProvider = repositoryProvider; }
if (aggregateFactory.getAggregateType().isInstance(r)) { return cachedAggregate; } else { aggregateIdentifier); DomainEventStream eventStream = eventStore.readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); aggregateRoot = EventSourcedAggregate.initialize(aggregateFactory.createAggregateRoot( aggregateIdentifier, eventStream.peek()), model, eventStore, repositoryProvider, trigger );
@SuppressWarnings("unchecked") @Override protected DomainEventMessage createSnapshot(Class<?> aggregateType, String aggregateIdentifier, DomainEventStream eventStream) { DomainEventMessage firstEvent = eventStream.peek(); AggregateFactory<?> aggregateFactory = getAggregateFactory(aggregateType); if (aggregateFactory == null) { throw new IllegalArgumentException( "Aggregate Type is unknown in this snapshotter: " + aggregateType.getName() ); } aggregateModels.computeIfAbsent(aggregateType, k -> AnnotatedAggregateMetaModelFactory .inspectAggregate(k, parameterResolverFactory, handlerDefinition)); Object aggregateRoot = aggregateFactory.createAggregateRoot(aggregateIdentifier, firstEvent); SnapshotAggregate<Object> aggregate = new SnapshotAggregate(aggregateRoot, aggregateModels.get(aggregateType), repositoryProvider); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { return null; } return new GenericDomainEventMessage<>(aggregate.type(), aggregate.identifierAsString(), aggregate.version(), aggregate.getAggregateRoot()); }
private DisruptorRepository(AggregateFactory<T> aggregateFactory, Cache cache, EventStore eventStore, ParameterResolverFactory parameterResolverFactory, HandlerDefinition handlerDefinition, SnapshotTriggerDefinition snapshotTriggerDefinition, RepositoryProvider repositoryProvider) { this.aggregateFactory = aggregateFactory; this.cache = cache; this.eventStore = eventStore; this.snapshotTriggerDefinition = snapshotTriggerDefinition; this.model = AnnotatedAggregateMetaModelFactory.inspectAggregate(aggregateFactory.getAggregateType(), parameterResolverFactory, handlerDefinition); this.repositoryProvider = repositoryProvider; }
if (aggregateFactory.getAggregateType().isInstance(r)) { return cachedAggregate; } else { aggregateIdentifier); DomainEventStream eventStream = eventStore.readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); aggregateRoot = EventSourcedAggregate.initialize(aggregateFactory.createAggregateRoot( aggregateIdentifier, eventStream.peek()), model, eventStore, repositoryProvider, trigger );
@SuppressWarnings("unchecked") @Override protected DomainEventMessage createSnapshot(Class<?> aggregateType, String aggregateIdentifier, DomainEventStream eventStream) { DomainEventMessage firstEvent = eventStream.peek(); AggregateFactory<?> aggregateFactory = getAggregateFactory(aggregateType); if (aggregateFactory == null) { throw new IllegalArgumentException("Aggregate Type is unknown in this snapshotter: " + aggregateType.getName()); } aggregateModels.computeIfAbsent(aggregateType, k -> AnnotatedAggregateMetaModelFactory .inspectAggregate(k, parameterResolverFactory, handlerDefinition)); Object aggregateRoot = aggregateFactory.createAggregateRoot(aggregateIdentifier, firstEvent); SnapshotAggregate<Object> aggregate = new SnapshotAggregate(aggregateRoot, aggregateModels.get(aggregateType), repositoryProvider); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { return null; } return new GenericDomainEventMessage<>(aggregate.type(), aggregate.identifierAsString(), aggregate.version(), aggregate.getAggregateRoot()); }
/** * Sets the {@code aggregateFactories} supported by this snapshotter. The {@link AggregateFactory} instances are * used to create the relevant Aggregate Root instance, which represent the snapshots. * * @param aggregateFactories a {@link List} of {@link AggregateFactory} instances which this snapshotter will * support * @return the current Builder instance, for fluent interfacing */ public Builder aggregateFactories(List<AggregateFactory<?>> aggregateFactories) { assertNonNull(aggregateFactories, "AggregateFactories may not be null"); aggregateFactories.forEach(f -> this.aggregateFactories.put(f.getAggregateType(), f)); return this; }
/** * Perform the actual loading of an aggregate. The necessary locks have been obtained. * * @param aggregateIdentifier the identifier of the aggregate to load * @param expectedVersion The expected version of the loaded aggregate * @return the fully initialized aggregate * @throws AggregateDeletedException in case an aggregate existed in the past, but has been deleted * @throws AggregateNotFoundException when an aggregate with the given identifier does not exist */ @Override protected EventSourcedAggregate<T> doLoadWithLock(String aggregateIdentifier, Long expectedVersion) { DomainEventStream eventStream = readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); } EventSourcedAggregate<T> aggregate = EventSourcedAggregate .initialize(aggregateFactory.createAggregateRoot(aggregateIdentifier, eventStream.peek()), aggregateModel(), eventStore, repositoryProvider, trigger); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { throw new AggregateDeletedException(aggregateIdentifier); } return aggregate; }
HandlerDefinition handlerDefinition) { return repositories.computeIfAbsent( aggregateFactory.getAggregateType(), k -> new DisruptorRepository<>( aggregateFactory,
if (aggregateFactory.getAggregateType().isInstance(r)) { return cachedAggregate; } else { aggregateIdentifier); DomainEventStream eventStream = eventStore.readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); aggregateRoot = EventSourcedAggregate.initialize(aggregateFactory.createAggregateRoot( aggregateIdentifier, eventStream.peek()), model, eventStore, repositoryProvider, trigger );
@Override protected AggregateFactory<?> getAggregateFactory(Class<?> aggregateType) { AggregateFactory<?> aggregateFactory = super.getAggregateFactory(aggregateType); if (aggregateFactory == null) { Optional<AggregateFactory> factory = applicationContext.getBeansOfType(AggregateFactory.class).values().stream() .filter(af -> Objects.equals(af.getAggregateType(), aggregateType)) .findFirst(); if (!factory.isPresent()) { factory = applicationContext.getBeansOfType(EventSourcingRepository.class).values().stream() .map((Function<EventSourcingRepository, AggregateFactory>) EventSourcingRepository::getAggregateFactory) .filter(af -> Objects.equals(af.getAggregateType(), aggregateType)) .findFirst(); if (factory.isPresent()) { aggregateFactory = factory.get(); registerAggregateFactory(aggregateFactory); } } if (factory.isPresent()) { aggregateFactory = factory.get(); registerAggregateFactory(aggregateFactory); } } return aggregateFactory; }
/** * Perform the actual loading of an aggregate. The necessary locks have been obtained. * * @param aggregateIdentifier the identifier of the aggregate to load * @param expectedVersion The expected version of the loaded aggregate * @return the fully initialized aggregate * * @throws AggregateDeletedException in case an aggregate existed in the past, but has been deleted * @throws AggregateNotFoundException when an aggregate with the given identifier does not exist */ @Override protected EventSourcedAggregate<T> doLoadWithLock(String aggregateIdentifier, Long expectedVersion) { DomainEventStream eventStream = readEvents(aggregateIdentifier); SnapshotTrigger trigger = snapshotTriggerDefinition.prepareTrigger(aggregateFactory.getAggregateType()); if (!eventStream.hasNext()) { throw new AggregateNotFoundException(aggregateIdentifier, "The aggregate was not found in the event store"); } EventSourcedAggregate<T> aggregate = EventSourcedAggregate .initialize(aggregateFactory.createAggregateRoot(aggregateIdentifier, eventStream.peek()), aggregateModel(), eventStore, repositoryProvider, trigger); aggregate.initializeState(eventStream); if (aggregate.isDeleted()) { throw new AggregateDeletedException(aggregateIdentifier); } return aggregate; }
/** * Creates a repository instance for an Event Sourced aggregate, source from given {@code eventStore}, that is * created by the given {@code aggregateFactory}. The given {@code decorator} is used to decorate event streams. * <p> * The repository returned must be used by Command Handlers subscribed to this Command Bus for loading aggregate * instances. Using any other repository instance may result in undefined outcome (a.k.a. concurrency problems). * <p> * Note that a second invocation of this method with an aggregate factory for the same aggregate type <em>may</em> * return the same instance as the first invocation, even if the given {@code decorator} is different. * * @param eventStore The Event Store to retrieve and persist events * @param aggregateFactory The factory creating uninitialized instances of the Aggregate * @param snapshotTriggerDefinition The trigger definition for creating snapshots * @param repositoryProvider Provides repositories for specified aggregate types * @param <T> The type of aggregate to create the repository for * @return the repository that provides access to stored aggregates */ public <T> Repository<T> createRepository(EventStore eventStore, AggregateFactory<T> aggregateFactory, SnapshotTriggerDefinition snapshotTriggerDefinition, RepositoryProvider repositoryProvider) { return createRepository(eventStore, aggregateFactory, snapshotTriggerDefinition, ClasspathParameterResolverFactory.forClass(aggregateFactory.getAggregateType()), ClasspathHandlerDefinition.forClass(aggregateFactory.getAggregateType()), repositoryProvider); }
/** * Creates a repository instance for an Event Sourced aggregate, sourced from given {@code eventStore}, that is * created by the given {@code aggregateFactory}. Parameters of the annotated methods are resolved using the given * {@code parameterResolverFactory}. * * @param eventStore The Event Store to retrieve and persist events * @param aggregateFactory The factory creating uninitialized instances of the Aggregate * @param snapshotTriggerDefinition The trigger definition for snapshots * @param parameterResolverFactory The ParameterResolverFactory to resolve parameter values of annotated handler * with * @param <T> The type of aggregate managed by this repository * @return the repository that provides access to stored aggregates */ public <T> Repository<T> createRepository(EventStore eventStore, AggregateFactory<T> aggregateFactory, SnapshotTriggerDefinition snapshotTriggerDefinition, ParameterResolverFactory parameterResolverFactory) { return createRepository(eventStore, aggregateFactory, snapshotTriggerDefinition, parameterResolverFactory, ClasspathHandlerDefinition.forClass(aggregateFactory.getAggregateType()), null); }
/** * Creates a repository instance for an Event Sourced aggregate, source from given {@code eventStore}, that is * created by the given {@code aggregateFactory}. * <p> * The repository returned must be used by Command Handlers subscribed to this Command Bus for loading aggregate * instances. Using any other repository instance may result in undefined outcome (a.k.a. concurrency problems). * * @param eventStore The Event Store to retrieve and persist events * @param aggregateFactory The factory creating uninitialized instances of the Aggregate * @param snapshotTriggerDefinition The trigger definition for creating snapshots * @param <T> The type of aggregate to create the repository for * @return the repository that provides access to stored aggregates */ public <T> Repository<T> createRepository(EventStore eventStore, AggregateFactory<T> aggregateFactory, SnapshotTriggerDefinition snapshotTriggerDefinition) { return createRepository(eventStore, aggregateFactory, snapshotTriggerDefinition, ClasspathParameterResolverFactory.forClass(aggregateFactory.getAggregateType())); }
/** * Create a repository instance for an aggregate created by the given {@code aggregateFactory}. The returning * repository must be safe to use by this invoker instance. * * @param <T> The type of aggregate created by the factory * @param eventStore The events store to load and publish events * @param aggregateFactory The factory creating aggregate instances * @param snapshotTriggerDefinition The trigger definition for snapshots * @param parameterResolverFactory The factory used to resolve parameters on command handler methods * @return A Repository instance for the given aggregate */ @SuppressWarnings("unchecked") public <T> Repository<T> createRepository(EventStore eventStore, AggregateFactory<T> aggregateFactory, SnapshotTriggerDefinition snapshotTriggerDefinition, ParameterResolverFactory parameterResolverFactory) { return createRepository(eventStore, null, aggregateFactory, snapshotTriggerDefinition, parameterResolverFactory, ClasspathHandlerDefinition.forClass(aggregateFactory.getAggregateType())); }