From 8bde95472d7a21adf4424d8580995396e97c5ac1 Mon Sep 17 00:00:00 2001 From: Tom Hombergs Date: Mon, 30 Sep 2019 11:00:57 +0200 Subject: [PATCH] simplifiex code examples --- .../AccountPersistenceAdapter.java | 7 +++- .../adapter/web/SendMoneyController.java | 2 +- .../adapter/web/SendMoneyControllerTest.java | 4 +- .../application/port/in/SendMoneyUseCase.java | 14 +++---- .../application/service/SendMoneyService.java | 37 ++++++++++++------- .../reflectoring/buckpal/domain/Account.java | 22 +++++++---- .../buckpal/domain/ActivityWindow.java | 3 +- .../buckpal/SendMoneySystemTest.java | 2 +- 8 files changed, 57 insertions(+), 34 deletions(-) diff --git a/adapters/buckpal-persistence/src/main/java/io/reflectoring/buckpal/adapter/persistence/AccountPersistenceAdapter.java b/adapters/buckpal-persistence/src/main/java/io/reflectoring/buckpal/adapter/persistence/AccountPersistenceAdapter.java index ab671e1..92e8d5c 100644 --- a/adapters/buckpal-persistence/src/main/java/io/reflectoring/buckpal/adapter/persistence/AccountPersistenceAdapter.java +++ b/adapters/buckpal-persistence/src/main/java/io/reflectoring/buckpal/adapter/persistence/AccountPersistenceAdapter.java @@ -12,9 +12,10 @@ import io.reflectoring.buckpal.domain.Account.AccountId; import io.reflectoring.buckpal.domain.Activity; import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; @RequiredArgsConstructor -@PersistenceAdapter +@Component class AccountPersistenceAdapter implements LoadAccountPort, UpdateAccountStatePort { @@ -24,7 +25,9 @@ class AccountPersistenceAdapter implements private final AccountMapper accountMapper; @Override - public Account loadAccount(AccountId accountId, LocalDateTime baselineDate) { + public Account loadAccount( + AccountId accountId, + LocalDateTime baselineDate) { AccountJpaEntity account = accountRepository.findById(accountId.getValue()) diff --git a/adapters/buckpal-web/src/main/java/io/reflectoring/buckpal/adapter/web/SendMoneyController.java b/adapters/buckpal-web/src/main/java/io/reflectoring/buckpal/adapter/web/SendMoneyController.java index 955a19f..6678fd6 100644 --- a/adapters/buckpal-web/src/main/java/io/reflectoring/buckpal/adapter/web/SendMoneyController.java +++ b/adapters/buckpal-web/src/main/java/io/reflectoring/buckpal/adapter/web/SendMoneyController.java @@ -15,7 +15,7 @@ public class SendMoneyController { private final SendMoneyUseCase sendMoneyUseCase; - @PostMapping(path = "/accounts/sendMoney/{sourceAccountId}/{targetAccountId}/{amount}") + @PostMapping(path = "/accounts/send/{sourceAccountId}/{targetAccountId}/{amount}") void sendMoney( @PathVariable("sourceAccountId") Long sourceAccountId, @PathVariable("targetAccountId") Long targetAccountId, diff --git a/adapters/buckpal-web/src/test/java/io/reflectoring/buckpal/adapter/web/SendMoneyControllerTest.java b/adapters/buckpal-web/src/test/java/io/reflectoring/buckpal/adapter/web/SendMoneyControllerTest.java index 2b6bfcf..53fe5ae 100644 --- a/adapters/buckpal-web/src/test/java/io/reflectoring/buckpal/adapter/web/SendMoneyControllerTest.java +++ b/adapters/buckpal-web/src/test/java/io/reflectoring/buckpal/adapter/web/SendMoneyControllerTest.java @@ -25,7 +25,7 @@ class SendMoneyControllerTest { @Test void testSendMoney() throws Exception { - mockMvc.perform(post("/accounts/sendMoney/{sourceAccountId}/{targetAccountId}/{amount}", + mockMvc.perform(post("/accounts/send/{sourceAccountId}/{targetAccountId}/{amount}", 41L, 42L, 500) .header("Content-Type", "application/json")) .andExpect(status().isOk()); @@ -37,4 +37,4 @@ void testSendMoney() throws Exception { Money.of(500L)))); } -} \ No newline at end of file +} diff --git a/buckpal-application/src/main/java/io/reflectoring/buckpal/application/port/in/SendMoneyUseCase.java b/buckpal-application/src/main/java/io/reflectoring/buckpal/application/port/in/SendMoneyUseCase.java index 87bb4e3..5b72b1b 100644 --- a/buckpal-application/src/main/java/io/reflectoring/buckpal/application/port/in/SendMoneyUseCase.java +++ b/buckpal-application/src/main/java/io/reflectoring/buckpal/application/port/in/SendMoneyUseCase.java @@ -1,13 +1,13 @@ package io.reflectoring.buckpal.application.port.in; -import javax.validation.constraints.NotNull; - -import io.reflectoring.buckpal.domain.Account; +import io.reflectoring.buckpal.domain.Account.AccountId; import io.reflectoring.buckpal.domain.Money; import io.reflectoring.buckpal.testdata.SelfValidating; import lombok.EqualsAndHashCode; import lombok.Value; +import javax.validation.constraints.NotNull; + public interface SendMoneyUseCase { boolean sendMoney(SendMoneyCommand command); @@ -17,17 +17,17 @@ public interface SendMoneyUseCase { class SendMoneyCommand extends SelfValidating { @NotNull - private final Account.AccountId sourceAccountId; + private final AccountId sourceAccountId; @NotNull - private final Account.AccountId targetAccountId; + private final AccountId targetAccountId; @NotNull private final Money money; public SendMoneyCommand( - Account.AccountId sourceAccountId, - Account.AccountId targetAccountId, + AccountId sourceAccountId, + AccountId targetAccountId, Money money) { this.sourceAccountId = sourceAccountId; this.targetAccountId = targetAccountId; diff --git a/buckpal-application/src/main/java/io/reflectoring/buckpal/application/service/SendMoneyService.java b/buckpal-application/src/main/java/io/reflectoring/buckpal/application/service/SendMoneyService.java index 871a3e2..cb3b6a8 100644 --- a/buckpal-application/src/main/java/io/reflectoring/buckpal/application/service/SendMoneyService.java +++ b/buckpal-application/src/main/java/io/reflectoring/buckpal/application/service/SendMoneyService.java @@ -5,14 +5,16 @@ import io.reflectoring.buckpal.application.port.out.LoadAccountPort; import io.reflectoring.buckpal.application.port.out.UpdateAccountStatePort; import io.reflectoring.buckpal.domain.Account; +import io.reflectoring.buckpal.domain.Account.AccountId; import io.reflectoring.buckpal.testdata.UseCase; import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; import javax.transaction.Transactional; import java.time.LocalDateTime; @RequiredArgsConstructor -@UseCase +@Component @Transactional public class SendMoneyService implements SendMoneyUseCase { @@ -24,9 +26,7 @@ public class SendMoneyService implements SendMoneyUseCase { @Override public boolean sendMoney(SendMoneyCommand command) { - if(command.getMoney().isGreaterThan(moneyTransferProperties.getMaximumTransferThreshold())){ - throw new ThresholdExceededException(moneyTransferProperties.getMaximumTransferThreshold(), command.getMoney()); - } + checkThreshold(command); LocalDateTime baselineDate = LocalDateTime.now().minusDays(10); @@ -38,25 +38,36 @@ public boolean sendMoney(SendMoneyCommand command) { command.getTargetAccountId(), baselineDate); - accountLock.lockAccount(sourceAccount.getId()); - if (!sourceAccount.withdraw(command.getMoney(), targetAccount.getId())) { - accountLock.releaseAccount(sourceAccount.getId()); + AccountId sourceAccountId = sourceAccount.getId() + .orElseThrow(() -> new IllegalStateException("expected source account ID not to be empty")); + AccountId targetAccountId = targetAccount.getId() + .orElseThrow(() -> new IllegalStateException("expected target account ID not to be empty")); + + accountLock.lockAccount(sourceAccountId); + if (!sourceAccount.withdraw(command.getMoney(), targetAccountId)) { + accountLock.releaseAccount(sourceAccountId); return false; } - accountLock.lockAccount(targetAccount.getId()); - if (!targetAccount.deposit(command.getMoney(), sourceAccount.getId())) { - accountLock.releaseAccount(sourceAccount.getId()); - accountLock.releaseAccount(targetAccount.getId()); + accountLock.lockAccount(targetAccountId); + if (!targetAccount.deposit(command.getMoney(), sourceAccountId)) { + accountLock.releaseAccount(sourceAccountId); + accountLock.releaseAccount(targetAccountId); return false; } updateAccountStatePort.updateActivities(sourceAccount); updateAccountStatePort.updateActivities(targetAccount); - accountLock.releaseAccount(sourceAccount.getId()); - accountLock.releaseAccount(targetAccount.getId()); + accountLock.releaseAccount(sourceAccountId); + accountLock.releaseAccount(targetAccountId); return true; } + private void checkThreshold(SendMoneyCommand command) { + if(command.getMoney().isGreaterThan(moneyTransferProperties.getMaximumTransferThreshold())){ + throw new ThresholdExceededException(moneyTransferProperties.getMaximumTransferThreshold(), command.getMoney()); + } + } + } diff --git a/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/Account.java b/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/Account.java index 4736c19..5cfdf47 100644 --- a/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/Account.java +++ b/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/Account.java @@ -1,6 +1,7 @@ package io.reflectoring.buckpal.domain; import java.time.LocalDateTime; +import java.util.Optional; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -19,36 +20,43 @@ public class Account { /** * The unique ID of the account. */ - @Getter - private AccountId id; + @Getter private final AccountId id; /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ - private Money baselineBalance; + @Getter private final Money baselineBalance; /** * The window of latest activities on this account. */ - @Getter - private ActivityWindow activityWindow; + @Getter private final ActivityWindow activityWindow; /** * Creates an {@link Account} entity without an ID. Use to create a new entity that is not yet * persisted. */ - public static Account withoutId(Money baselineBalance, ActivityWindow activityWindow) { + public static Account withoutId( + Money baselineBalance, + ActivityWindow activityWindow) { return new Account(null, baselineBalance, activityWindow); } /** * Creates an {@link Account} entity with an ID. Use to reconstitute a persisted entity. */ - public static Account withId(AccountId accountId, Money baselineBalance, ActivityWindow activityWindow) { + public static Account withId( + AccountId accountId, + Money baselineBalance, + ActivityWindow activityWindow) { return new Account(accountId, baselineBalance, activityWindow); } + public Optional getId(){ + return Optional.ofNullable(this.id); + } + /** * Calculates the total balance of the account by adding the activity values to the baseline balance. */ diff --git a/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/ActivityWindow.java b/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/ActivityWindow.java index 14e40ae..b4d6675 100644 --- a/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/ActivityWindow.java +++ b/buckpal-application/src/main/java/io/reflectoring/buckpal/domain/ActivityWindow.java @@ -3,6 +3,7 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -66,7 +67,7 @@ public ActivityWindow(@NonNull Activity... activities) { } public List getActivities() { - return new ArrayList<>(this.activities); + return Collections.unmodifiableList(this.activities); } public void addActivity(Activity activity) { diff --git a/buckpal-configuration/src/test/java/io/reflectoring/buckpal/SendMoneySystemTest.java b/buckpal-configuration/src/test/java/io/reflectoring/buckpal/SendMoneySystemTest.java index 033fe48..600a487 100644 --- a/buckpal-configuration/src/test/java/io/reflectoring/buckpal/SendMoneySystemTest.java +++ b/buckpal-configuration/src/test/java/io/reflectoring/buckpal/SendMoneySystemTest.java @@ -75,7 +75,7 @@ private ResponseEntity whenSendMoney( HttpEntity request = new HttpEntity<>(null, headers); return restTemplate.exchange( - "/accounts/sendMoney/{sourceAccountId}/{targetAccountId}/{amount}", + "/accounts/send/{sourceAccountId}/{targetAccountId}/{amount}", HttpMethod.POST, request, Object.class,