EventStore.java

1
package com.reallifedeveloper.common.application.eventstore;
2
3
import static com.reallifedeveloper.common.domain.LogUtil.removeCRLF;
4
5
import java.util.List;
6
7
import org.slf4j.Logger;
8
import org.slf4j.LoggerFactory;
9
10
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
11
12
import com.reallifedeveloper.common.domain.ErrorHandling;
13
import com.reallifedeveloper.common.domain.ObjectSerializer;
14
import com.reallifedeveloper.common.domain.event.DomainEvent;
15
16
/**
17
 * An {@code EventStore} saves {@link DomainEvent DomainEvents} in a database as {@link StoredEvent StoredEvents}.
18
 *
19
 * @author RealLifeDeveloper
20
 */
21
public final class EventStore {
22
23
    private static final Logger LOG = LoggerFactory.getLogger(EventStore.class);
24
25
    private final ObjectSerializer<String> serializer;
26
27
    private final StoredEventRepository repository;
28
29
    /**
30
     * Creates a new {@code EventStore} with the given serializer and repository.
31
     *
32
     * @param serializer the {@code DomainEventSerializer} to use to serialize and deserialize {@code DomainEvents}
33
     * @param repository the {@code StoredEventRepository} to use to work with persisted {@code StoredEvents}
34
     */
35
    @SuppressFBWarnings(value = "CRLF_INJECTION_LOGS", justification = "Logging only of objects, not user data")
36
    public EventStore(ObjectSerializer<String> serializer, StoredEventRepository repository) {
37 1 1. <init> : removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED
        ErrorHandling.checkNull("Arguments must not be null: serializer=%s, repository=%s", serializer, repository);
38
        LOG.info("Creating new EventStore: serializer={}, repository={}", serializer, repository);
39
        this.serializer = serializer;
40
        this.repository = repository;
41
    }
42
43
    /**
44
     * Adds a new {@link StoredEvent} representing the given {@link DomainEvent} to the event store.
45
     *
46
     * @param event the {@code DomainEvent} to add
47
     * @return the saved {@code StoredEvent} representing {@code event}
48
     */
49
    public StoredEvent add(DomainEvent event) {
50
        if (LOG.isTraceEnabled()) {
51
            LOG.trace("add: event={}", removeCRLF(event));
52
        }
53 1 1. add : removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED
        ErrorHandling.checkNull("event must not be null", event);
54
        String serializedEvent = serializer.serialize(event);
55
        StoredEvent storedEvent = new StoredEvent(event.getClass().getName(), serializedEvent, event.eventOccurredOn(),
56
                event.eventVersion());
57 1 1. add : replaced return value with null for com/reallifedeveloper/common/application/eventstore/EventStore::add → KILLED
        return repository.save(storedEvent);
58
    }
59
60
    /**
61
     * Gives all {@code StoredEvents} with IDs greater than {@code storedEventId}, i.e., all events that occurred after the event with the
62
     * given ID.
63
     *
64
     * @param storedEventId return all events with IDs greater than this
65
     * @return a list of {@code StoredEvents} with IDs greater than or equal to {@code firstStoredEventId}
66
     */
67
    public List<StoredEvent> allEventsSince(long storedEventId) {
68
        LOG.trace("allEventsSince: storedEventId={}", storedEventId);
69 1 1. allEventsSince : replaced return value with Collections.emptyList for com/reallifedeveloper/common/application/eventstore/EventStore::allEventsSince → KILLED
        return repository.allEventsSince(storedEventId);
70
    }
71
72
    /**
73
     * Gives all {@code StoredEvents} with IDs greater than or equal to {@code firstStoredEventId} and less than or equals to
74
     * {@code lastStoredEventId}, i.e., all events that occurred between the events with the given IDs, inclusive.
75
     *
76
     * @param firstStoredEventId ID of the first {@code StoredEvent} to retrieve
77
     * @param lastStoredEventId  ID of the last {@code StoredEvent} to retrieve
78
     * @return a list of all {@code StoredEvents} with IDs between {@code firstStoredEventId} and {@code lastStoredEventId}, inclusive
79
     */
80
    public List<StoredEvent> allEventsBetween(long firstStoredEventId, long lastStoredEventId) {
81
        LOG.trace("allEventsBetween: firstStoredEventId={}, lastStoredEventId={}", firstStoredEventId, lastStoredEventId);
82 1 1. allEventsBetween : replaced return value with Collections.emptyList for com/reallifedeveloper/common/application/eventstore/EventStore::allEventsBetween → KILLED
        return repository.allEventsBetween(firstStoredEventId, lastStoredEventId);
83
    }
84
85
    /**
86
     * Converts a {@link StoredEvent} back to its original {@code DomainEvent}.
87
     * <p>
88
     * This is only guaranteed to work if the same kind of {@code EventStore}, using the same type of {@code DomainEventSerializer}, was
89
     * used to add the {@code DomainEvent}.
90
     *
91
     * @param storedEvent the {@code StoredEvent} to convert
92
     * @param <T>         the type of {@code DomainEvent} to return
93
     * @return the original {@code DomainEvent} represented by {@code storedEvent}
94
     * @throws IllegalArgumentException if {@code storedEvent} is {@code null}
95
     * @throws IllegalStateException    if loading of the class {@code T} failed
96
     */
97
    public <T extends DomainEvent> T toDomainEvent(StoredEvent storedEvent) {
98
        if (LOG.isTraceEnabled()) {
99
            LOG.trace("toDomainEvent: storedEvent={}", removeCRLF(storedEvent));
100
        }
101 1 1. toDomainEvent : removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED
        ErrorHandling.checkNull("storedEvent must not be null", storedEvent);
102
        try {
103
            @SuppressWarnings("unchecked")
104
            Class<T> eventClass = (Class<T>) Class.forName(storedEvent.eventType());
105 1 1. toDomainEvent : replaced return value with null for com/reallifedeveloper/common/application/eventstore/EventStore::toDomainEvent → KILLED
            return serializer.deserialize(storedEvent.eventBody(), eventClass);
106
        } catch (ClassNotFoundException e) {
107
            throw new IllegalStateException("Failed to load class " + storedEvent.eventType(), e);
108
        }
109
    }
110
111
    /**
112
     * Gives the ID of the most recently added {@code StoredEvents}.
113
     *
114
     * @return the ID of the most recently added {@code StoredEvent}
115
     */
116
    public long lastStoredEventId() {
117
        LOG.trace("lastStoredEventId");
118 1 1. lastStoredEventId : replaced long return with 0 for com/reallifedeveloper/common/application/eventstore/EventStore::lastStoredEventId → KILLED
        return repository.lastStoredEventId().orElse(0L);
119
    }
120
}

Mutations

37

1.1
Location : <init>
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:constructorNullSerializer()]
removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED

53

1.1
Location : add
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:addNullEvent()]
removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED

57

1.1
Location : add
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:addOneEvent()]
replaced return value with null for com/reallifedeveloper/common/application/eventstore/EventStore::add → KILLED

69

1.1
Location : allEventsSince
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:allEventsSince()]
replaced return value with Collections.emptyList for com/reallifedeveloper/common/application/eventstore/EventStore::allEventsSince → KILLED

82

1.1
Location : allEventsBetween
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:allEventsBetween()]
replaced return value with Collections.emptyList for com/reallifedeveloper/common/application/eventstore/EventStore::allEventsBetween → KILLED

101

1.1
Location : toDomainEvent
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:toDomainEventNull()]
removed call to com/reallifedeveloper/common/domain/ErrorHandling::checkNull → KILLED

105

1.1
Location : toDomainEvent
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:allEventsBetween()]
replaced return value with null for com/reallifedeveloper/common/application/eventstore/EventStore::toDomainEvent → KILLED

118

1.1
Location : lastStoredEventId
Killed by : com.reallifedeveloper.common.application.eventstore.EventStoreTest.[engine:junit-jupiter]/[class:com.reallifedeveloper.common.application.eventstore.EventStoreTest]/[method:allEventsSince()]
replaced long return with 0 for com/reallifedeveloper/common/application/eventstore/EventStore::lastStoredEventId → KILLED

Active mutators

Tests examined


Report generated by PIT 1.20.0