/** * Create an empty DomainEventStream. * * @return A DomainEventStream containing no events */ static DomainEventStream empty() { return DomainEventStream.of(); }
/** * Create a new DomainEventStream from the given {@code events}. * * @param events Events to add to the resulting DomainEventStream * @return A DomainEventStream consisting of all given events */ static DomainEventStream of(DomainEventMessage<?>... events) { return DomainEventStream.of(Arrays.asList(events)); }
/** * Create a new DomainEventStream with events obtained from the given {@code list}. * * @param list list that serves as a source of events in the resulting DomainEventStream * @return A DomainEventStream containing all events returned by the list */ static DomainEventStream of(List<? extends DomainEventMessage<?>> list) { return list.isEmpty() ? of(Stream.empty(), () -> null) : of(list.stream(), () -> list.isEmpty() ? null : list.get(list.size() - 1).getSequenceNumber()); }
@Override public DomainEventStream readEvents(String aggregateIdentifier) { Stream<? extends DomainEventData<?>> input = this.readEventData(aggregateIdentifier, ALLOW_SNAPSHOTS_MAGIC_VALUE); return DomainEventStream.of(input.map(this::upcastAndDeserializeDomainEvent).filter(Objects::nonNull)); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { AtomicReference<Long> sequenceNumber = new AtomicReference<>(); Stream<? extends DomainEventMessage<?>> stream = events.values().stream().filter(event -> event instanceof DomainEventMessage<?>) .map(event -> (DomainEventMessage<?>) event) .filter(event -> aggregateIdentifier.equals(event.getAggregateIdentifier()) && event.getSequenceNumber() >= firstSequenceNumber) .peek(event -> sequenceNumber.set(event.getSequenceNumber())); return DomainEventStream.of(stream, sequenceNumber::get); }
@Override public DomainEventStream readEvents(String identifier) { return DomainEventStream.of(new ArrayList<>(storedEvents)); }
/** * Open an event stream containing all domain events belonging to the given {@code aggregateIdentifier}. * <p> * The returned stream is <em>finite</em>, ending with the last known event of the aggregate. If the event store * holds no events of the given aggregate an empty stream is returned. * <p> * The default implementation invokes {@link #readEvents(String)} and then filters out events with a sequence number * smaller than {@code firstSequenceNumber}. * * @param aggregateIdentifier the identifier of the aggregate whose events to fetch * @param firstSequenceNumber the expected sequence number of the first event in the returned stream * @return a stream of all currently stored events of the aggregate */ default DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { DomainEventStream wholeStream = readEvents(aggregateIdentifier); return DomainEventStream .of(wholeStream.asStream().filter(event -> event.getSequenceNumber() >= firstSequenceNumber), wholeStream::getLastSequenceNumber); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { return DomainEventStream.concat(storageEngine.readEvents(aggregateIdentifier, firstSequenceNumber), DomainEventStream.of( stagedDomainEventMessages(aggregateIdentifier) .filter(m -> m.getSequenceNumber() >= firstSequenceNumber))); }
/** * {@inheritDoc} * <p> * This implementation returns a {@link DomainEventStream} starting with the last stored snapshot of the aggregate * followed by subsequent domain events. */ @Override public DomainEventStream readEvents(String aggregateIdentifier) { Optional<DomainEventMessage<?>> optionalSnapshot; try { optionalSnapshot = storageEngine.readSnapshot(aggregateIdentifier); } catch (Exception | LinkageError e) { optionalSnapshot = handleSnapshotReadingError(aggregateIdentifier, e); } DomainEventStream eventStream; if (optionalSnapshot.isPresent()) { DomainEventMessage<?> snapshot = optionalSnapshot.get(); eventStream = DomainEventStream.concat(DomainEventStream.of(snapshot), storageEngine.readEvents(aggregateIdentifier, snapshot.getSequenceNumber() + 1)); } else { eventStream = storageEngine.readEvents(aggregateIdentifier); } Stream<? extends DomainEventMessage<?>> domainEventMessages = stagedDomainEventMessages(aggregateIdentifier); return DomainEventStream.concat(eventStream, DomainEventStream.of(domainEventMessages)); }
return DomainEventStream.of(stream, currentSequenceNumber::get);
@Test public void testPublicationOrderIsMaintained_AggregateAdded() { String aggregateId = UUID.randomUUID().toString(); GenericDomainEventMessage<StubAggregateCreatedEvent> event = new GenericDomainEventMessage<>("test", aggregateId, 0, new StubAggregateCreatedEvent(aggregateId)); when(eventStore.readEvents(aggregateId)).thenReturn(DomainEventStream.of(event)); doAnswer(invocation -> { System.out.println("Published event: " + invocation.getArguments()[0].toString()); return Void.class; }).when(eventStore).publish(isA(EventMessage.class)); commandBus.dispatch(asCommandMessage(new UpdateStubAggregateWithExtraEventCommand(aggregateId))); InOrder inOrder = inOrder(eventStore, eventStore, eventStore); inOrder.verify(eventStore).publish(isA(DomainEventMessage.class)); inOrder.verify(eventStore).publish(argThat(new NotADomainEventMatcher())); inOrder.verify(eventStore).publish(isA(DomainEventMessage.class)); }
/** * Create an empty DomainEventStream. * * @return A DomainEventStream containing no events */ static DomainEventStream empty() { return DomainEventStream.of(); }
/** * Create an empty DomainEventStream. * * @return A DomainEventStream containing no events */ static DomainEventStream empty() { return DomainEventStream.of(); }
/** * Create a new DomainEventStream from the given {@code events}. * * @param events Events to add to the resulting DomainEventStream * @return A DomainEventStream consisting of all given events */ static DomainEventStream of(DomainEventMessage<?>... events) { return DomainEventStream.of(Arrays.asList(events)); }
/** * Create a new DomainEventStream from the given {@code events}. * * @param events Events to add to the resulting DomainEventStream * @return A DomainEventStream consisting of all given events */ static DomainEventStream of(DomainEventMessage<?>... events) { return DomainEventStream.of(Arrays.asList(events)); }
/** * Create a new DomainEventStream with events obtained from the given {@code list}. * * @param list list that serves as a source of events in the resulting DomainEventStream * @return A DomainEventStream containing all events returned by the list */ static DomainEventStream of(List<? extends DomainEventMessage<?>> list) { return list.isEmpty() ? of(Stream.empty(), () -> null) : of(list.stream(), () -> list.isEmpty() ? null : list.get(list.size() - 1).getSequenceNumber()); }
@Override public DomainEventStream readEvents(String aggregateIdentifier) { Stream<? extends DomainEventData<?>> input = this.readEventData(aggregateIdentifier, ALLOW_SNAPSHOTS_MAGIC_VALUE); return DomainEventStream.of(input.map(this::upcastAndDeserializeDomainEvent).filter(Objects::nonNull)); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { AtomicReference<Long> sequenceNumber = new AtomicReference<>(); Stream<? extends DomainEventMessage<?>> stream = events.values().stream().filter(event -> event instanceof DomainEventMessage<?>) .map(event -> (DomainEventMessage<?>) event) .filter(event -> aggregateIdentifier.equals(event.getAggregateIdentifier()) && event.getSequenceNumber() >= firstSequenceNumber) .peek(event -> sequenceNumber.set(event.getSequenceNumber())); return DomainEventStream.of(stream, sequenceNumber::get); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { return DomainEventStream.concat(storageEngine.readEvents(aggregateIdentifier, firstSequenceNumber), DomainEventStream.of( stagedDomainEventMessages(aggregateIdentifier) .filter(m -> m.getSequenceNumber() >= firstSequenceNumber))); }
@Override public DomainEventStream readEvents(String aggregateIdentifier, long firstSequenceNumber) { return DomainEventStream.concat(storageEngine.readEvents(aggregateIdentifier, firstSequenceNumber), DomainEventStream.of( stagedDomainEventMessages(aggregateIdentifier) .filter(m -> m.getSequenceNumber() >= firstSequenceNumber))); }