diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..58fc87f --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,37 @@ +name: Java Maven Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout source + uses: actions/checkout@v2 + + - name: Show versions + run: ./mvnw -version + + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'zulu' + cache: maven + + - name: Cache Maven packages + uses: actions/cache@v1 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + - name: Build with Maven + run: ./mvnw clean verify -U -B --file pom.xml + diff --git a/.gitignore b/.gitignore index d6c7569..7dd9ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,6 @@ !.gitignore !.gitkeep !.mvn +!.github target *.log diff --git a/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/DuplicatePersonNameException.java b/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/DuplicatePersonNameException.java index 79bd535..79e3e0e 100644 --- a/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/DuplicatePersonNameException.java +++ b/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/DuplicatePersonNameException.java @@ -18,7 +18,6 @@ import org.fuin.cqrs4j.example.shared.PersonId; import org.fuin.cqrs4j.example.shared.PersonName; import org.fuin.objects4j.common.ExceptionShortIdentifable; - /** * A name that should be unique does already exist. */ @@ -26,11 +25,11 @@ public final class DuplicatePersonNameException extends Exception implements Exc private static final long serialVersionUID = 1000L; - private static final String SHORT_ID = "DUPLICATE_PERSON_NAME"; - - private PersonId personId; + private static final String SHORT_ID = "DUPLICATE_PERSON_NAME"; - private PersonName name; + private final PersonId personId; + + private final PersonName name; /** * Constructor with mandatory data. @@ -64,9 +63,9 @@ public final class DuplicatePersonNameException extends Exception implements Exc return name; } - @Override - public final String getShortId() { - return SHORT_ID; - } + @Override + public final String getShortId() { + return SHORT_ID; + } } \ No newline at end of file diff --git a/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/PersonRepository.java b/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/PersonRepository.java index ccb708f..5569f31 100644 --- a/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/PersonRepository.java +++ b/aggregates/src/main/java/org/fuin/cqrs4j/example/aggregates/PersonRepository.java @@ -12,13 +12,13 @@ */ package org.fuin.cqrs4j.example.aggregates; -import org.fuin.objects4j.common.NotThreadSafe; import javax.validation.constraints.NotNull; import org.fuin.cqrs4j.example.shared.PersonId; import org.fuin.ddd4j.ddd.EntityType; import org.fuin.ddd4j.esrepo.EventStoreRepository; import org.fuin.esc.api.EventStore; +import org.fuin.objects4j.common.NotThreadSafe; /** * Event sourced repository for storing a {@link Person} aggregate. diff --git a/aggregates/src/test/java/org/fuin/cqrs4j/example/aggregates/PersonTest.java b/aggregates/src/test/java/org/fuin/cqrs4j/example/aggregates/PersonTest.java index a3752f5..8613579 100644 --- a/aggregates/src/test/java/org/fuin/cqrs4j/example/aggregates/PersonTest.java +++ b/aggregates/src/test/java/org/fuin/cqrs4j/example/aggregates/PersonTest.java @@ -12,7 +12,7 @@ import org.fuin.cqrs4j.example.shared.PersonName; import org.junit.Test; /** - * Test for the {@link Person} class. + * Test for the {@link Person} class. */ public class PersonTest { @@ -24,7 +24,9 @@ public class PersonTest { final PersonName personName = new PersonName("Peter Parker"); // TEST - final Person testee = new Person(personId, personName, pid -> { return Optional.empty(); }) ; + final Person testee = new Person(personId, personName, pid -> { + return Optional.empty(); + }); // VERIFY assertThat(testee.getUncommittedChanges()).hasSize(1); @@ -34,8 +36,7 @@ public class PersonTest { assertThat(event.getName()).isEqualTo(personName); } - - + @Test public final void testCreateDuplicateName() { @@ -46,12 +47,14 @@ public class PersonTest { // TEST & VERIFY try { - new Person(personId, personName, pid -> { return Optional.of(otherId); }) ; + new Person(personId, personName, pid -> { + return Optional.of(otherId); + }); fail("Excpected duplicate name exception"); } catch (final DuplicatePersonNameException ex) { assertThat(ex.getMessage()).isEqualTo("The name 'Peter Parker' already exists: " + otherId); } - + } - + } diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/app/CmdExampleApp.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/app/CmdExampleApp.java index 9268acc..3e9201a 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/app/CmdExampleApp.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/app/CmdExampleApp.java @@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory; public class CmdExampleApp { private static final Logger LOG = LoggerFactory.getLogger(CmdExampleApp.class); - + @Inject private Instance eventStoreInstance; @@ -48,7 +48,7 @@ public class CmdExampleApp { public void execute() { LOG.info("Executing..."); - + try (final EventStore eventStore = eventStoreInstance.get()) { final PersonId id = new PersonId(UUID.fromString("f645969a-402d-41a9-882b-d2d8000d0f43")); @@ -61,7 +61,7 @@ public class CmdExampleApp { repo.update(person); LOG.info("Updated event store..."); - + } catch (final Exception ex) { throw new RuntimeException("Error saving person aggregate into event store", ex); } @@ -81,16 +81,16 @@ public class CmdExampleApp { new LogbackStandalone().init(args, new NewLogConfigFileParams("org.fuin.cqrs4j.example.javasecdi", "logback")); LOG.info("Start example"); - + try (final SeContainer container = SeContainerInitializer.newInstance().initialize()) { final CmdExampleApp app = container.select(CmdExampleApp.class).get(); app.execute(); } LOG.info("Finished example"); - + System.exit(0); - + } catch (final RuntimeException ex) { ex.printStackTrace(System.err); System.exit(1); diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/domain/Person.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/domain/Person.java index df096ec..8de27a1 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/domain/Person.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/cmd/domain/Person.java @@ -45,7 +45,8 @@ public class Person extends AbstractAggregateRoot implements Serializa * @throws DuplicatePersonNameException * The name already exists for another person. */ - public Person(@NotNull final PersonId id, @NotNull final PersonName name, final PersonService service) throws DuplicatePersonNameException { + public Person(@NotNull final PersonId id, @NotNull final PersonName name, final PersonService service) + throws DuplicatePersonNameException { super(); // VERIFY PRECONDITIONS diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryEntityManagerProducer.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryEntityManagerProducer.java index b059111..c42f627 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryEntityManagerProducer.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryEntityManagerProducer.java @@ -11,10 +11,10 @@ import org.apache.deltaspike.jpa.api.transaction.TransactionScoped; @ApplicationScoped public class QryEntityManagerProducer { - + private EntityManagerFactory emf; - @Produces + @Produces @TransactionScoped public EntityManager create() { if (emf == null) { diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryScheduledExecutorService.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryScheduledExecutorService.java index 32631e6..4d909cb 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryScheduledExecutorService.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/app/QryScheduledExecutorService.java @@ -16,7 +16,9 @@ public class QryScheduledExecutorService { @Produces @ApplicationScoped public ScheduledExecutorService create(ThreadFactory threadFactory) { - return new ScheduledThreadPoolExecutor(1, threadFactory, (runnable, executor) -> { System.out.println("Execution blocked"); }); + return new ScheduledThreadPoolExecutor(1, threadFactory, (runnable, executor) -> { + System.out.println("Execution blocked"); + }); } - + } diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/PersonCreatedEventHandler.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/PersonCreatedEventHandler.java index ea63750..c508049 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/PersonCreatedEventHandler.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/PersonCreatedEventHandler.java @@ -18,7 +18,7 @@ import org.slf4j.LoggerFactory; */ @ApplicationScoped public class PersonCreatedEventHandler implements EventHandler { - + private static final Logger LOG = LoggerFactory.getLogger(PersonCreatedEventHandler.class); @Inject diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/QryEventChunkHandler.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/QryEventChunkHandler.java index 81ae520..dc290f7 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/QryEventChunkHandler.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/qry/handler/QryEventChunkHandler.java @@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory; public class QryEventChunkHandler { private static final Logger LOG = LoggerFactory.getLogger(QryEventChunkHandler.class); - + /** Unique name of the event store projection that is used. */ public static final ProjectionStreamId PROJECTION_STREAM_ID = new ProjectionStreamId("qry-person-stream"); diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedConfig.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedConfig.java index 1d231c6..1d393b7 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedConfig.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedConfig.java @@ -68,14 +68,19 @@ public class SharedConfig { /** * Constructor with all data. * - * @param eventStoreHost Host. - * @param eventStoreHttpPort HTTP port - * @param eventStoreTcpPort TCP port. - * @param eventStoreUser User. - * @param eventStorePassword Password. + * @param eventStoreHost + * Host. + * @param eventStoreHttpPort + * HTTP port + * @param eventStoreTcpPort + * TCP port. + * @param eventStoreUser + * User. + * @param eventStorePassword + * Password. */ - public SharedConfig(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, - final String eventStoreUser, final String eventStorePassword) { + public SharedConfig(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, final String eventStoreUser, + final String eventStorePassword) { super(); this.eventStoreHost = eventStoreHost; this.eventStoreHttpPort = eventStoreHttpPort; diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedSerDeserializerRegistryFactory.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedSerDeserializerRegistryFactory.java index e41db17..4e510b5 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedSerDeserializerRegistryFactory.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedSerDeserializerRegistryFactory.java @@ -24,8 +24,7 @@ public class SharedSerDeserializerRegistryFactory { final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer(); // Registry connects the type with the appropriate serializer and de-serializer - final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry, - jsonbDeSer); + final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer); return serDeserRegistry; diff --git a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedUtils.java b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedUtils.java index f76aa5c..366f000 100644 --- a/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedUtils.java +++ b/java-se-cdi/src/main/java/org/fuin/cqrs4j/example/javasecdi/shared/app/SharedUtils.java @@ -39,7 +39,6 @@ import org.fuin.esc.spi.SerializedDataTypeRegistry; import org.fuin.esc.spi.SimpleSerializedDataTypeRegistry; import org.fuin.esc.spi.SimpleSerializerDeserializerRegistry; - /** * Utility code shared between command (write) and query (read) module. */ @@ -51,16 +50,14 @@ public final class SharedUtils { /** All JSON-B adapters from this module. */ public static JsonbAdapter[] JSONB_ADAPTERS = new JsonbAdapter[] { new EventIdConverter(), - new EntityIdPathConverter(new SharedEntityIdFactory()), new PersonId.Converter(), - new PersonName.Converter() }; + new EntityIdPathConverter(new SharedEntityIdFactory()), new PersonId.Converter(), new PersonName.Converter() }; private SharedUtils() { throw new UnsupportedOperationException("It is not allowed to create an instance of a utiliy class"); } /** - * Create a registry that allows finding types (classes) based on their unique - * type name. + * Create a registry that allows finding types (classes) based on their unique type name. * * @return New instance. */ @@ -84,11 +81,12 @@ public final class SharedUtils { } /** - * Creates a registry that connects the type with the appropriate serializer and - * de-serializer. + * Creates a registry that connects the type with the appropriate serializer and de-serializer. * - * @param typeRegistry Type registry (Mapping from type name to class). - * @param jsonbDeSer JSON-B serializer/deserializer to use. + * @param typeRegistry + * Type registry (Mapping from type name to class). + * @param jsonbDeSer + * JSON-B serializer/deserializer to use. * * @return New instance. */ @@ -120,9 +118,8 @@ public final class SharedUtils { public static JsonbDeSerializer createJsonbDeSerializer() { return JsonbDeSerializer.builder().withSerializers(EscSpiUtils.createEscJsonbSerializers()) - .withDeserializers(EscSpiUtils.createEscJsonbDeserializers()) - .withAdapters(JSONB_ADAPTERS).withPropertyVisibilityStrategy(new FieldAccessStrategy()) - .withEncoding(Charset.forName("utf-8")).build(); + .withDeserializers(EscSpiUtils.createEscJsonbDeserializers()).withAdapters(JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(Charset.forName("utf-8")).build(); } @@ -138,8 +135,10 @@ public final class SharedUtils { /** * Constructor with all data. * - * @param type Type. - * @param clasz Class. + * @param type + * Type. + * @param clasz + * Class. */ public TypeClass(final SerializedDataType type, final Class clasz) { super(); diff --git a/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/AggregateAlreadyExistsExceptionMapper.java b/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/AggregateAlreadyExistsExceptionMapper.java index 948a0a6..7508103 100644 --- a/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/AggregateAlreadyExistsExceptionMapper.java +++ b/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/AggregateAlreadyExistsExceptionMapper.java @@ -40,8 +40,8 @@ public class AggregateAlreadyExistsExceptionMapper implements ExceptionMapper> constraintViolations) { - if (constraintViolations == null || constraintViolations.size() == 0) { + if (constraintViolations == null || constraintViolations.isEmpty()) { return ""; } final List list = new ArrayList<>(); diff --git a/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResource.java b/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResource.java index b076a66..868aa0a 100644 --- a/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResource.java +++ b/quarkus/command/src/main/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResource.java @@ -48,7 +48,7 @@ public class PersonResource { @Context UriInfo uriInfo; - + @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) @@ -64,18 +64,18 @@ public class PersonResource { try { // Create aggregate - final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), (name) -> { + final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), name -> { // TODO Execute a call to the query side to verify if the name already exists return Optional.empty(); }); repo.add(person); // Send OK response - return Response.ok(SimpleResult.ok()).build(); + return Response.ok(SimpleResult.ok()).build(); } catch (final DuplicatePersonNameException ex) { throw new CommandExecutionFailedException(ex); } } - + } diff --git a/quarkus/command/src/test/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResourceIT.java b/quarkus/command/src/test/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResourceIT.java index 8a1e935..7031296 100644 --- a/quarkus/command/src/test/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResourceIT.java +++ b/quarkus/command/src/test/java/org/fuin/cqrs4j/example/quarkus/command/api/PersonResourceIT.java @@ -31,37 +31,28 @@ import io.quarkus.test.junit.QuarkusTest; import io.restassured.http.ContentType; @QuarkusTest -public class PersonResourceIT { +class PersonResourceIT { @Inject IESJCEventStore eventStore; - + @Inject Jsonb jsonb; - + @Test - public void testCreate() { - + void testCreate() { + // PREPARE final PersonId personId = new PersonId(UUID.randomUUID()); final PersonName personName = new PersonName("Peter Parker"); final CreatePersonCommand cmd = new CreatePersonCommand(personId, personName); final String json = jsonb.toJson(cmd); - + // TEST & VERIFY - final SimpleResult result = - given() - .accept(ContentType.JSON) - .contentType(ContentType.JSON) - .body(json) - .when() - .post("/persons/create") - .then() - .statusCode(200) - .extract() - .as(SimpleResult.class); + final SimpleResult result = given().accept(ContentType.JSON).contentType(ContentType.JSON).body(json).when().post("/persons/create") + .then().statusCode(200).extract().as(SimpleResult.class); assertThat(result.getType(), is(equalTo(ResultType.OK))); - + final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId); final StreamEventsSlice slice = eventStore.readEventsForward(personStreamId, 0, 1); final List events = slice.getEvents(); @@ -71,7 +62,7 @@ public class PersonResourceIT { final PersonCreatedEvent event = (PersonCreatedEvent) ce.getData(); assertThat(event.getEntityId(), is(equalTo(personId))); assertThat(event.getName(), is(equalTo(personName))); - + } } \ No newline at end of file diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java index f3cba75..1a60280 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java @@ -27,12 +27,13 @@ import org.fuin.objects4j.common.Contract; @ApplicationScoped public class QryProjectionPositionRepository implements ProjectionService { + private static final String ARG_STREAM_ID = "streamId"; @Inject EntityManager em; - + @Override public void resetProjectionPosition(@NotNull final StreamId streamId) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos != null) { pos.setNextPosition(0L); @@ -41,7 +42,7 @@ public class QryProjectionPositionRepository implements ProjectionService { @Override public Long readProjectionPosition(@NotNull StreamId streamId) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { return 0L; @@ -51,7 +52,7 @@ public class QryProjectionPositionRepository implements ProjectionService { @Override public void updateProjectionPosition(@NotNull StreamId streamId, @NotNull Long nextEventNumber) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); Contract.requireArgNotNull("nextEventNumber", nextEventNumber); final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/package-info.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/package-info.java index 5a3bd31..52a73e0 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/package-info.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/package-info.java @@ -14,5 +14,5 @@ package org.fuin.cqrs4j.example.quarkus.query.views; /** * Contains the views used in this query application. A view never uses code of another view, means all views are completely independent of - * each other. As an exception, the 'commons' package has some small classes that are not view specific. + * each other. As an exception, the 'commons' package has some small classes that are not view specific. */ diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonCreatedEventHandler.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonCreatedEventHandler.java index f1a7872..0e5c905 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonCreatedEventHandler.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonCreatedEventHandler.java @@ -28,12 +28,12 @@ import org.slf4j.LoggerFactory; */ @ApplicationScoped public class PersonCreatedEventHandler implements EventHandler { - + private static final Logger LOG = LoggerFactory.getLogger(PersonCreatedEventHandler.class); @Inject EntityManager em; - + @Override public EventType getEventType() { return PersonCreatedEvent.TYPE; @@ -41,7 +41,7 @@ public class PersonCreatedEventHandler implements EventHandler { - chunkHandler.handleChunk(currentSlice); - }); + eventstore.readAllEventsForward(chunkHandler.getProjectionStreamId(), nextEventNumber, 100, + currentSlice -> chunkHandler.handleChunk(currentSlice)); } diff --git a/quarkus/query/src/test/java/org/fuin/cqrs4j/example/quarkus/query/api/QryPersonResourceIT.java b/quarkus/query/src/test/java/org/fuin/cqrs4j/example/quarkus/query/api/QryPersonResourceIT.java index ec48fad..b5c4b6c 100644 --- a/quarkus/query/src/test/java/org/fuin/cqrs4j/example/quarkus/query/api/QryPersonResourceIT.java +++ b/quarkus/query/src/test/java/org/fuin/cqrs4j/example/quarkus/query/api/QryPersonResourceIT.java @@ -31,71 +31,52 @@ import org.junit.jupiter.api.Test; import io.quarkus.test.junit.QuarkusTest; @QuarkusTest -public class QryPersonResourceIT { - +class QryPersonResourceIT { + @Inject IESHttpEventStore eventStore; - + @Inject EntityManager em; @Test - public void testGetByIdNotFound() { - given() - .pathParam("id", UUID.randomUUID()) - .when() - .get("/persons/{id}") - .then() - .statusCode(404); + void testGetByIdNotFound() { + given().pathParam("id", UUID.randomUUID()).when().get("/persons/{id}").then().statusCode(404); } @ActivateRequestContext public boolean findPerson(final PersonId personId) { return em.find(PersonListEntry.class, personId.asString()) != null; } - + @Test - public void testGetByIdOK() { - + void testGetByIdOK() { + // PREPARE final PersonId personId = new PersonId(UUID.randomUUID()); final PersonName personName = new PersonName("Peter Parker"); final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId); final PersonCreatedEvent event = new PersonCreatedEvent(personId, personName); - final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()), - new TypeName(event.getEventType().asBaseType()), event); + final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()), + new TypeName(event.getEventType().asBaseType()), event); eventStore.appendToStream(personStreamId, ce); - + await().atMost(5, SECONDS).until(() -> findPerson(personId)); - + // TEST & VERIFY - - final PersonListEntry person = - given() - .pathParam("id", personId.asString()) - .when() - .get("/persons/{id}") - .then() - .statusCode(200) - .extract() - .as(PersonListEntry.class); + + final PersonListEntry person = given().pathParam("id", personId.asString()).when().get("/persons/{id}").then().statusCode(200) + .extract().as(PersonListEntry.class); assertThat(person.getId(), is(equalTo(personId))); assertThat(person.getName(), is(equalTo(personName))); - final PersonListEntry[] persons = - given() - .when() - .get("/persons") - .then() - .statusCode(200) - .extract() - .as(PersonListEntry[].class); + final PersonListEntry[] persons = given().when().get("/persons").then().statusCode(200).extract().as(PersonListEntry[].class); assertThat(Arrays.asList(persons), is(not(empty()))); final PersonListEntry person0 = persons[0]; assertThat(person0.getId(), is(equalTo(personId))); assertThat(person0.getName(), is(equalTo(personName))); - } + } } diff --git a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/Config.java b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/Config.java index 10d70f8..48bc83b 100644 --- a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/Config.java +++ b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/Config.java @@ -71,14 +71,19 @@ public class Config { /** * Constructor with all data. * - * @param eventStoreHost Host. - * @param eventStoreHttpPort HTTP port - * @param eventStoreTcpPort TCP port. - * @param eventStoreUser User. - * @param eventStorePassword Password. + * @param eventStoreHost + * Host. + * @param eventStoreHttpPort + * HTTP port + * @param eventStoreTcpPort + * TCP port. + * @param eventStoreUser + * User. + * @param eventStorePassword + * Password. */ - public Config(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, - final String eventStoreUser, final String eventStorePassword) { + public Config(final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, final String eventStoreUser, + final String eventStorePassword) { super(); this.eventStoreHost = eventStoreHost; this.eventStoreHttpPort = eventStoreHttpPort; diff --git a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EsjcEventStoreFactory.java b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EsjcEventStoreFactory.java index bbba8d2..dfa91ed 100644 --- a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EsjcEventStoreFactory.java +++ b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EsjcEventStoreFactory.java @@ -30,8 +30,7 @@ public class EsjcEventStoreFactory { @ApplicationScoped public EventStore createESJC(final ManagedExecutor executor, final Config config) { return EventStoreBuilder.newBuilder().singleNodeAddress(config.getEventStoreHost(), config.getEventStoreTcpPort()) - .executor(executor).userCredentials(config.getEventStoreUser(), config.getEventStorePassword()) - .build(); + .executor(executor).userCredentials(config.getEventStoreUser(), config.getEventStorePassword()).build(); } } \ No newline at end of file diff --git a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EventStoreFactory.java b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EventStoreFactory.java index 94e20e7..af16623 100644 --- a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EventStoreFactory.java +++ b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/EventStoreFactory.java @@ -12,7 +12,7 @@ */ package org.fuin.cqrs4j.example.quarkus.shared; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; @@ -57,7 +57,7 @@ public class EventStoreFactory { public IESJCEventStore createEventStore(final com.github.msemys.esjc.EventStore es, final SerDeserializerRegistry registry) { final IESJCEventStore eventstore = new ESJCEventStore.Builder().eventStore(es).serDesRegistry(registry) - .targetContentType(EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))).build(); + .targetContentType(EnhancedMimeType.create("application", "json", StandardCharsets.UTF_8)).build(); eventstore.open(); return eventstore; diff --git a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/JsonbFactory.java b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/JsonbFactory.java index e5d8d04..33e37cf 100644 --- a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/JsonbFactory.java +++ b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/JsonbFactory.java @@ -34,8 +34,7 @@ public class JsonbFactory { */ @Produces public Jsonb createJsonb() { - final JsonbConfig config = new JsonbConfig() - .withAdapters(SharedUtils.JSONB_ADAPTERS) + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) .withPropertyVisibilityStrategy(new FieldAccessStrategy()); return JsonbBuilder.create(config); } diff --git a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/SerDeserializerRegistryFactory.java b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/SerDeserializerRegistryFactory.java index 02fb86f..8e9c6fb 100644 --- a/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/SerDeserializerRegistryFactory.java +++ b/quarkus/shared/src/main/java/org/fuin/cqrs4j/example/quarkus/shared/SerDeserializerRegistryFactory.java @@ -37,8 +37,7 @@ public class SerDeserializerRegistryFactory { final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer(); // Registry connects the type with the appropriate serializer and de-serializer - return SharedUtils.createSerDeserializerRegistry(typeRegistry, - jsonbDeSer); + return SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer); } diff --git a/shared/src/main/java/org/fuin/cqrs4j/example/shared/CreatePersonCommand.java b/shared/src/main/java/org/fuin/cqrs4j/example/shared/CreatePersonCommand.java index f47bae1..f70a5a9 100644 --- a/shared/src/main/java/org/fuin/cqrs4j/example/shared/CreatePersonCommand.java +++ b/shared/src/main/java/org/fuin/cqrs4j/example/shared/CreatePersonCommand.java @@ -56,8 +56,10 @@ public final class CreatePersonCommand extends AbstractAggregateCommand { /** * A new person was created in the system. * - * @param id Identifies uniquely a person. - * @param name Name of a person. + * @param id + * Identifies uniquely a person. + * @param name + * Name of a person. */ public PersonCreatedEvent(@NotNull final PersonId id, @NotNull final PersonName name) { super(new EntityIdPath(id)); diff --git a/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonId.java b/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonId.java index 2c6c787..86ad9f4 100644 --- a/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonId.java +++ b/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonId.java @@ -19,13 +19,13 @@ package org.fuin.cqrs4j.example.shared; import java.util.UUID; -import org.fuin.objects4j.common.Immutable; import javax.json.bind.adapter.JsonbAdapter; import javax.validation.constraints.NotNull; import org.fuin.ddd4j.ddd.AggregateRootUuid; import org.fuin.ddd4j.ddd.EntityType; import org.fuin.ddd4j.ddd.StringBasedEntityType; +import org.fuin.objects4j.common.Immutable; import org.fuin.objects4j.ui.Label; import org.fuin.objects4j.ui.ShortLabel; import org.fuin.objects4j.ui.Tooltip; diff --git a/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonName.java b/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonName.java index 21d0480..f238e2f 100644 --- a/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonName.java +++ b/shared/src/main/java/org/fuin/cqrs4j/example/shared/PersonName.java @@ -23,7 +23,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.fuin.objects4j.common.Immutable; import javax.json.bind.adapter.JsonbAdapter; import javax.validation.Constraint; import javax.validation.ConstraintValidator; @@ -32,6 +31,7 @@ import javax.validation.Payload; import javax.validation.constraints.NotNull; import org.fuin.objects4j.common.ConstraintViolationException; +import org.fuin.objects4j.common.Immutable; import org.fuin.objects4j.ui.Label; import org.fuin.objects4j.ui.ShortLabel; import org.fuin.objects4j.ui.Tooltip; @@ -66,7 +66,8 @@ public final class PersonName extends AbstractStringValueObject { /** * Constructor with mandatory data. * - * @param value Value. + * @param value + * Value. */ public PersonName(final String value) { super(); @@ -83,14 +84,14 @@ public final class PersonName extends AbstractStringValueObject { public final String toString() { return value; } - + /** * Verifies that a given string can be converted into the type. * - * @param value Value to validate. + * @param value + * Value to validate. * - * @return Returns true if it's a valid type else - * false. + * @return Returns true if it's a valid type else false. */ public static boolean isValid(final String value) { if (value == null) { @@ -107,16 +108,17 @@ public final class PersonName extends AbstractStringValueObject { } /** - * Verifies if the argument is valid and throws an exception if this is not the - * case. + * Verifies if the argument is valid and throws an exception if this is not the case. * - * @param name Name of the value for a possible error message. - * @param value Value to check. + * @param name + * Name of the value for a possible error message. + * @param value + * Value to check. * - * @throws ConstraintViolationException The value was not valid. + * @throws ConstraintViolationException + * The value was not valid. */ - public static void requireArgValid(@NotNull final String name, @NotNull final String value) - throws ConstraintViolationException { + public static void requireArgValid(@NotNull final String name, @NotNull final String value) throws ConstraintViolationException { if (!PersonName.isValid(value)) { throw new ConstraintViolationException("The argument '" + name + "' is not valid: '" + value + "'"); @@ -163,8 +165,7 @@ public final class PersonName extends AbstractStringValueObject { /** * Converts the value object from/to string. */ - public static final class Converter - implements ValueObjectConverter, JsonbAdapter { + public static final class Converter implements ValueObjectConverter, JsonbAdapter { // Attribute Converter diff --git a/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedEntityIdFactory.java b/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedEntityIdFactory.java index f7a7d77..a2456d9 100644 --- a/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedEntityIdFactory.java +++ b/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedEntityIdFactory.java @@ -29,42 +29,42 @@ import org.fuin.ddd4j.ddd.EntityIdFactory; */ public final class SharedEntityIdFactory implements EntityIdFactory { - private Map> valueOfMap; + private Map> valueOfMap; - private Map> isValidMap; + private Map> isValidMap; - /** - * Default constructor. - */ - public SharedEntityIdFactory() { - super(); - valueOfMap = new HashMap<>(); - isValidMap = new HashMap<>(); - valueOfMap.put(PersonId.TYPE.asString(), PersonId::valueOf); - isValidMap.put(PersonId.TYPE.asString(), PersonId::isValid); - } + /** + * Default constructor. + */ + public SharedEntityIdFactory() { + super(); + valueOfMap = new HashMap<>(); + isValidMap = new HashMap<>(); + valueOfMap.put(PersonId.TYPE.asString(), PersonId::valueOf); + isValidMap.put(PersonId.TYPE.asString(), PersonId::isValid); + } - @Override - public EntityId createEntityId(final String type, final String id) { - final Function factory = valueOfMap.get(type); - if (factory == null) { - throw new IllegalArgumentException("Unknown type: " + type); - } - return factory.apply(id); - } + @Override + public EntityId createEntityId(final String type, final String id) { + final Function factory = valueOfMap.get(type); + if (factory == null) { + throw new IllegalArgumentException("Unknown type: " + type); + } + return factory.apply(id); + } - @Override - public boolean containsType(final String type) { - return valueOfMap.containsKey(type); - } + @Override + public boolean containsType(final String type) { + return valueOfMap.containsKey(type); + } - @Override - public boolean isValid(String type, String id) { - final Function func = isValidMap.get(type); - if (func == null) { - return false; - } - return func.apply(id); - } + @Override + public boolean isValid(String type, String id) { + final Function func = isValidMap.get(type); + if (func == null) { + return false; + } + return func.apply(id); + } } diff --git a/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedUtils.java b/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedUtils.java index e981628..59f0537 100644 --- a/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedUtils.java +++ b/shared/src/main/java/org/fuin/cqrs4j/example/shared/SharedUtils.java @@ -19,7 +19,7 @@ package org.fuin.cqrs4j.example.shared; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.zip.Adler32; @@ -48,12 +48,14 @@ import org.fuin.esc.spi.SimpleSerializerDeserializerRegistry; */ public final class SharedUtils { + private static final String APPLICATION_JSON = "application/json"; + /** All types that will be written into and read from the event store. */ - private static TypeClass[] USER_DEFINED_TYPES = new TypeClass[] { + private static final TypeClass[] USER_DEFINED_TYPES = new TypeClass[] { new TypeClass(PersonCreatedEvent.SER_TYPE, PersonCreatedEvent.class) }; /** All JSON-B adapters from this module. */ - public static JsonbAdapter[] JSONB_ADAPTERS = new JsonbAdapter[] { new EventIdConverter(), + public static final JsonbAdapter[] JSONB_ADAPTERS = new JsonbAdapter[] { new EventIdConverter(), new EntityIdPathConverter(new SharedEntityIdFactory()), new EntityIdConverter(new SharedEntityIdFactory()), new AggregateVersionConverter(), new PersonId.Converter(), new PersonName.Converter() }; @@ -101,14 +103,14 @@ public final class SharedUtils { final SimpleSerializerDeserializerRegistry registry = new SimpleSerializerDeserializerRegistry(); // Base types always needed - registry.add(EscEvents.SER_TYPE, "application/json", jsonbDeSer); - registry.add(EscEvent.SER_TYPE, "application/json", jsonbDeSer); - registry.add(EscMeta.SER_TYPE, "application/json", jsonbDeSer); - registry.add(Base64Data.SER_TYPE, "application/json", jsonbDeSer); + registry.add(EscEvents.SER_TYPE, APPLICATION_JSON, jsonbDeSer); + registry.add(EscEvent.SER_TYPE, APPLICATION_JSON, jsonbDeSer); + registry.add(EscMeta.SER_TYPE, APPLICATION_JSON, jsonbDeSer); + registry.add(Base64Data.SER_TYPE, APPLICATION_JSON, jsonbDeSer); // User defined types for (final TypeClass tc : USER_DEFINED_TYPES) { - registry.add(tc.getType(), "application/json", jsonbDeSer); + registry.add(tc.getType(), APPLICATION_JSON, jsonbDeSer); } jsonbDeSer.init(typeRegistry, registry, registry); @@ -129,9 +131,7 @@ public final class SharedUtils { final JsonbDeSerializer jsonbDeSer = SharedUtils.createJsonbDeSerializer(); // Registry connects the type with the appropriate serializer and de-serializer - final SerDeserializerRegistry serDeserRegistry = SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer); - - return serDeserRegistry; + return SharedUtils.createSerDeserializerRegistry(typeRegistry, jsonbDeSer); } @@ -144,7 +144,7 @@ public final class SharedUtils { return JsonbDeSerializer.builder().withSerializers(EscSpiUtils.createEscJsonbSerializers()) .withDeserializers(EscSpiUtils.createEscJsonbDeserializers()).withAdapters(JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(Charset.forName("utf-8")).build(); + .withPropertyVisibilityStrategy(new FieldAccessStrategy()).withEncoding(StandardCharsets.UTF_8).build(); } @@ -159,7 +159,7 @@ public final class SharedUtils { public static long calculateChecksum(final Collection eventTypes) { final Adler32 checksum = new Adler32(); for (final EventType eventType : eventTypes) { - checksum.update(eventType.asBaseType().getBytes(Charset.forName("ascii"))); + checksum.update(eventType.asBaseType().getBytes(StandardCharsets.US_ASCII)); } return checksum.getValue(); } diff --git a/shared/src/test/java/org/fuin/cqrs4j/example/shared/CreatePersonCommandTest.java b/shared/src/test/java/org/fuin/cqrs4j/example/shared/CreatePersonCommandTest.java index cf60db2..2383ae9 100644 --- a/shared/src/test/java/org/fuin/cqrs4j/example/shared/CreatePersonCommandTest.java +++ b/shared/src/test/java/org/fuin/cqrs4j/example/shared/CreatePersonCommandTest.java @@ -35,74 +35,72 @@ import org.junit.Test; // CHECKSTYLE:OFF public final class CreatePersonCommandTest { - - private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; + private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; - @Test - public final void testSerializeDeserialize() { + @Test + public final void testSerializeDeserialize() { - // PREPARE - final CreatePersonCommand original = createTestee(); + // PREPARE + final CreatePersonCommand original = createTestee(); - // TEST - final CreatePersonCommand copy = Utils4J.deserialize(Utils4J.serialize(original)); + // TEST + final CreatePersonCommand copy = Utils4J.deserialize(Utils4J.serialize(original)); - // VERIFY - assertThat(copy).isEqualTo(original); - assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); - assertThat(copy.getName()).isEqualTo(original.getName()); + // VERIFY + assertThat(copy).isEqualTo(original); + assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); + assertThat(copy.getName()).isEqualTo(original.getName()); - } + } - @Test - public final void testMarshalUnmarshalJson() { + @Test + public final void testMarshalUnmarshalJson() { - // PREPARE - final CreatePersonCommand original = createTestee(); + // PREPARE + final CreatePersonCommand original = createTestee(); - final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); - // TEST - final String json = jsonb.toJson(original, CreatePersonCommand.class); - final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); + // TEST + final String json = jsonb.toJson(original, CreatePersonCommand.class); + final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); - // VERIFY - assertThat(copy).isEqualTo(original); - assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); - assertThat(copy.getName()).isEqualTo(original.getName()); + // VERIFY + assertThat(copy).isEqualTo(original); + assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); + assertThat(copy.getName()).isEqualTo(original.getName()); - } + } - @Test - public final void testUnmarshalJsonFromFile() throws IOException { + @Test + public final void testUnmarshalJsonFromFile() throws IOException { - // PREPARE + // PREPARE final String json = IOUtils.toString(this.getClass().getResourceAsStream("/commands/CreatePersonCommand.json"), Charset.forName("utf-8")); - final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); - + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); - // TEST - final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); + // TEST + final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); - // VERIFY - assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552")); - assertThat(copy.getEventTimestamp()).isEqualTo(ZonedDateTime.parse("2019-11-17T10:27:13.183+01:00[Europe/Berlin]")); - assertThat(copy.getAggregateRootId().asString()).isEqualTo(PERSON_UUID); - assertThat(copy.getName().asString()).isEqualTo("Peter Parker"); + // VERIFY + assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552")); + assertThat(copy.getEventTimestamp()).isEqualTo(ZonedDateTime.parse("2019-11-17T10:27:13.183+01:00[Europe/Berlin]")); + assertThat(copy.getAggregateRootId().asString()).isEqualTo(PERSON_UUID); + assertThat(copy.getName().asString()).isEqualTo("Peter Parker"); - } + } - private CreatePersonCommand createTestee() { - final PersonId personId = new PersonId(UUID.fromString(PERSON_UUID)); - final PersonName personName = new PersonName("Peter Parker"); - return new CreatePersonCommand(personId, personName); - } + private CreatePersonCommand createTestee() { + final PersonId personId = new PersonId(UUID.fromString(PERSON_UUID)); + final PersonName personName = new PersonName("Peter Parker"); + return new CreatePersonCommand(personId, personName); + } } // CHECKSTYLE:ON diff --git a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonCreatedEventTest.java b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonCreatedEventTest.java index f536013..d39b2fa 100644 --- a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonCreatedEventTest.java +++ b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonCreatedEventTest.java @@ -33,7 +33,6 @@ import org.apache.commons.io.IOUtils; import org.eclipse.yasson.FieldAccessStrategy; import org.junit.Test; - // CHECKSTYLE:OFF public final class PersonCreatedEventTest { @@ -71,7 +70,7 @@ public final class PersonCreatedEventTest { assertThat(copy.getName()).isEqualTo(original.getName()); } - + @Test public final void testUnmarshalJson() throws IOException { @@ -92,12 +91,11 @@ public final class PersonCreatedEventTest { } - @Test public final void testToString() { final PersonCreatedEvent testee = createTestee(); - assertThat(testee.toString()) - .isEqualTo("Person 'Peter Parker' (" + testee.getEntityId() + ") was created [Event " + testee.getEventId() + "]"); + assertThat(testee) + .hasToString("Person 'Peter Parker' (" + testee.getEntityId() + ") was created [Event " + testee.getEventId() + "]"); } private PersonCreatedEvent createTestee() { diff --git a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonIdTest.java b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonIdTest.java index bc32843..7ce72c7 100644 --- a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonIdTest.java +++ b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonIdTest.java @@ -35,57 +35,55 @@ import nl.jqno.equalsverifier.Warning; */ public final class PersonIdTest { - private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; + private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; - @Test - public void testEquals() { - EqualsVerifier.forClass(PersonId.class).suppress(Warning.NONFINAL_FIELDS) - .withNonnullFields("entityType", "uuid") - .withPrefabValues(EntityType.class, new StringBasedEntityType("A"), new StringBasedEntityType("B")) - .verify(); - } + @Test + public void testEquals() { + EqualsVerifier.forClass(PersonId.class).suppress(Warning.NONFINAL_FIELDS).withNonnullFields("entityType", "uuid") + .withPrefabValues(EntityType.class, new StringBasedEntityType("A"), new StringBasedEntityType("B")).verify(); + } - @Test - public void testValueOf() { - final PersonId personId = PersonId.valueOf(PERSON_UUID); + @Test + public void testValueOf() { + final PersonId personId = PersonId.valueOf(PERSON_UUID); - assertThat(personId.asString()).isEqualTo(PERSON_UUID); + assertThat(personId.asString()).isEqualTo(PERSON_UUID); - } + } - @Test - public void testValueOfIllegalArgumentCharacter() { - try { - PersonId.valueOf("abc"); - fail(); - } catch (final ConstraintViolationException ex) { - assertThat(ex.getMessage()).isEqualTo("The argument 'value' is not valid: 'abc'"); - } - } + @Test + public void testValueOfIllegalArgumentCharacter() { + try { + PersonId.valueOf("abc"); + fail(); + } catch (final ConstraintViolationException ex) { + assertThat(ex.getMessage()).isEqualTo("The argument 'value' is not valid: 'abc'"); + } + } - @Test - public final void testConverterUnmarshal() throws Exception { + @Test + public final void testConverterUnmarshal() throws Exception { - // PREPARE - final String personIdValue = PERSON_UUID; + // PREPARE + final String personIdValue = PERSON_UUID; - // TEST - final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID)); + // TEST + final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID)); - // VERIFY - assertThat(personId.asString()).isEqualTo(personIdValue); - } + // VERIFY + assertThat(personId.asString()).isEqualTo(personIdValue); + } - @Test - public void testConverterMarshal() throws Exception { + @Test + public void testConverterMarshal() throws Exception { - final PersonId personId = PersonId.valueOf(PERSON_UUID); + final PersonId personId = PersonId.valueOf(PERSON_UUID); - // TEST - final UUID uuid = new PersonId.Converter().adaptToJson(personId); + // TEST + final UUID uuid = new PersonId.Converter().adaptToJson(personId); - // VERIFY - assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID)); - } + // VERIFY + assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID)); + } } diff --git a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonNameTest.java b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonNameTest.java index 1b3ae3b..39c2381 100644 --- a/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonNameTest.java +++ b/shared/src/test/java/org/fuin/cqrs4j/example/shared/PersonNameTest.java @@ -17,7 +17,6 @@ */ package org.fuin.cqrs4j.example.shared; - import static org.assertj.core.api.Assertions.assertThat; import org.fuin.objects4j.common.ConstraintViolationException; @@ -76,8 +75,9 @@ public final class PersonNameTest { assertThat(PersonName.isValid("Peter Parker")).isTrue(); assertThat(PersonName.isValid("")).isFalse(); - assertThat(PersonName.isValid("123456789.123456789.123456789.123456789.123456789." - + "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse(); + assertThat(PersonName.isValid( + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345")) + .isFalse(); } @@ -95,13 +95,12 @@ public final class PersonNameTest { } try { - PersonName.requireArgValid("d", "123456789.123456789.123456789.123456789.123456789." - + "123456789.123456789.123456789.123456789.123456789." + "12345"); + PersonName.requireArgValid("d", + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345"); Assert.fail(); } catch (final ConstraintViolationException ex) { - assertThat(ex.getMessage()) - .isEqualTo("The argument 'd' is not valid: '" + "123456789.123456789.123456789.123456789.123456789." - + "123456789.123456789.123456789.123456789.123456789." + "12345" + "'"); + assertThat(ex.getMessage()).isEqualTo("The argument 'd' is not valid: '" + "123456789.123456789.123456789.123456789.123456789." + + "123456789.123456789.123456789.123456789.123456789." + "12345" + "'"); } } @@ -113,8 +112,9 @@ public final class PersonNameTest { assertThat(new PersonName.Validator().isValid("Peter Parker", null)).isTrue(); assertThat(new PersonName.Validator().isValid("", null)).isFalse(); - assertThat(new PersonName.Validator().isValid("123456789.123456789.123456789.123456789.123456789." - + "123456789.123456789.123456789.123456789.123456789." + "12345", null)).isFalse(); + assertThat(new PersonName.Validator().isValid( + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345", + null)).isFalse(); } @@ -126,8 +126,9 @@ public final class PersonNameTest { assertThat(new PersonName.Converter().isValid(null)).isTrue(); assertThat(new PersonName.Converter().isValid("Peter Parker")).isTrue(); - assertThat(new PersonName.Converter().isValid("123456789.123456789.123456789.123456789.123456789." - + "123456789.123456789.123456789.123456789.123456789." + "12345")).isFalse(); + assertThat(new PersonName.Converter().isValid( + "123456789.123456789.123456789.123456789.123456789." + "123456789.123456789.123456789.123456789.123456789." + "12345")) + .isFalse(); } diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdApplication.java b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdApplication.java index 1c6a957..be35893 100644 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdApplication.java +++ b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdApplication.java @@ -8,24 +8,25 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.context.annotation.RequestScope; @SpringBootApplication(scanBasePackages = { "org.fuin.cqrs4j.example.spring.command.app", - "org.fuin.cqrs4j.example.spring.command.controller", "org.fuin.cqrs4j.example.spring.shared" }) + "org.fuin.cqrs4j.example.spring.command.controller", "org.fuin.cqrs4j.example.spring.shared" }) public class CmdApplication { - /** - * Creates an event sourced repository that can store a person. - * - * @param eventStore Event store to use. - * - * @return Repository only valid for the current request. - */ - @Bean - @RequestScope - public PersonRepository create(final IESJCEventStore eventStore) { - return new PersonRepository(eventStore); - } + /** + * Creates an event sourced repository that can store a person. + * + * @param eventStore + * Event store to use. + * + * @return Repository only valid for the current request. + */ + @Bean + @RequestScope + public PersonRepository create(final IESJCEventStore eventStore) { + return new PersonRepository(eventStore); + } - public static void main(String[] args) { - SpringApplication.run(CmdApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(CmdApplication.class, args); + } } diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/PersonController.java b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/PersonController.java index 618d51d..acf8b02 100644 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/PersonController.java +++ b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/PersonController.java @@ -40,33 +40,32 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/persons") public class PersonController { - @Autowired - private PersonRepository repo; + @Autowired + private PersonRepository repo; - @Autowired - private Validator validator; + @Autowired + private Validator validator; - @PostMapping(path = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity create(@RequestBody final CreatePersonCommand cmd) - throws AggregateAlreadyExistsException, AggregateDeletedException, CommandExecutionFailedException, - DuplicatePersonNameException { + @PostMapping(path = "/create", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity create(@RequestBody final CreatePersonCommand cmd) throws AggregateAlreadyExistsException, + AggregateDeletedException, CommandExecutionFailedException, DuplicatePersonNameException { - // Verify preconditions - final Set> violations = validator.validate(cmd); - if (!violations.isEmpty()) { - throw new ConstraintViolationException(violations); - } + // Verify preconditions + final Set> violations = validator.validate(cmd); + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } - // Create aggregate - final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), (name) -> { - // TODO Execute a call to the query side to verify if the name already exists - return Optional.empty(); - }); - repo.add(person); + // Create aggregate + final Person person = new Person(cmd.getAggregateRootId(), cmd.getName(), name -> { + // TODO Execute a call to the query side to verify if the name already exists + return Optional.empty(); + }); + repo.add(person); - // Send OK response - return new ResponseEntity<>(SimpleResult.ok(), HttpStatus.OK); + // Send OK response + return new ResponseEntity<>(SimpleResult.ok(), HttpStatus.OK); - } + } } diff --git a/spring-boot/command/src/test/java/org/fuin/cqrs4j/example/spring/command/api/PersonControllerIT.java b/spring-boot/command/src/test/java/org/fuin/cqrs4j/example/spring/command/api/PersonControllerIT.java index 285e594..712041f 100644 --- a/spring-boot/command/src/test/java/org/fuin/cqrs4j/example/spring/command/api/PersonControllerIT.java +++ b/spring-boot/command/src/test/java/org/fuin/cqrs4j/example/spring/command/api/PersonControllerIT.java @@ -39,49 +39,40 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = CmdApplication.class) -public class PersonControllerIT { +class PersonControllerIT { - @LocalServerPort + @LocalServerPort int port; - - @Autowired - WebApplicationContext wac; - - @Autowired - IESJCEventStore eventStore; - @Autowired + @Autowired + WebApplicationContext wac; + + @Autowired + IESJCEventStore eventStore; + + @Autowired Jsonb jsonb; - - @BeforeEach - public void initRestAssuredMockMvcStandalone() { - RestAssured.port = port; - RestAssuredMockMvc.webAppContextSetup(wac); - } - + + @BeforeEach + public void initRestAssuredMockMvcStandalone() { + RestAssured.port = port; + RestAssuredMockMvc.webAppContextSetup(wac); + } + @Test - public void testCreate() { - + void testCreate() { + // PREPARE final PersonId personId = new PersonId(UUID.randomUUID()); final PersonName personName = new PersonName("Peter Parker"); final CreatePersonCommand cmd = new CreatePersonCommand(personId, personName); final String json = jsonb.toJson(cmd); - + // TEST & VERIFY - final SimpleResult result = - given() - .accept(ContentType.JSON) - .contentType(ContentType.JSON) - .body(json) - .when() - .post("/persons/create") - .then() - .statusCode(200) - .extract() - .as(SimpleResult.class); + final SimpleResult result = given().accept(ContentType.JSON).contentType(ContentType.JSON).body(json).when().post("/persons/create") + .then().statusCode(200).extract().as(SimpleResult.class); assertThat(result.getType(), is(equalTo(ResultType.OK))); - + final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId); final StreamEventsSlice slice = eventStore.readEventsForward(personStreamId, 0, 1); final List events = slice.getEvents(); @@ -91,7 +82,7 @@ public class PersonControllerIT { final PersonCreatedEvent event = (PersonCreatedEvent) ce.getData(); assertThat(event.getEntityId(), is(equalTo(personId))); assertThat(event.getName(), is(equalTo(personName))); - + } } \ No newline at end of file diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryApplication.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryApplication.java index dd5fafb..106af79 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryApplication.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryApplication.java @@ -11,29 +11,28 @@ import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -@SpringBootApplication(scanBasePackages = { "org.fuin.cqrs4j.example.spring.query.app", - "org.fuin.cqrs4j.example.spring.query.controller", "org.fuin.cqrs4j.example.spring.query.views.common", - "org.fuin.cqrs4j.example.spring.query.views.personlist", "org.fuin.cqrs4j.example.spring.shared" }) +@SpringBootApplication(scanBasePackages = { "org.fuin.cqrs4j.example.spring.query.app", "org.fuin.cqrs4j.example.spring.query.controller", + "org.fuin.cqrs4j.example.spring.query.views.common", "org.fuin.cqrs4j.example.spring.query.views.personlist", + "org.fuin.cqrs4j.example.spring.shared" }) @EnableJpaRepositories("org.fuin.cqrs4j.example.spring.query.views.common") -@EntityScan({ "org.fuin.cqrs4j.example.spring.query.views.common", - "org.fuin.cqrs4j.example.spring.query.views.personlist" }) +@EntityScan({ "org.fuin.cqrs4j.example.spring.query.views.common", "org.fuin.cqrs4j.example.spring.query.views.personlist" }) @EnableScheduling @EnableAsync public class QryApplication { - @Bean("projectorExecutor") - public Executor taskExecutor() { - final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(1); - executor.setMaxPoolSize(5); - executor.setQueueCapacity(500); - executor.setThreadNamePrefix("person-"); - executor.initialize(); - return executor; - } + @Bean("projectorExecutor") + public Executor taskExecutor() { + final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(1); + executor.setMaxPoolSize(5); + executor.setQueueCapacity(500); + executor.setThreadNamePrefix("person-"); + executor.initialize(); + return executor; + } - public static void main(String[] args) { - SpringApplication.run(QryApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(QryApplication.class, args); + } } diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonController.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonController.java index 5cb875f..eaad69d 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonController.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonController.java @@ -36,44 +36,45 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/persons") @Transactional(readOnly = true) public class PersonController { - - private static final Logger LOG = LoggerFactory.getLogger(PersonController.class); + + private static final Logger LOG = LoggerFactory.getLogger(PersonController.class); @Autowired private EntityManager em; - /** - * Get all persons list. - * - * @return the list - */ - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - public List getAllPersons() { + /** + * Get all persons list. + * + * @return the list + */ + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public List getAllPersons() { final List persons = em.createNamedQuery(PersonListEntry.FIND_ALL, PersonListEntry.class).getResultList(); LOG.info("getAllPersons() = {}", persons.size()); - return persons; - } + return persons; + } + + /** + * Reads a person by it's universally unique aggregate UUID. + * + * @param personId + * Person UUID. + * + * @return Person from database. + * + * @throws AggregateNotFoundException + * A person with the given identifier is unknown. + */ + @GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getPersonById(@PathVariable(value = "id") @UUIDStr String personId) + throws AggregateNotFoundException { - /** - * Reads a person by it's universally unique aggregate UUID. - * - * @param personId Person UUID. - * - * @return Person from database. - * - * @throws AggregateNotFoundException A person with the given identifier is - * unknown. - */ - @GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getPersonById(@PathVariable(value = "id") @UUIDStr String personId) - throws AggregateNotFoundException { - final PersonListEntry person = em.find(PersonListEntry.class, personId); if (person == null) { - throw new AggregateNotFoundException(PersonId.TYPE, new PersonId(UUID.fromString(personId))); + throw new AggregateNotFoundException(PersonId.TYPE, new PersonId(UUID.fromString(personId))); } LOG.info("getPersonById({}) = {}", personId, person); - return ResponseEntity.ok().body(person); - } + return ResponseEntity.ok().body(person); + } } diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java index 7fa2528..89022a8 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java @@ -11,17 +11,18 @@ import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; /** - * Service to read and persist the next position of a stream to read. + * Service to read and persist the next position of a stream to read. */ @Repository public class QryProjectionService implements ProjectionService { + private static final String ARG_STREAM_ID = "streamId"; @PersistenceContext private EntityManager em; - + @Override public void resetProjectionPosition(@NotNull final StreamId streamId) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos != null) { pos.setNextPosition(0L); @@ -31,7 +32,7 @@ public class QryProjectionService implements ProjectionService { @Override @Transactional(readOnly = true) public Long readProjectionPosition(@NotNull StreamId streamId) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { return 0L; @@ -41,12 +42,12 @@ public class QryProjectionService implements ProjectionService { @Override public void updateProjectionPosition(@NotNull StreamId streamId, @NotNull Long nextEventNumber) { - Contract.requireArgNotNull("streamId", streamId); + Contract.requireArgNotNull(ARG_STREAM_ID, streamId); Contract.requireArgNotNull("nextEventNumber", nextEventNumber); QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { pos = new QryProjectionPosition(streamId, nextEventNumber); - em.persist(pos); + em.persist(pos); } else { pos.setNextPosition(nextEventNumber); } diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/package-info.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/package-info.java index e0e3fbb..fde056c 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/package-info.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/package-info.java @@ -14,5 +14,5 @@ package org.fuin.cqrs4j.example.spring.query.views; /** * Contains the views used in this query application. A view never uses code of another view, means all views are completely independent of - * each other. As an exception, the 'commons' package has some small classes that are not view specific. + * each other. As an exception, the 'commons' package has some small classes that are not view specific. */ diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java index 5c0c5fb..7981c38 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java @@ -16,7 +16,7 @@ import org.springframework.stereotype.Component; */ @Component public class PersonCreatedEventHandler implements EventHandler { - + private static final Logger LOG = LoggerFactory.getLogger(PersonCreatedEventHandler.class); @Autowired @@ -27,9 +27,9 @@ public class PersonCreatedEventHandler implements EventHandler getAllTypes() { - return delegate.getAllTypes(); - } + @Override + public @NotNull Set getAllTypes() { + return delegate.getAllTypes(); + } - @Override - public void dispatchCommonEvents(@NotNull List commonEvents) { - delegate.dispatchCommonEvents(commonEvents); - } + @Override + public void dispatchCommonEvents(@NotNull List commonEvents) { + delegate.dispatchCommonEvents(commonEvents); + } - @Override - public void dispatchEvents(@NotNull List events) { - delegate.dispatchEvents(events); - } + @Override + public void dispatchEvents(@NotNull List events) { + delegate.dispatchEvents(events); + } - @Override - public void dispatchEvent(@NotNull Event event) { - delegate.dispatchEvent(event); - } + @Override + public void dispatchEvent(@NotNull Event event) { + delegate.dispatchEvent(event); + } } diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonListProjector.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonListProjector.java index 246673c..f866da9 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonListProjector.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonListProjector.java @@ -9,11 +9,11 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.PreDestroy; -import org.fuin.objects4j.common.ThreadSafe; import org.fuin.ddd4j.ddd.EventType; import org.fuin.esc.api.TypeName; import org.fuin.esc.eshttp.IESHttpEventStore; +import org.fuin.objects4j.common.ThreadSafe; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -24,66 +24,64 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; /** - * Reads incoming events from an event store projection and dispatches them to - * the appropriate event handlers. The event store projection will be created by - * this class, if it does not yet exist. + * Reads incoming events from an event store projection and dispatches them to the appropriate event handlers. The event store projection + * will be created by this class, if it does not yet exist. */ @ThreadSafe @Component public class PersonListProjector { - private static final Logger LOG = LoggerFactory.getLogger(PersonListProjector.class); + private static final Logger LOG = LoggerFactory.getLogger(PersonListProjector.class); - /** Prevents more than one projector thread running at a time. */ - private static final Semaphore LOCK = new Semaphore(1); + /** Prevents more than one projector thread running at a time. */ + private static final Semaphore LOCK = new Semaphore(1); - private static AtomicBoolean APP_STARTED = new AtomicBoolean(false); - - // The following beans are NOT thread safe! - // Above LOCK prevents multithreaded access + private static final AtomicBoolean APP_STARTED = new AtomicBoolean(false); - @Autowired - private IESHttpEventStore eventstore; + // The following beans are NOT thread safe! + // Above LOCK prevents multithreaded access - @Autowired - private PersonListEventChunkHandler chunkHandler; + @Autowired + private IESHttpEventStore eventstore; - @Autowired - private PersonListEventDispatcher dispatcher; + @Autowired + private PersonListEventChunkHandler chunkHandler; - /** - * Runs triggered by the timer. If a second timer event occurs while the - * previous call is still being executed, the method execution will simply be - * skipped. - */ - @Scheduled(fixedRate = 100) - @Async("projectorExecutor") - public void execute() { - if (!APP_STARTED.get()) { - // Do nothing until application started - return; - } - tryLocked(LOCK, () -> { - try { - readStreamEvents(); - } catch (final RuntimeException ex) { - LOG.error("Error reading events from stream", ex); - } - }); - } - - @EventListener(ApplicationReadyEvent.class) - public void onAppStart() { - LOG.info("Application started"); - APP_STARTED.set(true); - } + @Autowired + private PersonListEventDispatcher dispatcher; - @PreDestroy - public void destroy() { - APP_STARTED.set(false); - LOG.info("Application stopped"); + /** + * Runs triggered by the timer. If a second timer event occurs while the previous call is still being executed, the method execution + * will simply be skipped. + */ + @Scheduled(fixedRate = 100) + @Async("projectorExecutor") + public void execute() { + if (!APP_STARTED.get()) { + // Do nothing until application started + return; + } + tryLocked(LOCK, () -> { + try { + readStreamEvents(); + } catch (final RuntimeException ex) { + LOG.error("Error reading events from stream", ex); + } + }); } - + + @EventListener(ApplicationReadyEvent.class) + public void onAppStart() { + LOG.info("Application started"); + APP_STARTED.set(true); + } + + @PreDestroy + public void destroy() { + APP_STARTED.set(false); + LOG.info("Application stopped"); + } + private void readStreamEvents() { // Create a projection if it does not exist. @@ -97,9 +95,8 @@ public class PersonListProjector { // Read and dispatch events final Long nextEventNumber = chunkHandler.readNextEventNumber(); - eventstore.readAllEventsForward(chunkHandler.getProjectionStreamId(), nextEventNumber, 100, (currentSlice) -> { - chunkHandler.handleChunk(currentSlice); - }); + eventstore.readAllEventsForward(chunkHandler.getProjectionStreamId(), nextEventNumber, 100, + currentSlice -> chunkHandler.handleChunk(currentSlice)); } diff --git a/spring-boot/query/src/test/java/org/fuin/cqrs4j/example/spring/query/api/PersonControllerIT.java b/spring-boot/query/src/test/java/org/fuin/cqrs4j/example/spring/query/api/PersonControllerIT.java index d97d2af..b4f1a49 100644 --- a/spring-boot/query/src/test/java/org/fuin/cqrs4j/example/spring/query/api/PersonControllerIT.java +++ b/spring-boot/query/src/test/java/org/fuin/cqrs4j/example/spring/query/api/PersonControllerIT.java @@ -40,72 +40,72 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ContextConfiguration(classes = QryApplication.class) -public class PersonControllerIT { +class PersonControllerIT { - @LocalServerPort + @LocalServerPort int port; - - @Autowired - WebApplicationContext wac; - - @Autowired - IESHttpEventStore eventStore; - @Autowired - EntityManager em; + @Autowired + WebApplicationContext wac; - @Autowired - PersonController testee; + @Autowired + IESHttpEventStore eventStore; - @Autowired - Config config; + @Autowired + EntityManager em; - @BeforeEach - public void initRestAssuredMockMvcStandalone() { - RestAssured.port = port; - RestAssuredMockMvc.webAppContextSetup(wac); - } + @Autowired + PersonController testee; - @Test - public void testGetByIdNotFound() { - given().pathParam("id", UUID.randomUUID()).when().get("/persons/{id}").then().statusCode(404); - } + @Autowired + Config config; - public boolean findPerson(final PersonId personId) { - return em.find(PersonListEntry.class, personId.asString()) != null; - } + @BeforeEach + public void initRestAssuredMockMvcStandalone() { + RestAssured.port = port; + RestAssuredMockMvc.webAppContextSetup(wac); + } - @Test - public void testGetByIdOK() { + @Test + void testGetByIdNotFound() { + given().pathParam("id", UUID.randomUUID()).when().get("/persons/{id}").then().statusCode(404); + } - // PREPARE - final PersonId personId = new PersonId(UUID.randomUUID()); - final PersonName personName = new PersonName("Peter Parker " + personId); - final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId); - final PersonCreatedEvent event = new PersonCreatedEvent(personId, personName); - final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()), - new TypeName(event.getEventType().asBaseType()), event); - eventStore.appendToStream(personStreamId, ce); + public boolean findPerson(final PersonId personId) { + return em.find(PersonListEntry.class, personId.asString()) != null; + } - await().atMost(5, SECONDS).until(() -> findPerson(personId)); + @Test + void testGetByIdOK() { - // TEST & VERIFY + // PREPARE + final PersonId personId = new PersonId(UUID.randomUUID()); + final PersonName personName = new PersonName("Peter Parker " + personId); + final SimpleStreamId personStreamId = new SimpleStreamId(PersonId.TYPE + "-" + personId); + final PersonCreatedEvent event = new PersonCreatedEvent(personId, personName); + final CommonEvent ce = new SimpleCommonEvent(new EventId(event.getEventId().asBaseType()), + new TypeName(event.getEventType().asBaseType()), event); + eventStore.appendToStream(personStreamId, ce); - // given().pathParam("id", personId.asString()).when().get("/persons/{id}").then().log().all(true); - - final PersonListEntry person = given().pathParam("id", personId.asString()).when().get("/persons/{id}").then() - .statusCode(200).extract().as(PersonListEntry.class); - assertThat(person.getId(), is(equalTo(personId))); - assertThat(person.getName(), is(equalTo(personName))); + await().atMost(5, SECONDS).until(() -> findPerson(personId)); - final PersonListEntry[] persons = given().when().get("/persons").then().statusCode(200).extract() - .as(PersonListEntry[].class); + // TEST & VERIFY - assertThat(Arrays.asList(persons), is(not(empty()))); - final PersonListEntry person0 = persons[0]; - assertThat(person0.getId(), is(equalTo(personId))); - assertThat(person0.getName(), is(equalTo(personName))); + // given().pathParam("id", + // personId.asString()).when().get("/persons/{id}").then().log().all(true); - } + final PersonListEntry person = given().pathParam("id", personId.asString()).when().get("/persons/{id}").then().statusCode(200) + .extract().as(PersonListEntry.class); + assertThat(person.getId(), is(equalTo(personId))); + assertThat(person.getName(), is(equalTo(personName))); + + final PersonListEntry[] persons = given().when().get("/persons").then().statusCode(200).extract().as(PersonListEntry[].class); + + assertThat(Arrays.asList(persons), is(not(empty()))); + final PersonListEntry person0 = persons[0]; + assertThat(person0.getId(), is(equalTo(personId))); + assertThat(person0.getName(), is(equalTo(personName))); + + } } diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/BeanFactory.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/BeanFactory.java index 2c53fef..11d8cba 100644 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/BeanFactory.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/BeanFactory.java @@ -2,7 +2,7 @@ package org.fuin.cqrs4j.example.spring.shared; import java.net.MalformedURLException; import java.net.URL; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.concurrent.Executors; import javax.json.bind.Jsonb; @@ -39,8 +39,7 @@ public class BeanFactory { public Jsonb createJsonb() { final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); - return jsonb; + return JsonbBuilder.create(config); } /** @@ -72,7 +71,7 @@ public class BeanFactory { final SerDeserializerRegistry registry = SharedUtils.createRegistry(); final IESJCEventStore eventstore = new ESJCEventStore.Builder().eventStore(es).serDesRegistry(registry) - .targetContentType(EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))).build(); + .targetContentType(EnhancedMimeType.create("application", "json", StandardCharsets.UTF_8)).build(); eventstore.open(); return eventstore; diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java index 1c8254f..1d1d5a4 100644 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java @@ -6,122 +6,128 @@ import org.springframework.stereotype.Component; @Component public class Config { - private static final String EVENT_STORE_PROTOCOL = "http"; + private static final String EVENT_STORE_PROTOCOL = "http"; - private static final String EVENT_STORE_HOST = "localhost"; + private static final String EVENT_STORE_HOST = "localhost"; - private static final int EVENT_STORE_HTTP_PORT = 2113; + private static final int EVENT_STORE_HTTP_PORT = 2113; - private static final int EVENT_STORE_TCP_PORT = 1113; + private static final int EVENT_STORE_TCP_PORT = 1113; - private static final String EVENT_STORE_USER = "admin"; + private static final String EVENT_STORE_USER = "admin"; - private static final String EVENT_STORE_PASSWORD = "changeit"; + private static final String EVENT_STORE_PASSWORD = "changeit"; - @Value("${EVENT_STORE_PROTOCOL:http}") - private String eventStoreProtocol; + @Value("${EVENT_STORE_PROTOCOL:http}") + private String eventStoreProtocol; - @Value("${EVENT_STORE_HOST:localhost}") - private String eventStoreHost; + @Value("${EVENT_STORE_HOST:localhost}") + private String eventStoreHost; - @Value("${EVENT_STORE_HTTP_PORT:2113}") - private int eventStoreHttpPort; + @Value("${EVENT_STORE_HTTP_PORT:2113}") + private int eventStoreHttpPort; - @Value("${EVENT_STORE_TCP_PORT:1113}") - private int eventStoreTcpPort; + @Value("${EVENT_STORE_TCP_PORT:1113}") + private int eventStoreTcpPort; - @Value("${EVENT_STORE_USER:admin}") - private String eventStoreUser; + @Value("${EVENT_STORE_USER:admin}") + private String eventStoreUser; - @Value("${EVENT_STORE_PASSWORD:changeit}") - private String eventStorePassword; + @Value("${EVENT_STORE_PASSWORD:changeit}") + private String eventStorePassword; - /** - * Constructor using default values internally. - */ - public Config() { - super(); - this.eventStoreProtocol = EVENT_STORE_PROTOCOL; - this.eventStoreHost = EVENT_STORE_HOST; - this.eventStoreHttpPort = EVENT_STORE_HTTP_PORT; - this.eventStoreTcpPort = EVENT_STORE_TCP_PORT; - this.eventStoreUser = EVENT_STORE_USER; - this.eventStorePassword = EVENT_STORE_PASSWORD; - } + /** + * Constructor using default values internally. + */ + public Config() { + super(); + this.eventStoreProtocol = EVENT_STORE_PROTOCOL; + this.eventStoreHost = EVENT_STORE_HOST; + this.eventStoreHttpPort = EVENT_STORE_HTTP_PORT; + this.eventStoreTcpPort = EVENT_STORE_TCP_PORT; + this.eventStoreUser = EVENT_STORE_USER; + this.eventStorePassword = EVENT_STORE_PASSWORD; + } - /** - * Constructor with all data. - * - * @param eventStoreProtocol Protocol. - * @param eventStoreHost Host. - * @param eventStoreHttpPort HTTP port - * @param eventStoreTcpPort TCP port. - * @param eventStoreUser User. - * @param eventStorePassword Password. - */ - public Config(final String eventStoreProtocol, final String eventStoreHost, final int eventStoreHttpPort, - final int eventStoreTcpPort, final String eventStoreUser, final String eventStorePassword) { - super(); - this.eventStoreProtocol = eventStoreProtocol; - this.eventStoreHost = eventStoreHost; - this.eventStoreHttpPort = eventStoreHttpPort; - this.eventStoreTcpPort = eventStoreTcpPort; - this.eventStoreUser = eventStoreUser; - this.eventStorePassword = eventStorePassword; - } + /** + * Constructor with all data. + * + * @param eventStoreProtocol + * Protocol. + * @param eventStoreHost + * Host. + * @param eventStoreHttpPort + * HTTP port + * @param eventStoreTcpPort + * TCP port. + * @param eventStoreUser + * User. + * @param eventStorePassword + * Password. + */ + public Config(final String eventStoreProtocol, final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, + final String eventStoreUser, final String eventStorePassword) { + super(); + this.eventStoreProtocol = eventStoreProtocol; + this.eventStoreHost = eventStoreHost; + this.eventStoreHttpPort = eventStoreHttpPort; + this.eventStoreTcpPort = eventStoreTcpPort; + this.eventStoreUser = eventStoreUser; + this.eventStorePassword = eventStorePassword; + } - /** - * Returns the protocol of the event store. - * - * @return Either http or https. - */ - public String getEventStoreProtocol() { - return eventStoreProtocol; - } + /** + * Returns the protocol of the event store. + * + * @return Either http or https. + */ + public String getEventStoreProtocol() { + return eventStoreProtocol; + } - /** - * Returns the host name of the event store. - * - * @return Name. - */ - public String getEventStoreHost() { - return eventStoreHost; - } + /** + * Returns the host name of the event store. + * + * @return Name. + */ + public String getEventStoreHost() { + return eventStoreHost; + } - /** - * Returns the HTTP port of the event store. - * - * @return Port. - */ - public int getEventStoreHttpPort() { - return eventStoreHttpPort; - } + /** + * Returns the HTTP port of the event store. + * + * @return Port. + */ + public int getEventStoreHttpPort() { + return eventStoreHttpPort; + } - /** - * Returns the TCP port of the event store. - * - * @return Port. - */ - public int getEventStoreTcpPort() { - return eventStoreTcpPort; - } + /** + * Returns the TCP port of the event store. + * + * @return Port. + */ + public int getEventStoreTcpPort() { + return eventStoreTcpPort; + } - /** - * Returns the username of the event store. - * - * @return Username. - */ - public String getEventStoreUser() { - return eventStoreUser; - } + /** + * Returns the username of the event store. + * + * @return Username. + */ + public String getEventStoreUser() { + return eventStoreUser; + } - /** - * Returns the password of the event store. - * - * @return Password. - */ - public String getEventStorePassword() { - return eventStorePassword; - } + /** + * Returns the password of the event store. + * + * @return Password. + */ + public String getEventStorePassword() { + return eventStorePassword; + } } diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java index ba826ac..1df8ef2 100644 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java @@ -16,7 +16,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import org.fuin.objects4j.common.Nullable; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; @@ -29,6 +28,7 @@ import org.fuin.ddd4j.ddd.AggregateVersionConflictException; import org.fuin.ddd4j.ddd.AggregateVersionNotFoundException; import org.fuin.objects4j.common.Contract; import org.fuin.objects4j.common.ExceptionShortIdentifable; +import org.fuin.objects4j.common.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; @@ -129,12 +129,13 @@ public class GlobalExceptionHandler { final HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); - return new ResponseEntity<>(SimpleResult.error(CONSTRAINT_VIOLATION, asString(ex.getConstraintViolations())), headers, HttpStatus.BAD_REQUEST); + return new ResponseEntity<>(SimpleResult.error(CONSTRAINT_VIOLATION, asString(ex.getConstraintViolations())), headers, + HttpStatus.BAD_REQUEST); } - + private static String asString(@Nullable final Set> constraintViolations) { - if (constraintViolations == null || constraintViolations.size() == 0) { + if (constraintViolations == null || constraintViolations.isEmpty()) { return ""; } final List list = new ArrayList<>(); @@ -143,5 +144,5 @@ public class GlobalExceptionHandler { } return list.toString(); } - + }