Skip to content

Commit

Permalink
Merge develop into master (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-schnell authored Dec 31, 2023
1 parent a116226 commit ccf2d83
Show file tree
Hide file tree
Showing 15 changed files with 291 additions and 65 deletions.
39 changes: 23 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,23 @@ Defines a common event store Java interface and provides some adapters (like for
## Status
![Warning](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/warning.gif) **This is work in progress** ![Warning](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/warning.gif)

| Module | Description | Status | Comment |
|:-------|:------------|--------|:--------|
| [esc-api](api) | Defines the event store commons API. | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~92% |
| [esc-http](eshttp) | HTTP adapter for Greg Young's [event store](https://www.geteventstore.com/)| ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~66% |
| [esc-esjc](esjc) | [Event Store Java Client](https://github.com/msemys/esjc) adapter for Greg Young's [event store](https://www.geteventstore.com/)| ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~80% |
| [esc-grpc](grpc) | [Event Store DB Client](https://github.com/EventStore/EventStoreDB-Client-Java) adapter for Greg Young's [event store](https://www.geteventstore.com/)| ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~80% |
| [esc-jpa](jpa) | JPA adapter | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~59% |
| [esc-mem](mem) | In-memory implementation | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~60% |
| [esc-spi](spi) | Helper classes for adapters and implementations | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~67% |
| [esc-test](test) | Cucumber tests for adapters and implementations | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Subscriptions not tested yet |
| Module | Description | Status | Comment |
|:------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------|--------|:-----------------------------|
| [esc-api](api) | Defines the event store commons API. | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~92% |
| [esc-http-admin](admin) | HTTP projection admin adapter for Greg Young's [event store](https://www.geteventstore.com/) | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~80% |
| [esc-grpc](grpc) | [Event Store DB Client](https://github.com/EventStore/EventStoreDB-Client-Java) adapter for Greg Young's [event store](https://www.geteventstore.com/) | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~80% |
| [esc-jpa](jpa) | JPA adapter | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~59% |
| [esc-mem](mem) | In-memory implementation | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~60% |
| [esc-spi](spi) | Helper classes for adapters and implementations | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Test coverage ~67% |
| [esc-test](test) | Cucumber tests for adapters and implementations | ![OK](https://raw.githubusercontent.com/fuinorg/event-store-commons/master/doc/ok.png) | Subscriptions not tested yet |

Deprecated modules:

| Module | Description | Comment |
|:-------------------|:-------------------------------------------------------------|:------------------------------------------------------|
| [esc-http](eshttp) | HTTP adapter for Greg Young's event store | No longer supported by event store (use GRPC instead) |
| [esc-esjc](esjc) | Event Store Java Client adapter for Greg Young's event store | No longer supported by event store (use GRPC instead) |


## Architecture
![Layers](https://raw.github.com/fuinorg/event-store-commons/master/doc/event-store-commons.png)
Expand All @@ -42,12 +49,12 @@ Defines a common event store Java interface and provides some adapters (like for

### Major changes

| Version | Description |
|:---------------|:-------------------------------------------------------|
| 0.6.0 | Java 17 / Added new GRPC java client implementation |
| 0.5.0 | Namespace changed from "javax" to "jakarta" |
| 0.4.0 | Java 11 |
| 0.3.1 | Type of the event version changed from `int` to `long` |
| Version | Description |
|:--------|:-------------------------------------------------------|
| 0.6.0 | Java 17 / Added new GRPC java client implementation |
| 0.5.0 | Namespace changed from "javax" to "jakarta" |
| 0.4.0 | Java 11 |
| 0.3.1 | Type of the event version changed from `int` to `long` |

### Snapshots

Expand Down
2 changes: 1 addition & 1 deletion api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0-SNAPSHOT</version>
</parent>

<artifactId>esc-api</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion esgrpc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<parent>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0-SNAPSHOT</version>
</parent>

<artifactId>esc-esgrpc</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.fuin.esc.esgrpc;

import com.eventstore.dbclient.CreateProjectionOptions;
import com.eventstore.dbclient.DeleteProjectionOptions;
import com.eventstore.dbclient.EventStoreDBProjectionManagementClient;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import jakarta.validation.constraints.NotNull;
import org.fuin.esc.api.*;
import org.fuin.esc.spi.ProjectionJavaScriptBuilder;
import org.fuin.esc.spi.TenantStreamId;
import org.fuin.objects4j.common.ConstraintViolationException;
import org.fuin.objects4j.common.Contract;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

/**
* GRPC based eventstore projection admin implementation.
*/
public final class GrpcProjectionAdminEventStore implements ProjectionAdminEventStore {

private final EventStoreDBProjectionManagementClient es;

private final TenantId tenantId;

/**
* Constructor with mandatory data.
*
* @param es Eventstore client to use.
*/
public GrpcProjectionAdminEventStore(EventStoreDBProjectionManagementClient es) {
this(es, null);
}

/**
* Constructor with all data.
*
* @param es Eventstore client to use.
* @param tenantId Tenant ID or {@literal null}.
*/
public GrpcProjectionAdminEventStore(EventStoreDBProjectionManagementClient es, TenantId tenantId) {
Contract.requireArgNotNull("es", es);
this.es = es;
this.tenantId = tenantId;
}

@Override
public ProjectionAdminEventStore open() {
// Do nothing
return this;
}

@Override
public void close() {
// Do nothing
}

@Override
public boolean projectionExists(StreamId projectionId) {
Contract.requireArgNotNull("projectionId", projectionId);
requireProjection(projectionId);

try {
es.getStatus(new TenantStreamId(tenantId, projectionId).asString()).get();
return true;
} catch (final InterruptedException | ExecutionException ex) { // NOSONAR
if (ex.getCause() instanceof StatusRuntimeException sre) {
if (sre.getStatus().getCode().equals(Status.UNKNOWN.getCode())
&& sre.getMessage() != null && sre.getMessage().contains("NotFound")) {
return false;
}
}
throw new RuntimeException("Error waiting for getStatus(..) result", ex);
}

}

@Override
public void enableProjection(StreamId projectionId) throws StreamNotFoundException {
Contract.requireArgNotNull("projectionId", projectionId);
requireProjection(projectionId);

try {
es.enable(new TenantStreamId(tenantId, projectionId).asString()).get();
} catch (final InterruptedException | ExecutionException ex) { // NOSONAR
throw new RuntimeException("Error waiting for enable(..) result", ex);
}
}

@Override
public void disableProjection(StreamId projectionId) throws StreamNotFoundException {
Contract.requireArgNotNull("projectionId", projectionId);
requireProjection(projectionId);

try {
es.disable(new TenantStreamId(tenantId, projectionId).asString()).get();
} catch (final InterruptedException | ExecutionException ex) { // NOSONAR
throw new RuntimeException("Error waiting for disable(..) result", ex);
}
}

@Override
public void createProjection(StreamId projectionId, boolean enable, @NotNull TypeName... eventType) throws StreamAlreadyExistsException {
createProjection(projectionId, enable, Arrays.asList(eventType));
}

@Override
public void createProjection(StreamId projectionId, boolean enable, List<TypeName> eventTypes) throws StreamAlreadyExistsException {
Contract.requireArgNotNull("projectionId", projectionId);
requireProjection(projectionId);

final TenantStreamId pid = new TenantStreamId(tenantId, projectionId);
final String javascript = new ProjectionJavaScriptBuilder(pid).types(eventTypes).build();
try {
es.create(pid.asString(), javascript, CreateProjectionOptions.get().emitEnabled(false).trackEmittedStreams(true)).get();
} catch (final InterruptedException | ExecutionException ex) { // NOSONAR
throw new RuntimeException("Error waiting for create(..) result", ex);
}
if (enable) {
enableProjection(pid);
} else {
// Workaround for https://github.com/EventStore/EventStoreDB-Client-Java/issues/259 (not a perfect one...)
disableProjection(pid);
}
}

@Override
public void deleteProjection(StreamId projectionId) throws StreamNotFoundException {
Contract.requireArgNotNull("projectionId", projectionId);
requireProjection(projectionId);

disableProjection(projectionId);

final TenantStreamId pid = new TenantStreamId(tenantId, projectionId);
try {
es.delete(pid.asString(), DeleteProjectionOptions.get().deleteCheckpointStream().deleteStateStream().deleteEmittedStreams()).get();
} catch (final InterruptedException | ExecutionException ex) { // NOSONAR
throw new RuntimeException("Error waiting for delete(..) result", ex);
}

}

static void requireProjection(final StreamId projectionId) {
if (!projectionId.isProjection()) {
throw new ConstraintViolationException("The stream identifier is not a projection id");
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.fuin.esc.esgrpc;

import com.eventstore.dbclient.EventStoreDBClientSettings;
import com.eventstore.dbclient.EventStoreDBConnectionString;
import com.eventstore.dbclient.EventStoreDBProjectionManagementClient;
import org.fuin.esc.api.ProjectionStreamId;
import org.fuin.esc.api.TypeName;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.net.MalformedURLException;

import static org.assertj.core.api.Assertions.assertThat;

/**
* Tests the {@link GrpcProjectionAdminEventStore} class.
*/
class GrpcProjectionAdminEventStoreIT {

private static EventStoreDBProjectionManagementClient client;

private GrpcProjectionAdminEventStore testee;

@BeforeAll
static void beforeAll() {
final EventStoreDBClientSettings setts = EventStoreDBConnectionString
.parseOrThrow("esdb://localhost:2113?tls=false");
client = EventStoreDBProjectionManagementClient.create(setts);
}

@BeforeEach
void beforeEach() throws MalformedURLException {
testee = new GrpcProjectionAdminEventStore(client, null);
}

@Test
void testProjectionNotExists() {
assertThat(testee.projectionExists(new ProjectionStreamId("grpc-test-not-existing"))).isFalse();
}

@Test
void testEnableDisableProjection() {

// GIVEN
final ProjectionStreamId projectionId = new ProjectionStreamId("grpc-test-disabled");
testee.createProjection(projectionId, false, new TypeName("one"), new TypeName("two"));

// WHEN
testee.enableProjection(projectionId);

// THEN
// TODO assertThat(testee.projectionEnabled()).isTrue();

}

@Test
void testCreateAndExistsProjection() {

// GIVEN
final ProjectionStreamId projectionId = new ProjectionStreamId("grpc-test-create");
assertThat(testee.projectionExists(projectionId)).isFalse();

// WHEN
testee.createProjection(projectionId, true, new TypeName("one"), new TypeName("two"));

// THEN
assertThat(testee.projectionExists(projectionId)).isTrue();

}

@Test
void testDeleteProjection() {

// GIVEN
final ProjectionStreamId projectionId = new ProjectionStreamId("grpc-test-delete");
testee.createProjection(projectionId, false, new TypeName("one"), new TypeName("two"));
assertThat(testee.projectionExists(projectionId)).isTrue();

// WHEN
testee.deleteProjection(projectionId);

// THEN
assertThat(testee.projectionExists(projectionId)).isFalse();

}

}
2 changes: 1 addition & 1 deletion eshttp/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.fuin.esc</groupId>
<artifactId>esc-parent</artifactId>
<version>0.6.0</version>
<version>0.7.0-SNAPSHOT</version>
</parent>

<artifactId>esc-eshttp</artifactId>
Expand Down
52 changes: 16 additions & 36 deletions eshttp/src/main/java/org/fuin/esc/eshttp/ESHttpEventStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,7 @@
*/
package org.fuin.esc.eshttp;

import static org.fuin.esc.api.ExpectedVersion.ANY;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

import jakarta.validation.constraints.NotNull;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
Expand All @@ -52,32 +37,27 @@
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.impl.nio.client.HttpAsyncClients;
import org.apache.http.util.EntityUtils;
import org.fuin.esc.api.CommonEvent;
import org.fuin.esc.api.EventNotFoundException;
import org.fuin.esc.api.ExpectedVersion;
import org.fuin.esc.api.SimpleStreamId;
import org.fuin.esc.api.StreamAlreadyExistsException;
import org.fuin.esc.api.StreamDeletedException;
import org.fuin.esc.api.StreamEventsSlice;
import org.fuin.esc.api.StreamId;
import org.fuin.esc.api.StreamNotFoundException;
import org.fuin.esc.api.StreamReadOnlyException;
import org.fuin.esc.api.StreamState;
import org.fuin.esc.api.TenantId;
import org.fuin.esc.api.TypeName;
import org.fuin.esc.api.WrongExpectedVersionException;
import org.fuin.esc.spi.AbstractReadableEventStore;
import org.fuin.esc.spi.DeserializerRegistry;
import org.fuin.esc.spi.EnhancedMimeType;
import org.fuin.esc.spi.EscSpiUtils;
import org.fuin.esc.spi.SerDeserializerRegistry;
import org.fuin.esc.spi.SerializerRegistry;
import org.fuin.esc.spi.TenantStreamId;
import org.fuin.esc.api.*;
import org.fuin.esc.spi.*;
import org.fuin.objects4j.common.ConstraintViolationException;
import org.fuin.objects4j.common.Contract;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;

import static org.fuin.esc.api.ExpectedVersion.ANY;

/**
* Implementation that connects to the http://www.geteventstore.com via HTTP API.
*/
Expand Down
Loading

0 comments on commit ccf2d83

Please sign in to comment.