Skip to content

Commit

Permalink
GH-294 - Introduce user API to deal with completed and incomplete eve…
Browse files Browse the repository at this point in the history
…nt publications.

Introduce a new spring-modulith-events-api artifact to contain types that are supposed to be used by application code to deal with event publications. `EventPublication` was moved into that artifact and got everything non infrastructure related extracted from it's previous incarnation. That in turn has been renamed to `TargetEventPublication`.

`CompletedEventPublications` exposes API to allow purging completed publications either by a given predicate or age (in `Duration`). The interface is implemented by `DefaultEventPublicationRegistry` and thus subject for dependency injection into user code. It primarily delegates to the corresponding methods on `EventPublicationRepository` adapting the given `Duration`s to the `Clock` instance already held internally.

`IncompleteEventPublications` allows triggering the re-submission of incomplete publications by the same criteria as `CEP`. The interface is implemented by `PersistentApplicationEventMulticaster` and this subject for dependency injection into user code.

`EventPublicationRepository` now also allows publications to be deleted by identifiers. The existing implementations have been adapted and batch the requests for every 100 identifiers to prevent a list too large to run into limitations of the underlying data store.

Polished transactional metadata declaration in JPA- and MongoDB-based repository implementations.

Tightened nullability expressions here and there.
  • Loading branch information
odrotbohm committed Sep 4, 2023
1 parent 1fe681b commit 971a143
Show file tree
Hide file tree
Showing 29 changed files with 871 additions and 272 deletions.
1 change: 1 addition & 0 deletions spring-modulith-events/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<name>Spring Modulith - Events</name>

<modules>
<module>spring-modulith-events-api</module>
<module>spring-modulith-events-core</module>
<module>spring-modulith-events-jpa</module>
<module>spring-modulith-events-jdbc</module>
Expand Down
35 changes: 35 additions & 0 deletions spring-modulith-events/spring-modulith-events-api/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-events</artifactId>
<version>1.1.0-SNAPSHOT</version>
</parent>

<name>Spring Modulith - Events - API</name>
<artifactId>spring-modulith-events-api</artifactId>

<properties>
<module.name>org.springframework.modulith.events.api</module.name>
</properties>

<dependencies>

<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-api</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2023 the original author or authors.
*
* 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
*
* https://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.springframework.modulith.events;

import java.time.Duration;
import java.util.Collection;
import java.util.function.Predicate;

/**
* All {@link EventPublication}s that have already been completed.
*
* @author Oliver Drotbohm
* @since 1.1
*/
public interface CompletedEventPublications {

/**
* Returns all {@link EventPublication}s that have already been completed.
*
* @return will never be {@literal null}.
*/
Collection<? extends EventPublication> findAll();

/**
* Deletes all {@link EventPublication}s matching the given {@link Predicate}. Note that implementations will iterate
* all completed {@link EventPublication}s and apply the predicate in memory.
*
* @param filter must not be {@literal null}.
*/
void deletePublications(Predicate<EventPublication> filter);

/**
* Deletes all {@link EventPublication}s whose completion date is older than the given {@link Duration}.
*
* @param duration must not be {@literal null}.
*/
void deletePublicationsOlderThan(Duration duration);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Copyright 2023 the original author or authors.
*
* 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
*
* https://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.springframework.modulith.events;

import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.PayloadApplicationEvent;

/**
* An event publication.
*
* @author Oliver Drotbohm
* @since 1.1
*/
public interface EventPublication {

/**
* Returns a unique identifier for this publication.
*
* @return will never be {@literal null}.
*/
UUID getIdentifier();

/**
* Returns the event that is published.
*
* @return
*/
Object getEvent();

/**
* Returns the event as Spring {@link ApplicationEvent}, effectively wrapping it into a
* {@link PayloadApplicationEvent} in case it's not one already.
*
* @return
*/
default ApplicationEvent getApplicationEvent() {

Object event = getEvent();

return PayloadApplicationEvent.class.isInstance(event) //
? PayloadApplicationEvent.class.cast(event)
: new PayloadApplicationEvent<>(this, event);
}

/**
* Returns the time the event is published at.
*
* @return
*/
Instant getPublicationDate();

/**
* Returns the completion date of the publication.
*
* @return will never be {@literal null}.
*/
Optional<Instant> getCompletionDate();

/**
* Returns whether the publication of the event has completed.
*
* @return will never be {@literal null}.
*/
default boolean isPublicationCompleted() {
return getCompletionDate().isPresent();
}

/*
* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
default int compareTo(EventPublication that) {
return this.getPublicationDate().compareTo(that.getPublicationDate());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2023 the original author or authors.
*
* 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
*
* https://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.springframework.modulith.events;

import java.time.Duration;
import java.util.function.Predicate;

/**
* All uncompleted event publications.
*
* @author Oliver Drotbohm
* @since 1.1
*/
public interface IncompleteEventPublications {

/**
* Triggers the re-submission of events for which incomplete {@link EventPublication}s are registered. Note, that this
* will materialize <em>all</em> incomplete event publications.
*
* @param filter a {@link Predicate} to select the event publications for which to resubmit events.
*/
void resubmitIncompletePublications(Predicate<EventPublication> filter);

/**
* Triggers the re-submission of events for which incomplete {@link EventPublication}s are registered that exceed a
* certain age regarding their original publication date.
*
* @param duration must not be {@literal null}.
*/
void resubmitIncompletePublicationsOlderThan(Duration duration);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* API of the event publication registry abstraction.
*/
@org.springframework.lang.NonNullApi
package org.springframework.modulith.events;
6 changes: 6 additions & 0 deletions spring-modulith-events/spring-modulith-events-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@

<dependencies>

<dependency>
<groupId>org.springframework.modulith</groupId>
<artifactId>spring-modulith-events-api</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import java.time.Instant;

/**
* Internal interface to be able to mark {@link EventPublication} instances as completed.
* Internal interface to be able to mark {@link TargetEventPublication} instances as completed.
*
* @author Oliver Drotbohm
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@
import java.util.Optional;
import java.util.UUID;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
* Default {@link Completable} implementation.
*
* @author Oliver Drotbohm
*/
class DefaultEventPublication implements EventPublication {
class DefaultEventPublication implements TargetEventPublication {

private final UUID identifier;
private final Object event;
Expand Down Expand Up @@ -124,7 +125,7 @@ public String toString() {
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {

if (this == obj) {
return true;
Expand Down
Loading

0 comments on commit 971a143

Please sign in to comment.