/* * Copyright (c) 2010-2016. 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.mongo.eventsourcing.eventstore.documentpercommit; import com.mongodb.BasicDBObject; import com.mongodb.client.MongoCollection; import com.mongodb.client.model.IndexOptions; import org.axonframework.eventhandling.EventMessage; import org.axonframework.eventsourcing.DomainEventMessage; import org.axonframework.eventsourcing.eventstore.DomainEventData; import org.axonframework.eventsourcing.eventstore.EventUtils; import org.axonframework.mongo.eventsourcing.eventstore.AbstractMongoEventStorageStrategy; import org.axonframework.mongo.eventsourcing.eventstore.StorageStrategy; import org.axonframework.mongo.eventsourcing.eventstore.documentperevent.EventEntryConfiguration; import org.axonframework.serialization.Serializer; import org.bson.Document; import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * Implementation of a Mongo {@link StorageStrategy} that stores one {@link Document} per commit of a batch of events. * <p> * For instance, one command commonly gives rise to more than one event. Using this strategt all events for that single * command will be grouped in a single Mongo Document. */ public class DocumentPerCommitStorageStrategy extends AbstractMongoEventStorageStrategy { private final CommitEntryConfiguration commitEntryConfiguration; /** * Initializes a {@link DocumentPerCommitStorageStrategy} with default event entry and commit entry configuration. */ public DocumentPerCommitStorageStrategy() { this(CommitEntryConfiguration.getDefault()); } /** * Initializes a {@link DocumentPerCommitStorageStrategy} with default event entry and given {@code * commitEntryConfiguration}. * * @param commitEntryConfiguration object that configures the naming of commit entry properties */ public DocumentPerCommitStorageStrategy(CommitEntryConfiguration commitEntryConfiguration) { this(EventEntryConfiguration.getDefault(), commitEntryConfiguration, null); } /** * Initializes a {@link DocumentPerCommitStorageStrategy} with given {@code eventConfiguration} and {@code * commitEntryConfiguration}. * * @param eventConfiguration object that configures the naming of event entry properties * @param commitEntryConfiguration object that configures the naming of event entry properties * @param lookBackTime the maximum time to look back when fetching new events while tracking. */ public DocumentPerCommitStorageStrategy(EventEntryConfiguration eventConfiguration, CommitEntryConfiguration commitEntryConfiguration, Duration lookBackTime) { super(eventConfiguration, lookBackTime); this.commitEntryConfiguration = commitEntryConfiguration; } @Override protected Stream<Document> createEventDocuments(List<? extends EventMessage<?>> events, Serializer serializer) { return Stream .of(new CommitEntry(events.stream().map(EventUtils::asDomainEventMessage).collect(Collectors.toList()), serializer).asDocument(commitEntryConfiguration, eventConfiguration())); } @Override protected Document createSnapshotDocument(DomainEventMessage<?> snapshot, Serializer serializer) { return new CommitEntry(Collections.singletonList(snapshot), serializer) .asDocument(commitEntryConfiguration, eventConfiguration()); } @Override protected Stream<? extends DomainEventData<?>> extractEvents(Document object) { return Stream.of(new CommitEntry(object, commitEntryConfiguration, eventConfiguration()).getEvents()); } @Override protected DomainEventData<?> extractSnapshot(Document object) { return new CommitEntry(object, commitEntryConfiguration, eventConfiguration()).getEvents()[0]; } @Override public void ensureIndexes(MongoCollection<Document> eventsCollection, MongoCollection<Document> snapshotsCollection) { super.ensureIndexes(eventsCollection, snapshotsCollection); //prevents duplicate commits eventsCollection.createIndex(new BasicDBObject(eventConfiguration().aggregateIdentifierProperty(), ORDER_ASC) .append(commitEntryConfiguration.firstSequenceNumberProperty(), ORDER_ASC), new IndexOptions().unique(true).name("uniqueAggregateStartIndex")); } }