Refactored module and package structure
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
package org.fuin.cqrs4j.example.spring.command.app;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class CmdConfig {
|
||||
|
||||
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 CmdConfig() {
|
||||
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 CmdConfig(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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,160 +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.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.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;
|
||||
import org.fuin.ddd4j.ddd.AggregateVersionConflictException;
|
||||
import org.fuin.ddd4j.ddd.AggregateVersionNotFoundException;
|
||||
import org.fuin.objects4j.common.Contract;
|
||||
import org.fuin.objects4j.common.ExceptionShortIdentifable;
|
||||
import org.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 = AggregateAlreadyExistsException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final AggregateAlreadyExistsException 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 = AggregateDeletedException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final AggregateDeletedException 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.GONE);
|
||||
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = AggregateNotFoundException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final AggregateNotFoundException 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 = AggregateVersionConflictException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final AggregateVersionConflictException 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 = AggregateVersionNotFoundException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final AggregateVersionNotFoundException 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 = CommandExecutionFailedException.class)
|
||||
public ResponseEntity<SimpleResult> exception(final CommandExecutionFailedException ex) {
|
||||
|
||||
final String shortId;
|
||||
if (ex.getCause() instanceof ExceptionShortIdentifable) {
|
||||
final ExceptionShortIdentifable esi = (ExceptionShortIdentifable) ex.getCause();
|
||||
shortId = esi.getShortId();
|
||||
} else {
|
||||
shortId = ex.getCause().getClass().getName();
|
||||
}
|
||||
|
||||
LOG.info("{} {}", shortId, ex.getCause().getMessage());
|
||||
|
||||
final HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
return new ResponseEntity<>(SimpleResult.error(shortId, ex.getMessage()), headers, HttpStatus.BAD_REQUEST);
|
||||
|
||||
}
|
||||
|
||||
@ExceptionHandler(value = DuplicatePersonNameException.class)
|
||||
public ResponseEntity<SimpleResult> 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<SimpleResult> 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<ConstraintViolation<?>> constraintViolations) {
|
||||
if (constraintViolations == null || constraintViolations.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
final List<String> list = new ArrayList<>();
|
||||
for (final ConstraintViolation<?> constraintViolation : constraintViolations) {
|
||||
list.add(Contract.asString(constraintViolation));
|
||||
}
|
||||
return list.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<PersonId> 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<PersonId, Person> {
|
||||
|
||||
/**
|
||||
* Constructor all mandatory data.
|
||||
*
|
||||
* @param eventStore
|
||||
* Event store.
|
||||
*/
|
||||
public PersonRepository(final EventStore eventStore) {
|
||||
super(eventStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Class<Person> 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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user