diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPosition.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPosition.java similarity index 89% rename from quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPosition.java rename to quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPosition.java index 44a6468..f1e52bb 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPosition.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPosition.java @@ -26,8 +26,8 @@ import org.fuin.objects4j.common.Contract; * Stores the next position to read from the projection in the event store. */ @Entity -@Table(name = "QRY_PERSON_PROJECTION_POS") -public class ProjectionPosition { +@Table(name = "QUARKUS_QRY_PROJECTION_POS") +public class QryProjectionPosition { @Id @Column(name = "STREAM_ID", nullable = false, length = 250, updatable = false) @@ -41,7 +41,7 @@ public class ProjectionPosition { /** * JPA constructor. */ - protected ProjectionPosition() { + protected QryProjectionPosition() { super(); } @@ -53,7 +53,7 @@ public class ProjectionPosition { * @param nextPos * Next position from the stream to read. */ - public ProjectionPosition(@NotNull final StreamId streamId, @NotNull final Long nextPos) { + public QryProjectionPosition(@NotNull final StreamId streamId, @NotNull final Long nextPos) { super(); Contract.requireArgNotNull("streamId", streamId); Contract.requireArgNotNull("nextPos", nextPos); @@ -94,7 +94,7 @@ public class ProjectionPosition { @Override public String toString() { - return "QryPersonHandlerPosition [streamId=" + streamId + ", nextPos=" + nextPos + "]"; + return "QryProjectionPosition [streamId=" + streamId + ", nextPos=" + nextPos + "]"; } } diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPositionRepository.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java similarity index 81% rename from quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPositionRepository.java rename to quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java index 474e444..f3cba75 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/ProjectionPositionRepository.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/common/QryProjectionPositionRepository.java @@ -25,7 +25,7 @@ import org.fuin.objects4j.common.Contract; * Repository that contains the position of the stream. */ @ApplicationScoped -public class ProjectionPositionRepository implements ProjectionService { +public class QryProjectionPositionRepository implements ProjectionService { @Inject EntityManager em; @@ -33,7 +33,7 @@ public class ProjectionPositionRepository implements ProjectionService { @Override public void resetProjectionPosition(@NotNull final StreamId streamId) { Contract.requireArgNotNull("streamId", streamId); - final ProjectionPosition pos = em.find(ProjectionPosition.class, streamId.asString()); + final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos != null) { pos.setNextPosition(0L); } @@ -42,7 +42,7 @@ public class ProjectionPositionRepository implements ProjectionService { @Override public Long readProjectionPosition(@NotNull StreamId streamId) { Contract.requireArgNotNull("streamId", streamId); - final ProjectionPosition pos = em.find(ProjectionPosition.class, streamId.asString()); + final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { return 0L; } @@ -53,9 +53,9 @@ public class ProjectionPositionRepository implements ProjectionService { public void updateProjectionPosition(@NotNull StreamId streamId, @NotNull Long nextEventNumber) { Contract.requireArgNotNull("streamId", streamId); Contract.requireArgNotNull("nextEventNumber", nextEventNumber); - final ProjectionPosition pos = em.find(ProjectionPosition.class, streamId.asString()); + final QryProjectionPosition pos = em.find(QryProjectionPosition.class, streamId.asString()); if (pos == null) { - em.persist(new ProjectionPosition(streamId, nextEventNumber)); + em.persist(new QryProjectionPosition(streamId, nextEventNumber)); } else { pos.setNextPosition(nextEventNumber); em.merge(pos); diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEntry.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEntry.java index 503e2ae..4b5d9ec 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEntry.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEntry.java @@ -33,7 +33,7 @@ import io.quarkus.runtime.annotations.RegisterForReflection; * Represents a person that will be stored in the database. */ @Entity -@Table(name = "PERSON_LIST") +@Table(name = "QUARKUS_PERSON_LIST") @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "person") @NamedQuery(name = PersonListEntry.FIND_ALL, query = "SELECT p FROM PersonListEntry p") diff --git a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEventChunkHandler.java b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEventChunkHandler.java index 917dc02..0a88742 100644 --- a/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEventChunkHandler.java +++ b/quarkus/query/src/main/java/org/fuin/cqrs4j/example/quarkus/query/views/personlist/PersonListEventChunkHandler.java @@ -30,7 +30,7 @@ public class PersonListEventChunkHandler { private static final Logger LOG = LoggerFactory.getLogger(PersonListEventChunkHandler.class); /** Unique name of the event store projection that is used. */ - public static final ProjectionStreamId PROJECTION_STREAM_ID = new ProjectionStreamId("qry-person-stream"); + public static final ProjectionStreamId PROJECTION_STREAM_ID = new ProjectionStreamId("quarkus-qry-person-stream"); @Inject EventDispatcher dispatcher; diff --git a/spring-boot/command/pom.xml b/spring-boot/command/pom.xml index 12cac55..26084d1 100644 --- a/spring-boot/command/pom.xml +++ b/spring-boot/command/pom.xml @@ -21,13 +21,25 @@ 1.8 1.8 1.8 - 0.3.1-SNAPSHOT + 0.3.1 + + org.fuin.cqrs4j.example + cqrs4j-example-shared + 0.1.0-SNAPSHOT + + + + org.fuin.cqrs4j.example + cqrs4j-example-aggregates + 0.1.0-SNAPSHOT + + org.fuin.cqrs4j.example.spring cqrs4j-spring-example-shared @@ -47,26 +59,26 @@ org.fuin cqrs-4-java - 0.2.1-SNAPSHOT + 0.2.1 - - org.fuin.esc - esc-spi - ${esc.version} - + + org.fuin.esc + esc-spi + ${esc.version} + - - org.fuin.esc - esc-esjc - ${esc.version} - + + org.fuin.esc + esc-esjc + ${esc.version} + - - org.fuin.esc - esc-esjc - ${esc.version} - + + org.fuin.esc + esc-esjc + ${esc.version} + @@ -128,14 +140,14 @@ - + - + org.springframework.boot spring-boot-maven-plugin - + maven-failsafe-plugin @@ -199,9 +211,9 @@ - + - + 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 3c75f17..b170d14 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,10 +8,11 @@ import javax.json.bind.JsonbBuilder; import javax.json.bind.JsonbConfig; import org.eclipse.yasson.FieldAccessStrategy; -import org.fuin.cqrs4j.example.spring.command.domain.PersonRepository; -import org.fuin.cqrs4j.example.spring.shared.SharedUtils; -import org.fuin.esc.api.EventStore; +import org.fuin.cqrs4j.example.aggregates.PersonRepository; +import org.fuin.cqrs4j.example.shared.SharedUtils; +import org.fuin.cqrs4j.example.spring.shared.Config; import org.fuin.esc.esjc.ESJCEventStore; +import org.fuin.esc.esjc.IESJCEventStore; import org.fuin.esc.spi.EnhancedMimeType; import org.fuin.esc.spi.SerDeserializerRegistry; import org.springframework.boot.SpringApplication; @@ -21,7 +22,8 @@ import org.springframework.web.context.annotation.RequestScope; import com.github.msemys.esjc.EventStoreBuilder; -@SpringBootApplication(scanBasePackages = "org.fuin.cqrs4j.example.spring.command") +@SpringBootApplication(scanBasePackages = { "org.fuin.cqrs4j.example.spring.command.app", + "org.fuin.cqrs4j.example.spring.command.controller", "org.fuin.cqrs4j.example.spring.shared" }) public class CmdApplication { /** @@ -30,49 +32,48 @@ public class CmdApplication { * @return Fully configured instance. */ @Bean - public Jsonb createJsonb() { - final JsonbConfig config = new JsonbConfig() - .withAdapters(SharedUtils.JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); - return jsonb; - } - - /** - * Creates a TCP based event store connection. - * - * @param config Configuration to use. - * - * @return New event store instance. - */ - @Bean(destroyMethod = "shutdown") - public com.github.msemys.esjc.EventStore getESHttpEventStore(final CmdConfig config) { - return EventStoreBuilder.newBuilder().singleNodeAddress(config.getEventStoreHost(), config.getEventStoreTcpPort()) - .executor(Executors.newFixedThreadPool(10)).userCredentials(config.getEventStoreUser(), config.getEventStorePassword()) - .build(); + public Jsonb createJsonb() { + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); + return jsonb; } - - + /** - * Creates an event store connection. + * Creates a TCP based event store connection. * * @param config Configuration to use. * * @return New event store instance. - */ + */ + @Bean(destroyMethod = "shutdown") + public com.github.msemys.esjc.EventStore getESHttpEventStore(final Config config) { + return EventStoreBuilder.newBuilder() + .singleNodeAddress(config.getEventStoreHost(), config.getEventStoreTcpPort()) + .executor(Executors.newFixedThreadPool(10)) + .userCredentials(config.getEventStoreUser(), config.getEventStorePassword()).build(); + } + + /** + * Creates an event store connection. + * + * @param config Configuration to use. + * + * @return New event store instance. + */ @Bean(destroyMethod = "close") - public EventStore getEventStore(final com.github.msemys.esjc.EventStore es) { + public IESJCEventStore getEventStore(final com.github.msemys.esjc.EventStore es) { final SerDeserializerRegistry registry = SharedUtils.createRegistry(); - final EventStore eventstore = new ESJCEventStore(es, registry, registry, - EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))); - eventstore.open(); - return eventstore; + final IESJCEventStore eventstore = new ESJCEventStore(es, registry, registry, + EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))); + eventstore.open(); + return eventstore; + + } - } - /** - * Creates an event sourced repository that can store a person. + * Creates an event sourced repository that can store a person. * * @param eventStore Event store to use. * @@ -80,11 +81,11 @@ public class CmdApplication { */ @Bean @RequestScope - public PersonRepository create(final EventStore eventStore) { - return new PersonRepository(eventStore); - } - - public static void main(String[] args) { + public PersonRepository create(final IESJCEventStore eventStore) { + return new PersonRepository(eventStore); + } + + 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 edb7b08..c7d054d 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 @@ -20,10 +20,10 @@ import javax.validation.Validator; import org.fuin.cqrs4j.CommandExecutionFailedException; import org.fuin.cqrs4j.SimpleResult; -import org.fuin.cqrs4j.example.spring.command.domain.DuplicatePersonNameException; -import org.fuin.cqrs4j.example.spring.command.domain.Person; -import org.fuin.cqrs4j.example.spring.command.domain.PersonRepository; -import org.fuin.cqrs4j.example.spring.shared.CreatePersonCommand; +import org.fuin.cqrs4j.example.aggregates.DuplicatePersonNameException; +import org.fuin.cqrs4j.example.aggregates.Person; +import org.fuin.cqrs4j.example.aggregates.PersonRepository; +import org.fuin.cqrs4j.example.shared.CreatePersonCommand; import org.fuin.ddd4j.ddd.AggregateAlreadyExistsException; import org.fuin.ddd4j.ddd.AggregateDeletedException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/DuplicatePersonNameException.java b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/DuplicatePersonNameException.java deleted file mode 100644 index b63b427..0000000 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/DuplicatePersonNameException.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see - * http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.command.domain; - -import javax.validation.constraints.NotNull; - -import org.fuin.cqrs4j.example.spring.shared.PersonId; -import org.fuin.cqrs4j.example.spring.shared.PersonName; -import org.fuin.objects4j.common.ExceptionShortIdentifable; - -/** - * A name that should be unique does already exist. - */ -public final class DuplicatePersonNameException extends Exception implements ExceptionShortIdentifable { - - private static final long serialVersionUID = 1000L; - - private String sid; - - private PersonId personId; - - private PersonName name; - - /** - * Constructor with mandatory data. - * - * @param personId - * Identifier of the resource that caused the problem. - * @param name - * Name of the resource that caused the problem. - */ - public DuplicatePersonNameException(@NotNull final PersonId personId, @NotNull final PersonName name) { - super("The name '" + name + "' already exists: " + personId.asString()); - this.sid = "DUPLICATE_PERSON_NAME"; - this.personId = personId; - this.name = name; - } - - @Override - public final String getShortId() { - return sid; - } - - /** - * Returns the identifier of the entity that has the name. - * - * @return Identifier. - */ - public final PersonId getPersonId() { - return personId; - } - - /** - * Returns the name that already exists. - * - * @return Name. - */ - public final PersonName getName() { - return name; - } - -} \ No newline at end of file diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/Person.java b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/Person.java deleted file mode 100644 index 786d695..0000000 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/Person.java +++ /dev/null @@ -1,111 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see - * http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.command.domain; - -import java.io.Serializable; - -import javax.validation.constraints.NotNull; - -import org.fuin.cqrs4j.example.spring.shared.PersonCreatedEvent; -import org.fuin.cqrs4j.example.spring.shared.PersonId; -import org.fuin.cqrs4j.example.spring.shared.PersonName; -import org.fuin.ddd4j.ddd.AbstractAggregateRoot; -import org.fuin.ddd4j.ddd.ApplyEvent; -import org.fuin.ddd4j.ddd.EntityType; -import org.fuin.objects4j.common.Contract; - -/** - * A medical practitioner most likely also holder of an accredited academic - * degree. - */ -public class Person extends AbstractAggregateRoot implements Serializable { - - private static final long serialVersionUID = 1000L; - - @NotNull - private PersonId id; - - @NotNull - private PersonName name; - - /** - * Default constructor that is mandatory for aggregate roots. - */ - public Person() { - super(); - } - - /** - * Constructor with all data. - * - * @param id Unique identifier of the person. - * @param name Unique name of the person. - * @param service Service required by the method. - * - * @throws DuplicatePersonNameException The name already exists for another - * person. - */ - public Person(@NotNull final PersonId id, @NotNull final PersonName name, final PersonService service) - throws DuplicatePersonNameException { - super(); - - // VERIFY PRECONDITIONS - Contract.requireArgNotNull("id", id); - Contract.requireArgNotNull("name", name); - - // VERIFY BUSINESS RULES - - // Rule 1: The name of the person must be unique - final PersonId otherId = service.loadPersonIdByName(name); - if (otherId != null) { - throw new DuplicatePersonNameException(otherId, name); - } - - // CREATE EVENT - apply(new PersonCreatedEvent(id, name)); - - } - - @Override - public PersonId getId() { - return id; - } - - @Override - public EntityType getType() { - return PersonId.TYPE; - } - - @ApplyEvent - public void applyEvent(final PersonCreatedEvent event) { - this.id = event.getEntityId(); - this.name = event.getName(); - } - - /** - * Service for the constructor. - */ - public static interface PersonService { - - /** - * Loads the person's identifier for a given name. - * - * @param name Person's name. - * - * @return Office identifier or {@literal null} if not found. - */ - public PersonId loadPersonIdByName(@NotNull PersonName name); - - } - -} diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/PersonRepository.java b/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/PersonRepository.java deleted file mode 100644 index bb8bca6..0000000 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/domain/PersonRepository.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.fuin.cqrs4j.example.spring.command.domain; - -import javax.annotation.concurrent.NotThreadSafe; -import javax.validation.constraints.NotNull; - -import org.fuin.cqrs4j.example.spring.shared.PersonId; -import org.fuin.ddd4j.ddd.EntityType; -import org.fuin.ddd4j.esrepo.EventStoreRepository; -import org.fuin.esc.api.EventStore; - -/** - * Event sourced repository for storing a {@link Person} aggregate. - */ -@NotThreadSafe -public class PersonRepository extends EventStoreRepository { - - /** - * Constructor all mandatory data. - * - * @param eventStore - * Event store. - */ - public PersonRepository(final EventStore eventStore) { - super(eventStore); - } - - @Override - @NotNull - public Class getAggregateClass() { - return Person.class; - } - - @Override - @NotNull - public EntityType getAggregateType() { - return PersonId.TYPE; - } - - @Override - @NotNull - public Person create() { - return new Person(); - } - - @Override - @NotNull - public String getIdParamName() { - return "personId"; - } - -} 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 c247a09..0ae8549 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 @@ -15,11 +15,11 @@ import javax.json.bind.Jsonb; import org.fuin.cqrs4j.ResultType; import org.fuin.cqrs4j.SimpleResult; +import org.fuin.cqrs4j.example.shared.CreatePersonCommand; +import org.fuin.cqrs4j.example.shared.PersonCreatedEvent; +import org.fuin.cqrs4j.example.shared.PersonId; +import org.fuin.cqrs4j.example.shared.PersonName; import org.fuin.cqrs4j.example.spring.command.app.CmdApplication; -import org.fuin.cqrs4j.example.spring.shared.CreatePersonCommand; -import org.fuin.cqrs4j.example.spring.shared.PersonCreatedEvent; -import org.fuin.cqrs4j.example.spring.shared.PersonId; -import org.fuin.cqrs4j.example.spring.shared.PersonName; import org.fuin.esc.api.CommonEvent; import org.fuin.esc.api.EventStore; import org.fuin.esc.api.SimpleStreamId; diff --git a/spring-boot/query/pom.xml b/spring-boot/query/pom.xml index 79c1dde..f4e5819 100644 --- a/spring-boot/query/pom.xml +++ b/spring-boot/query/pom.xml @@ -21,13 +21,19 @@ 1.8 1.8 1.8 - 0.3.1-SNAPSHOT + 0.3.1 + + org.fuin.cqrs4j.example + cqrs4j-example-shared + 0.1.0-SNAPSHOT + + org.fuin.cqrs4j.example.spring cqrs4j-spring-example-shared @@ -57,7 +63,7 @@ org.fuin cqrs-4-java - 0.2.1-SNAPSHOT + 0.2.1 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 7a30ff6..dd5fafb 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 @@ -1,24 +1,7 @@ package org.fuin.cqrs4j.example.spring.query.app; -import java.net.MalformedURLException; -import java.net.URL; import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import javax.json.bind.Jsonb; -import javax.json.bind.JsonbBuilder; -import javax.json.bind.JsonbConfig; - -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.eclipse.yasson.FieldAccessStrategy; -import org.fuin.cqrs4j.example.spring.shared.SharedUtils; -import org.fuin.esc.eshttp.ESEnvelopeType; -import org.fuin.esc.eshttp.ESHttpEventStore; -import org.fuin.esc.eshttp.IESHttpEventStore; -import org.fuin.esc.spi.SerDeserializerRegistry; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; @@ -29,54 +12,16 @@ 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.domain", - "org.fuin.cqrs4j.example.spring.query.handler" }) -@EnableJpaRepositories("org.fuin.cqrs4j.example.spring.query.domain") -@EntityScan({ "org.fuin.cqrs4j.example.spring.query.domain", "org.fuin.cqrs4j.example.spring.query.handler" }) + "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" }) @EnableScheduling @EnableAsync public class QryApplication { - /** - * Creates a Jsonb instance. - * - * @return Fully configured instance. - */ - @Bean - public Jsonb createJsonb() { - final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); - return jsonb; - } - - /** - * Creates a HTTP based event store connection. - * - * @param config Configuration to use. - * - * @return New event store instance. - */ - @Bean(destroyMethod = "close") - public IESHttpEventStore getESHttpEventStore(final QryConfig config) { - final String url = config.getEventStoreProtocol() + "://" + config.getEventStoreHost() + ":" - + config.getEventStoreHttpPort(); - try { - final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(config.getEventStoreUser(), - config.getEventStorePassword()); - credentialsProvider.setCredentials(AuthScope.ANY, credentials); - final SerDeserializerRegistry registry = SharedUtils.createRegistry(); - final ESHttpEventStore es = new ESHttpEventStore(Executors.defaultThreadFactory(), new URL(url), - ESEnvelopeType.JSON, registry, registry, credentialsProvider); - es.open(); - return es; - } catch (final MalformedURLException ex) { - throw new RuntimeException("Failed to create URL: " + url, ex); - } - } - - @Bean("personProjectorExecutor") + @Bean("projectorExecutor") public Executor taskExecutor() { final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(1); diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryConfig.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryConfig.java deleted file mode 100644 index bc48bea..0000000 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/app/QryConfig.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.fuin.cqrs4j.example.spring.query.app; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -public class QryConfig { - - private static final String EVENT_STORE_PROTOCOL = "http"; - - private static final String EVENT_STORE_HOST = "localhost"; - - private static final int EVENT_STORE_HTTP_PORT = 2113; - - private static final int EVENT_STORE_TCP_PORT = 1113; - - private static final String EVENT_STORE_USER = "admin"; - - private static final String EVENT_STORE_PASSWORD = "changeit"; - - @Value("${EVENT_STORE_PROTOCOL:http}") - private String eventStoreProtocol; - - @Value("${EVENT_STORE_HOST:localhost}") - private String eventStoreHost; - - @Value("${EVENT_STORE_HTTP_PORT:2113}") - private int eventStoreHttpPort; - - @Value("${EVENT_STORE_TCP_PORT:1113}") - private int eventStoreTcpPort; - - @Value("${EVENT_STORE_USER:admin}") - private String eventStoreUser; - - @Value("${EVENT_STORE_PASSWORD:changeit}") - private String eventStorePassword; - - /** - * Constructor using default values internally. - */ - public QryConfig() { - 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 QryConfig(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 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 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 password of the event store. - * - * @return Password. - */ - public String getEventStorePassword() { - return eventStorePassword; - } - - @Override - public String toString() { - return "QryConfig [eventStoreProtocol=" + eventStoreProtocol + ", eventStoreHost=" + eventStoreHost - + ", eventStoreHttpPort=" + eventStoreHttpPort + ", eventStoreTcpPort=" + eventStoreTcpPort - + ", eventStoreUser=" + eventStoreUser + "]"; - } - -} diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/GlobalExceptionHandler.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/GlobalExceptionHandler.java deleted file mode 100644 index 922450e..0000000 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/GlobalExceptionHandler.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see - * http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.query.controller; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import javax.annotation.Nullable; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; - -import org.fuin.cqrs4j.SimpleResult; -import org.fuin.objects4j.common.Contract; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -/** - * Maps the exceptions into a HTTP status. - */ -@ControllerAdvice -public class GlobalExceptionHandler { - - private static final String CONSTRAINT_VIOLATION = "CONSTRAINT_VIOLATION"; - - private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class); - - @ExceptionHandler(value = PersonNotFoundException.class) - public ResponseEntity exception(final PersonNotFoundException ex) { - - LOG.info("{} {}", ex.getShortId(), ex.getMessage()); - - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - return new ResponseEntity<>(SimpleResult.error(ex.getShortId(), ex.getMessage()), headers, - HttpStatus.NOT_FOUND); - - } - - @ExceptionHandler(value = ConstraintViolationException.class) - public ResponseEntity exception(final ConstraintViolationException ex) { - - LOG.info("{} {}", CONSTRAINT_VIOLATION, "ConstraintViolationException"); - - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - 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) { - return ""; - } - final List list = new ArrayList<>(); - for (final ConstraintViolation constraintViolation : constraintViolations) { - list.add(Contract.asString(constraintViolation)); - } - return list.toString(); - } - -} 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 8fd42bf..ab5ba7c 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 @@ -17,8 +17,9 @@ import java.util.UUID; import javax.persistence.EntityManager; -import org.fuin.cqrs4j.example.spring.query.domain.QryPerson; -import org.fuin.cqrs4j.example.spring.shared.PersonId; +import org.fuin.cqrs4j.example.shared.PersonId; +import org.fuin.cqrs4j.example.spring.query.views.personlist.PersonListEntry; +import org.fuin.ddd4j.ddd.AggregateNotFoundException; import org.fuin.objects4j.vo.UUIDStr; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,8 +48,8 @@ public class PersonController { * @return the list */ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - public List getAllPersons() { - final List persons = em.createNamedQuery(QryPerson.FIND_ALL, QryPerson.class).getResultList(); + public List getAllPersons() { + final List persons = em.createNamedQuery(PersonListEntry.FIND_ALL, PersonListEntry.class).getResultList(); LOG.info("getAllPersons() = {}", persons.size()); return persons; } @@ -60,16 +61,16 @@ public class PersonController { * * @return Person from database. * - * @throws PersonNotFoundException A person with the given identifier is + * @throws AggregateNotFoundException A person with the given identifier is * unknown. */ @GetMapping(path = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity getPersonsById(@PathVariable(value = "id") @UUIDStr String personId) - throws PersonNotFoundException { + public ResponseEntity getPersonsById(@PathVariable(value = "id") @UUIDStr String personId) + throws AggregateNotFoundException { - final QryPerson person = em.find(QryPerson.class, personId); + final PersonListEntry person = em.find(PersonListEntry.class, personId); if (person == null) { - throw new PersonNotFoundException(new PersonId(UUID.fromString(personId))); + throw new AggregateNotFoundException(PersonId.TYPE, new PersonId(UUID.fromString(personId))); } LOG.info("getPersonsById({}) = {}", personId, person); return ResponseEntity.ok().body(person); diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonNotFoundException.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonNotFoundException.java deleted file mode 100644 index ece0973..0000000 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/controller/PersonNotFoundException.java +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see - * http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.query.controller; - -import javax.validation.constraints.NotNull; - -import org.fuin.cqrs4j.example.spring.shared.PersonId; -import org.fuin.objects4j.common.ExceptionShortIdentifable; - -/** - * A person with the given identifier is unknown. - */ -public final class PersonNotFoundException extends Exception implements ExceptionShortIdentifable { - - private static final long serialVersionUID = 1000L; - - private String sid; - - private PersonId personId; - - /** - * Constructor with mandatory data. - * - * @param personId - * Identifier of the resource that caused the problem. - */ - public PersonNotFoundException(@NotNull final PersonId personId) { - super("Person not found: " + personId.asString()); - this.sid = "PERSON_NOT_FOUND"; - this.personId = personId; - } - - @Override - public final String getShortId() { - return sid; - } - - /** - * Returns the identifier of the entity that has the name. - * - * @return Identifier. - */ - public final PersonId getPersonId() { - return personId; - } - -} \ No newline at end of file diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionPosition.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionPosition.java similarity index 95% rename from spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionPosition.java rename to spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionPosition.java index 43bb31f..298e5e2 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionPosition.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionPosition.java @@ -1,4 +1,4 @@ -package org.fuin.cqrs4j.example.spring.query.handler; +package org.fuin.cqrs4j.example.spring.query.views.common; import javax.persistence.Column; import javax.persistence.Entity; @@ -14,7 +14,7 @@ import org.fuin.objects4j.common.Contract; * Stores the next position to read from a projection in the event store. */ @Entity -@Table(name = "QRY_PROJECTION_POS") +@Table(name = "SPRING_QRY_PROJECTION_POS") public class QryProjectionPosition { @Id diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionService.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java similarity index 96% rename from spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionService.java rename to spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java index c40efb7..7fa2528 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/QryProjectionService.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/common/QryProjectionService.java @@ -1,4 +1,4 @@ -package org.fuin.cqrs4j.example.spring.query.handler; +package org.fuin.cqrs4j.example.spring.query.views.common; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; 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 new file mode 100644 index 0000000..e0e3fbb --- /dev/null +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/package-info.java @@ -0,0 +1,18 @@ +/** + * Copyright (C) 2015 Michael Schnell. All rights reserved. http://www.fuin.org/ + * + * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see + * http://www.gnu.org/licenses/. + */ +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. + */ diff --git a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/PersonCreatedEventHandler.java b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java similarity index 69% rename from spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/PersonCreatedEventHandler.java rename to spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java index d718d18..5c0c5fb 100644 --- a/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/handler/PersonCreatedEventHandler.java +++ b/spring-boot/query/src/main/java/org/fuin/cqrs4j/example/spring/query/views/personlist/PersonCreatedEventHandler.java @@ -1,11 +1,10 @@ -package org.fuin.cqrs4j.example.spring.query.handler; +package org.fuin.cqrs4j.example.spring.query.views.personlist; import javax.persistence.EntityManager; import org.fuin.cqrs4j.EventHandler; -import org.fuin.cqrs4j.example.spring.query.domain.QryPerson; -import org.fuin.cqrs4j.example.spring.shared.PersonCreatedEvent; -import org.fuin.cqrs4j.example.spring.shared.PersonId; +import org.fuin.cqrs4j.example.shared.PersonCreatedEvent; +import org.fuin.cqrs4j.example.shared.PersonId; import org.fuin.ddd4j.ddd.EventType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,8 +31,8 @@ public class PersonCreatedEventHandler implements EventHandler 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.0.RELEASE + + + org.fuin.cqrs4j.example.spring cqrs4j-spring-example-shared 0.1.0-SNAPSHOT @@ -15,29 +22,45 @@ 1.8 1.8 1.8 - 0.3.1-SNAPSHOT + 0.3.1 + + org.fuin.cqrs4j.example + cqrs4j-example-shared + 0.1.0-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.boot + spring-boot-starter-web + + org.fuin ddd-4-java - 0.2.1-SNAPSHOT + 0.2.1 org.fuin cqrs-4-java - 0.2.1-SNAPSHOT + 0.2.1 org.fuin objects4j - 0.6.9-SNAPSHOT + 0.6.9 @@ -52,26 +75,20 @@ ${esc.version} + + org.fuin.esc + esc-eshttp + ${esc.version} + + org.slf4j slf4j-api - 1.7.25 org.hibernate.validator hibernate-validator - 6.0.10.Final - - - jaxb-impl - com.sun.xml.bind - - - jaxb-api - javax.xml.bind - - @@ -89,7 +106,6 @@ jakarta.persistence jakarta.persistence-api - 2.2.3 @@ -97,21 +113,19 @@ junit junit - 4.12 test org.assertj assertj-core - 3.10.0 test org.fuin units4j - 0.8.3 + 0.8.4 test 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 new file mode 100644 index 0000000..7f081da --- /dev/null +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/BeanFactory.java @@ -0,0 +1,106 @@ +package org.fuin.cqrs4j.example.spring.shared; + +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import javax.json.bind.Jsonb; +import javax.json.bind.JsonbBuilder; +import javax.json.bind.JsonbConfig; + +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.eclipse.yasson.FieldAccessStrategy; +import org.fuin.cqrs4j.example.shared.SharedUtils; +import org.fuin.esc.eshttp.ESEnvelopeType; +import org.fuin.esc.eshttp.ESHttpEventStore; +import org.fuin.esc.eshttp.IESHttpEventStore; +import org.fuin.esc.esjc.ESJCEventStore; +import org.fuin.esc.esjc.IESJCEventStore; +import org.fuin.esc.spi.EnhancedMimeType; +import org.fuin.esc.spi.SerDeserializerRegistry; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import com.github.msemys.esjc.EventStoreBuilder; + +@Component +public class BeanFactory { + + /** + * Creates a Jsonb instance. + * + * @return Fully configured instance. + */ + @Bean + public Jsonb createJsonb() { + final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) + .withPropertyVisibilityStrategy(new FieldAccessStrategy()); + final Jsonb jsonb = JsonbBuilder.create(config); + return jsonb; + } + + /** + * Creates a TCP based event store connection. + * + * @param config Configuration to use. + * + * @return New event store instance. + */ + @Bean(destroyMethod = "shutdown") + public com.github.msemys.esjc.EventStore getEventStore(final Config config) { + return EventStoreBuilder.newBuilder() + .singleNodeAddress(config.getEventStoreHost(), config.getEventStoreTcpPort()) + .executor(Executors.newFixedThreadPool(10)) + .userCredentials(config.getEventStoreUser(), config.getEventStorePassword()).build(); + } + + /** + * Creates an event store connection. + * + * @param config Configuration to use. + * + * @return New event store instance. + */ + @Bean(destroyMethod = "close") + public IESJCEventStore getESJCEventStore(final com.github.msemys.esjc.EventStore es) { + + final SerDeserializerRegistry registry = SharedUtils.createRegistry(); + final IESJCEventStore eventstore = new ESJCEventStore(es, registry, registry, + EnhancedMimeType.create("application", "json", Charset.forName("utf-8"))); + eventstore.open(); + return eventstore; + + } + + + /** + * Creates a HTTP based event store connection. + * + * @param config Configuration to use. + * + * @return New event store instance. + */ + @Bean(destroyMethod = "close") + public IESHttpEventStore getESHttpEventStore(final Config config) { + final String url = config.getEventStoreProtocol() + "://" + config.getEventStoreHost() + ":" + + config.getEventStoreHttpPort(); + try { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(config.getEventStoreUser(), + config.getEventStorePassword()); + credentialsProvider.setCredentials(AuthScope.ANY, credentials); + final SerDeserializerRegistry registry = SharedUtils.createRegistry(); + final ESHttpEventStore es = new ESHttpEventStore(Executors.defaultThreadFactory(), new URL(url), + ESEnvelopeType.JSON, registry, registry, credentialsProvider); + es.open(); + return es; + } catch (final MalformedURLException ex) { + throw new RuntimeException("Failed to create URL: " + url, ex); + } + } + +} diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdConfig.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java similarity index 93% rename from spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdConfig.java rename to spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java index ce8e41a..1c8254f 100644 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/app/CmdConfig.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/Config.java @@ -1,10 +1,10 @@ -package org.fuin.cqrs4j.example.spring.command.app; +package org.fuin.cqrs4j.example.spring.shared; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component -public class CmdConfig { +public class Config { private static final String EVENT_STORE_PROTOCOL = "http"; @@ -39,7 +39,7 @@ public class CmdConfig { /** * Constructor using default values internally. */ - public CmdConfig() { + public Config() { super(); this.eventStoreProtocol = EVENT_STORE_PROTOCOL; this.eventStoreHost = EVENT_STORE_HOST; @@ -59,7 +59,7 @@ public class CmdConfig { * @param eventStoreUser User. * @param eventStorePassword Password. */ - public CmdConfig(final String eventStoreProtocol, final String eventStoreHost, final int eventStoreHttpPort, + public Config(final String eventStoreProtocol, final String eventStoreHost, final int eventStoreHttpPort, final int eventStoreTcpPort, final String eventStoreUser, final String eventStorePassword) { super(); this.eventStoreProtocol = eventStoreProtocol; diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java deleted file mode 100644 index 9bfb9b6..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommand.java +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import javax.annotation.concurrent.Immutable; -import javax.json.bind.annotation.JsonbProperty; -import javax.validation.constraints.NotNull; - -import org.fuin.cqrs4j.AbstractAggregateCommand; -import org.fuin.ddd4j.ddd.DomainEventExpectedEntityIdPath; -import org.fuin.ddd4j.ddd.EventType; -import org.fuin.esc.spi.SerializedDataType; -import org.fuin.objects4j.common.Contract; - -/** - * A new person should be created in the system. - */ -@Immutable -@DomainEventExpectedEntityIdPath(PersonId.class) -public final class CreatePersonCommand extends AbstractAggregateCommand { - - private static final long serialVersionUID = 1000L; - - /** Never changing unique event type name. */ - public static final EventType TYPE = new EventType("CreatePersonCommand"); - - /** Unique name used for marshalling/unmarshalling the event. */ - public static final SerializedDataType SER_TYPE = new SerializedDataType(CreatePersonCommand.TYPE.asBaseType()); - - @NotNull - @JsonbProperty("name") - private PersonName name; - - /** - * Protected default constructor for deserialization. - */ - protected CreatePersonCommand() { - super(); - } - - /** - * A new person was created in the system. - * - * @param id Identifies uniquely a person. - * @param name Name of a person. - */ - public CreatePersonCommand(@NotNull final PersonId id, @NotNull final PersonName name) { - super(id, null); - Contract.requireArgNotNull("name", name); - this.name = name; - } - - @Override - public final EventType getEventType() { - return CreatePersonCommand.TYPE; - } - - /** - * Returns: Name of a person. - * - * @return Current value. - */ - @NotNull - public final PersonName getName() { - return name; - } - - @Override - public final String toString() { - return "Create person '" + name + "' with identifier '" + getAggregateRootId() + "'"; - } - -} \ No newline at end of file diff --git a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/GlobalExceptionHandler.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java similarity index 91% rename from spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/GlobalExceptionHandler.java rename to spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java index 0e0de6b..69529cc 100644 --- a/spring-boot/command/src/main/java/org/fuin/cqrs4j/example/spring/command/controller/GlobalExceptionHandler.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/GlobalExceptionHandler.java @@ -10,7 +10,7 @@ * You should have received a copy of the GNU Lesser General Public License along with this library. If not, see * http://www.gnu.org/licenses/. */ -package org.fuin.cqrs4j.example.spring.command.controller; +package org.fuin.cqrs4j.example.spring.shared; import java.util.ArrayList; import java.util.List; @@ -22,7 +22,6 @@ import javax.validation.ConstraintViolationException; import org.fuin.cqrs4j.CommandExecutionFailedException; import org.fuin.cqrs4j.SimpleResult; -import org.fuin.cqrs4j.example.spring.command.domain.DuplicatePersonNameException; import org.fuin.ddd4j.ddd.AggregateAlreadyExistsException; import org.fuin.ddd4j.ddd.AggregateDeletedException; import org.fuin.ddd4j.ddd.AggregateNotFoundException; @@ -123,18 +122,6 @@ public class GlobalExceptionHandler { } - @ExceptionHandler(value = DuplicatePersonNameException.class) - public ResponseEntity exception(final DuplicatePersonNameException ex) { - - LOG.info("{} {}", ex.getShortId(), ex.getMessage()); - - final HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - return new ResponseEntity<>(SimpleResult.error(ex.getShortId(), ex.getMessage()), headers, HttpStatus.CONFLICT); - - } - - @ExceptionHandler(value = ConstraintViolationException.class) public ResponseEntity exception(final ConstraintViolationException ex) { diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEvent.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEvent.java deleted file mode 100644 index 125b461..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEvent.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import javax.annotation.concurrent.Immutable; -import javax.json.bind.annotation.JsonbProperty; -import javax.validation.constraints.NotNull; - -import org.fuin.ddd4j.ddd.AbstractDomainEvent; -import org.fuin.ddd4j.ddd.EntityIdPath; -import org.fuin.ddd4j.ddd.EventType; -import org.fuin.esc.spi.SerializedDataType; -import org.fuin.objects4j.common.Contract; - -/** - * A new person was created in the system. - */ -@Immutable -public final class PersonCreatedEvent extends AbstractDomainEvent { - - private static final long serialVersionUID = 1000L; - - /** Never changing unique event type name. */ - public static final EventType TYPE = new EventType("PersonCreatedEvent"); - - /** Unique name used for marshalling/unmarshalling the event. */ - public static final SerializedDataType SER_TYPE = new SerializedDataType(PersonCreatedEvent.TYPE.asBaseType()); - - @NotNull - @JsonbProperty("name") - private PersonName name; - - /** - * Protected default constructor for deserialization. - */ - protected PersonCreatedEvent() { - super(); - } - - /** - * A new person was created in the system. - * - * @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)); - Contract.requireArgNotNull("name", name); - this.name = name; - } - - @Override - public final EventType getEventType() { - return PersonCreatedEvent.TYPE; - } - - /** - * Returns: Name of a person. - * - * @return Current value. - */ - @NotNull - public final PersonName getName() { - return name; - } - - @Override - public final String toString() { - return "Person '" + name + "' was created"; - } - -} diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonId.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonId.java deleted file mode 100644 index b5e8917..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonId.java +++ /dev/null @@ -1,148 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import java.util.UUID; - -import javax.annotation.concurrent.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.ui.Label; -import org.fuin.objects4j.ui.ShortLabel; -import org.fuin.objects4j.ui.Tooltip; -import org.fuin.objects4j.vo.ValueObjectConverter; - -/** - * Identifies uniquely a person. - */ -@ShortLabel(bundle = "ddd-cqrs-4-java-example", key = "PersonId.slabel", value = "PID") -@Label(bundle = "ddd-cqrs-4-java-example", key = "PersonId.label", value = "Person's ID") -@Tooltip(bundle = "ddd-cqrs-4-java-example", key = "PersonId.tooltip", value = "Unique identifier of a person") -@Immutable -public final class PersonId extends AggregateRootUuid { - - private static final long serialVersionUID = 1000L; - - /** Unique name of the aggregate this identifier refers to. */ - public static final EntityType TYPE = new StringBasedEntityType("PERSON"); - - /** - * Default constructor. - */ - protected PersonId() { - super(PersonId.TYPE); - } - - /** - * Constructor with all data. - * - * @param value - * Persistent value. - */ - public PersonId(@NotNull final UUID value) { - super(PersonId.TYPE, value); - } - - /** - * Verifies if the given string can be converted into a Person ID. - * - * @param value - * String with valid UUID string. A null value ris also valid. - * - * @return {@literal true} if the string is a valid UUID. - */ - public static boolean isValid(final String value) { - if (value == null) { - return true; - } - return AggregateRootUuid.isValid(value); - } - - /** - * Parses a given string and returns a new instance of PersonId. - * - * @param value - * String with valid UUID to convert. A null value returns null. - * - * @return Converted value. - */ - public static PersonId valueOf(final String value) { - if (value == null) { - return null; - } - AggregateRootUuid.requireArgValid("value", value); - return new PersonId(UUID.fromString(value)); - } - - /** - * Converts the value object from/to UUID. - */ - public static final class Converter implements ValueObjectConverter, JsonbAdapter { - - // Attribute Converter - - @Override - public final Class getBaseTypeClass() { - return UUID.class; - } - - @Override - public final Class getValueObjectClass() { - return PersonId.class; - } - - @Override - public boolean isValid(final UUID value) { - return true; - } - - @Override - public final PersonId toVO(final UUID value) { - if (value == null) { - return null; - } - return new PersonId(value); - } - - @Override - public final UUID fromVO(final PersonId value) { - if (value == null) { - return null; - } - return value.asBaseType(); - } - - // JSONB Adapter - - @Override - public final UUID adaptToJson(final PersonId obj) throws Exception { - return fromVO(obj); - } - - @Override - public final PersonId adaptFromJson(final UUID value) throws Exception { - return toVO(value); - } - - } - -} \ No newline at end of file diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonName.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonName.java deleted file mode 100644 index b2e6e6f..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/PersonName.java +++ /dev/null @@ -1,216 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import javax.annotation.concurrent.Immutable; -import javax.json.bind.adapter.JsonbAdapter; -import javax.validation.Constraint; -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; -import javax.validation.Payload; -import javax.validation.constraints.NotNull; - -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.objects4j.ui.Label; -import org.fuin.objects4j.ui.ShortLabel; -import org.fuin.objects4j.ui.Tooltip; -import org.fuin.objects4j.vo.AbstractStringValueObject; -import org.fuin.objects4j.vo.ValueObjectConverter; - -/** - * Name of a person. - */ -@ShortLabel(bundle = "ddd-cqrs-4-java-example", key = "PersonName.slabel", value = "PNAME") -@Label(bundle = "ddd-cqrs-4-java-example", key = "PersonName.label", value = "Person's name") -@Tooltip(bundle = "ddd-cqrs-4-java-example", key = "PersonName.tooltip", value = "Name of a person") -@Immutable -public final class PersonName extends AbstractStringValueObject { - - private static final long serialVersionUID = 1000L; - - /** Max length of a person's name. */ - public static final int MAX_LENGTH = 100; - - @NotNull - @PersonNameStr - private String value; - - /** - * Protected default constructor for deserialization. - */ - protected PersonName() { - super(); - } - - /** - * Constructor with mandatory data. - * - * @param value Value. - */ - public PersonName(final String value) { - super(); - PersonName.requireArgValid("value", value); - this.value = value; - } - - @Override - public final String asBaseType() { - return value; - } - - @Override - public final String toString() { - return value; - } - - /** - * Verifies that a given string can be converted into the type. - * - * @param value Value to validate. - * - * @return Returns true if it's a valid type else - * false. - */ - public static boolean isValid(final String value) { - if (value == null) { - return true; - } - if (value.length() == 0) { - return false; - } - final String trimmed = value.trim(); - if (trimmed.length() > PersonName.MAX_LENGTH) { - return false; - } - return true; - } - - /** - * 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. - * - * @throws ConstraintViolationException The value was not valid. - */ - 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 + "'"); - } - - } - - /** - * Ensures that the string can be converted into the type. - */ - @Target({ ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE }) - @Retention(RetentionPolicy.RUNTIME) - @Constraint(validatedBy = { Validator.class }) - @Documented - public static @interface PersonNameStr { - - String message() - - default "{org.fuin.cqrs4j.example.javasecdi.PersonName.message}"; - - Class[] groups() default {}; - - Class[] payload() default {}; - - } - - /** - * Validates if a string is compliant with the type. - */ - public static final class Validator implements ConstraintValidator { - - @Override - public final void initialize(final PersonNameStr annotation) { - // Not used - } - - @Override - public final boolean isValid(final String value, final ConstraintValidatorContext context) { - return PersonName.isValid(value); - } - - } - - /** - * Converts the value object from/to string. - */ - public static final class Converter - implements ValueObjectConverter, JsonbAdapter { - - // Attribute Converter - - @Override - public final Class getBaseTypeClass() { - return String.class; - } - - @Override - public final Class getValueObjectClass() { - return PersonName.class; - } - - @Override - public boolean isValid(final String value) { - return PersonName.isValid(value); - } - - @Override - public final PersonName toVO(final String value) { - if (value == null) { - return null; - } - return new PersonName(value); - } - - @Override - public final String fromVO(final PersonName value) { - if (value == null) { - return null; - } - return value.asBaseType(); - } - - // JSONB Adapter - - @Override - public final String adaptToJson(final PersonName obj) throws Exception { - return fromVO(obj); - } - - @Override - public final PersonName adaptFromJson(final String str) throws Exception { - return toVO(str); - } - - } - -} diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedEntityIdFactory.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedEntityIdFactory.java deleted file mode 100644 index 32d1d20..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedEntityIdFactory.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Function; - -import org.fuin.ddd4j.ddd.EntityId; -import org.fuin.ddd4j.ddd.EntityIdFactory; - -/** - * Factory that creates entity identifier instances based on the type. - */ -public final class SharedEntityIdFactory implements EntityIdFactory { - - private Map> valueOfMap; - - 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); - } - - @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 isValid(String type, String id) { - final Function func = isValidMap.get(type); - if (func == null) { - return false; - } - return func.apply(id); - } - -} diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedUtils.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedUtils.java deleted file mode 100644 index f40b0e9..0000000 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/SharedUtils.java +++ /dev/null @@ -1,189 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import java.nio.charset.Charset; - -import javax.json.bind.adapter.JsonbAdapter; - -import org.eclipse.yasson.FieldAccessStrategy; -import org.fuin.ddd4j.ddd.EntityIdPathConverter; -import org.fuin.ddd4j.ddd.EventIdConverter; -import org.fuin.esc.spi.Base64Data; -import org.fuin.esc.spi.EscEvent; -import org.fuin.esc.spi.EscEvents; -import org.fuin.esc.spi.EscMeta; -import org.fuin.esc.spi.EscSpiUtils; -import org.fuin.esc.spi.JsonbDeSerializer; -import org.fuin.esc.spi.SerDeserializerRegistry; -import org.fuin.esc.spi.SerializedDataType; -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. - */ -public final class SharedUtils { - - /** All types that will be written into and read from the event store. */ - private static 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(), - 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. - * - * @return New instance. - */ - public static SerializedDataTypeRegistry createTypeRegistry() { - - // Contains all types for usage with JSON-B - final SimpleSerializedDataTypeRegistry typeRegistry = new SimpleSerializedDataTypeRegistry(); - - // Base types always needed - typeRegistry.add(EscEvent.SER_TYPE, EscEvent.class); - typeRegistry.add(EscEvents.SER_TYPE, EscEvents.class); - typeRegistry.add(EscMeta.SER_TYPE, EscMeta.class); - typeRegistry.add(Base64Data.SER_TYPE, Base64Data.class); - - // User defined types - for (final TypeClass tc : USER_DEFINED_TYPES) { - typeRegistry.add(tc.getType(), tc.getClasz()); - } - return typeRegistry; - - } - - /** - * 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. - * - * @return New instance. - */ - public static SerDeserializerRegistry createSerDeserializerRegistry(final SerializedDataTypeRegistry typeRegistry, - final JsonbDeSerializer jsonbDeSer) { - - 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); - - // User defined types - for (final TypeClass tc : USER_DEFINED_TYPES) { - registry.add(tc.getType(), "application/json", jsonbDeSer); - } - jsonbDeSer.init(typeRegistry, registry, registry); - - return registry; - } - - /** - * Creates a registry that connects the type with the appropriate serializer and - * de-serializer. - * - * @return New instance. - */ - public static SerDeserializerRegistry createRegistry() { - - // Knows about all types for usage with JSON-B - final SerializedDataTypeRegistry typeRegistry = SharedUtils.createTypeRegistry(); - - // Does the actual marshalling/unmarshalling - 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; - - } - - /** - * Creates an instance of the JSON-B serializer/deserializer. - * - * @return New instance that is fully initialized with al necessary settings. - */ - 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(); - - } - - /** - * Helper class for type/class combination. - */ - private static final class TypeClass { - - private final SerializedDataType type; - - private final Class clasz; - - /** - * Constructor with all data. - * - * @param type Type. - * @param clasz Class. - */ - public TypeClass(final SerializedDataType type, final Class clasz) { - super(); - this.type = type; - this.clasz = clasz; - } - - /** - * Returns the type. - * - * @return Type. - */ - public SerializedDataType getType() { - return type; - } - - /** - * Returns the class. - * - * @return Class. - */ - public Class getClasz() { - return clasz; - } - - } - -} \ No newline at end of file diff --git a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/package-info.java b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/package-info.java index e0fe386..635443f 100644 --- a/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/package-info.java +++ b/spring-boot/shared/src/main/java/org/fuin/cqrs4j/example/spring/shared/package-info.java @@ -13,5 +13,5 @@ package org.fuin.cqrs4j.example.spring.shared; /** - * Domain specific code to be shared between all modules. + * Spring Boot specific code to be shared between all modules. */ diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java deleted file mode 100644 index 1d4ee4b..0000000 --- a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/CreatePersonCommandTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.time.ZonedDateTime; -import java.util.UUID; - -import javax.json.bind.Jsonb; -import javax.json.bind.JsonbBuilder; -import javax.json.bind.JsonbConfig; - -import org.apache.commons.io.IOUtils; -import org.eclipse.yasson.FieldAccessStrategy; -import org.fuin.utils4j.Utils4J; -import org.junit.Test; - -// CHECKSTYLE:OFF -public final class CreatePersonCommandTest { - - private static final String PERSON_UUID = "84565d62-115e-4502-b7c9-38ad69c64b05"; - - - @Test - public final void testSerializeDeserialize() { - - // PREPARE - final CreatePersonCommand original = createTestee(); - - // 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()); - - } - - @Test - public final void testMarshalUnmarshalJson() { - - // PREPARE - final CreatePersonCommand original = createTestee(); - - 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); - - // VERIFY - assertThat(copy).isEqualTo(original); - assertThat(copy.getAggregateRootId()).isEqualTo(original.getAggregateRootId()); - assertThat(copy.getName()).isEqualTo(original.getName()); - - } - - @Test - public final void testUnmarshalJsonFromFile() throws IOException { - - // 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); - - - // TEST - final CreatePersonCommand copy = jsonb.fromJson(json, CreatePersonCommand.class); - - // VERIFY - assertThat(copy.getEventId().asBaseType()).isEqualTo(UUID.fromString("109a77b2-1de2-46fc-aee1-97fa7740a552")); - assertThat(copy.getTimestamp()).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); - } - -} -// CHECKSTYLE:ON diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java deleted file mode 100644 index 6244547..0000000 --- a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonCreatedEventTest.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.fuin.utils4j.Utils4J.deserialize; -import static org.fuin.utils4j.Utils4J.serialize; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.UUID; - -import javax.json.bind.Jsonb; -import javax.json.bind.JsonbBuilder; -import javax.json.bind.JsonbConfig; - -import org.apache.commons.io.IOUtils; -import org.eclipse.yasson.FieldAccessStrategy; -import org.junit.Test; - - -// CHECKSTYLE:OFF -public final class PersonCreatedEventTest { - - @Test - public final void testSerializeDeserialize() { - - // PREPARE - final PersonCreatedEvent original = createTestee(); - - // TEST - final PersonCreatedEvent copy = deserialize(serialize(original)); - - // VERIFY - assertThat(copy).isEqualTo(original); - assertThat(copy.getName()).isEqualTo(original.getName()); - - } - - @Test - public final void testMarshalUnmarshalJson() { - - // PREPARE - final PersonCreatedEvent original = createTestee(); - - 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, PersonCreatedEvent.class); - final PersonCreatedEvent copy = jsonb.fromJson(json, PersonCreatedEvent.class); - - // VERIFY - assertThat(copy).isEqualTo(original); - assertThat(copy.getName()).isEqualTo(original.getName()); - - } - - @Test - public final void testUnmarshalJson() throws IOException { - - // PREPARE - final PersonCreatedEvent original = createTestee(); - final JsonbConfig config = new JsonbConfig().withAdapters(SharedUtils.JSONB_ADAPTERS) - .withPropertyVisibilityStrategy(new FieldAccessStrategy()); - final Jsonb jsonb = JsonbBuilder.create(config); - - // TEST - final String json = IOUtils.toString(this.getClass().getResourceAsStream("/events/PersonCreatedEvent.json"), - Charset.forName("utf-8")); - final PersonCreatedEvent copy = jsonb.fromJson(json, PersonCreatedEvent.class); - - // VERIFY - assertThat(copy.getEntityIdPath()).isEqualTo(original.getEntityIdPath()); - assertThat(copy.getName()).isEqualTo(original.getName()); - - } - - - @Test - public final void testToString() { - assertThat(createTestee().toString()) - .isEqualTo("Person 'Peter Parker' was created"); - } - - private PersonCreatedEvent createTestee() { - final PersonId personId = new PersonId(UUID.fromString("f645969a-402d-41a9-882b-d2d8000d0f43")); - final PersonName personName = new PersonName("Peter Parker"); - return new PersonCreatedEvent(personId, personName); - } - -} diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java deleted file mode 100644 index fec2fd7..0000000 --- a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonIdTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -import java.util.UUID; - -import org.fuin.ddd4j.ddd.EntityType; -import org.fuin.ddd4j.ddd.StringBasedEntityType; -import org.fuin.objects4j.common.ConstraintViolationException; -import org.junit.Test; - -import nl.jqno.equalsverifier.EqualsVerifier; -import nl.jqno.equalsverifier.Warning; - -/** - * Test for {@link PersonId}. - */ -public final class PersonIdTest { - - 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 testValueOf() { - final PersonId personId = PersonId.valueOf(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 final void testConverterUnmarshal() throws Exception { - - // PREPARE - final String personIdValue = PERSON_UUID; - - // TEST - final PersonId personId = new PersonId.Converter().adaptFromJson(UUID.fromString(PERSON_UUID)); - - // VERIFY - assertThat(personId.asString()).isEqualTo(personIdValue); - } - - @Test - public void testConverterMarshal() throws Exception { - - final PersonId personId = PersonId.valueOf(PERSON_UUID); - - // TEST - final UUID uuid = new PersonId.Converter().adaptToJson(personId); - - // VERIFY - assertThat(uuid).isEqualTo(UUID.fromString(PERSON_UUID)); - } - -} diff --git a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java b/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java deleted file mode 100644 index d9ea349..0000000 --- a/spring-boot/shared/src/test/java/org/fuin/cqrs4j/example/spring/shared/PersonNameTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/** - * Copyright (C) 2015 Michael Schnell. All rights reserved. - * http://www.fuin.org/ - * - * This library is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) any - * later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see http://www.gnu.org/licenses/. - */ -package org.fuin.cqrs4j.example.spring.shared; - - -import static org.assertj.core.api.Assertions.assertThat; - -import org.fuin.objects4j.common.ConstraintViolationException; -import org.fuin.utils4j.Utils4J; -import org.junit.Assert; -import org.junit.Test; - -import nl.jqno.equalsverifier.EqualsVerifier; -import nl.jqno.equalsverifier.Warning; - -// CHECKSTYLE:OFF -public final class PersonNameTest { - - @Test - public void testSerialize() { - final PersonName original = new PersonName("Peter Parker"); - final PersonName copy = Utils4J.deserialize(Utils4J.serialize(original)); - assertThat(original).isEqualTo(copy); - } - - @Test - public void testHashCodeEquals() { - EqualsVerifier.forClass(PersonName.class).suppress(Warning.NULL_FIELDS).withRedefinedSuperclass().verify(); - } - - @Test - public void testMarshalJson() throws Exception { - - // PREPARE - final String str = "Peter Parker"; - final PersonName testee = new PersonName(str); - - // TEST & VERIFY - assertThat(new PersonName.Converter().adaptToJson(testee)).isEqualTo(str); - assertThat(new PersonName.Converter().adaptToJson(null)).isNull(); - - } - - @Test - public void testUnmarshalJson() throws Exception { - - // PREPARE - final String str = "Peter Parker"; - final PersonName testee = new PersonName(str); - - // TEST & VERIFY - assertThat(new PersonName.Converter().adaptFromJson(str)).isEqualTo(testee); - assertThat(new PersonName.Converter().adaptFromJson(null)).isNull(); - - } - - @Test - public void testIsValid() { - - assertThat(PersonName.isValid(null)).isTrue(); - 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(); - - } - - @Test - public void testRequireArgValid() { - - PersonName.requireArgValid("a", "Peter Parker"); - PersonName.requireArgValid("b", null); - - try { - PersonName.requireArgValid("c", ""); - Assert.fail(); - } catch (final ConstraintViolationException ex) { - assertThat(ex.getMessage()).isEqualTo("The argument 'c' is not valid: ''"); - } - - try { - 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" + "'"); - } - - } - - @Test - public void testValidator() { - - assertThat(new PersonName.Validator().isValid(null, null)).isTrue(); - 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(); - - } - - @Test - public void testValueObjectConverter() { - - assertThat(new PersonName.Converter().getBaseTypeClass()).isEqualTo(String.class); - assertThat(new PersonName.Converter().getValueObjectClass()).isEqualTo(PersonName.class); - 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(); - - } - -}