From 3cff5edee8b9d7a6642e48bb600c8baf19837794 Mon Sep 17 00:00:00 2001 From: Justin Phillips Date: Fri, 29 Mar 2019 17:08:50 -0400 Subject: [PATCH 1/5] Added full coverage for Account aggregate --- .../cmd/tests/unit/isolation/AccountTest.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java index b9069492..a5e992aa 100644 --- a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java +++ b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java @@ -1,13 +1,19 @@ package com.ultimatesoftware.banking.account.cmd.tests.unit.isolation; import com.ultimatesoftware.banking.account.cmd.aggregates.Account; +import com.ultimatesoftware.banking.account.cmd.commands.CancelTransferCommand; +import com.ultimatesoftware.banking.account.cmd.commands.ConcludeTransferDepositCommand; import com.ultimatesoftware.banking.account.cmd.commands.CreditAccountCommand; import com.ultimatesoftware.banking.account.cmd.commands.DebitAccountCommand; import com.ultimatesoftware.banking.account.cmd.commands.DeleteAccountCommand; +import com.ultimatesoftware.banking.account.cmd.commands.FailToStartTransferTransactionCommand; +import com.ultimatesoftware.banking.account.cmd.commands.ReleaseAccountCommand; +import com.ultimatesoftware.banking.account.cmd.commands.StartTransferTransactionCommand; import com.ultimatesoftware.banking.account.cmd.commands.UpdateAccountCommand; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForCreditException; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForDebitException; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForDeleteException; +import com.ultimatesoftware.banking.account.cmd.models.TransactionDto; import com.ultimatesoftware.banking.account.cmd.rules.AccountRules; import com.ultimatesoftware.banking.account.events.*; import org.bson.types.ObjectId; @@ -174,6 +180,93 @@ public void givenAccountExists_WhenUpdating_AccountUpdatedIsEmitted() throws Exc verify(account, times(1)).applyEvent(any()); } + @Test + public void givenAccountExists_WhenConcludeTransferDeposit_TransactionStratedEmitted() throws Exception { + // arrange + doNothing().when(account).applyEvent(any()); + account.on(AccountCreatedEvent.builder() + .id(id.toHexString()) + .customerId(customerId) + .balance(0.0) + .build()); + TransactionDto transaction = new TransactionDto("", ObjectId.get().toHexString(), "customer", 10.0, "dest"); + + // act + account.on(new StartTransferTransactionCommand(transaction)); + + // assert + verify(account, times(1)).applyEvent(any(TransferTransactionStartedEvent.class)); + } + + @Test + public void givenAccountExists_WhenConcludeTransfer_TransferConcludedEmitted() throws Exception { + // arrange + doNothing().when(account).applyEvent(any()); + account.on(AccountCreatedEvent.builder() + .id(id.toHexString()) + .customerId(customerId) + .balance(0.0) + .build()); + + // act + account.on(new ConcludeTransferDepositCommand(ObjectId.get().toHexString(), 10.00, "transaction")); + + // assert + verify(account, times(1)).applyEvent(any(TransferDepositConcludedEvent.class)); + } + + @Test + public void givenAccountExists_WhenReleaseAccountCommmand_AccountReleasedEmitted() throws Exception { + // arrange + doNothing().when(account).applyEvent(any()); + account.on(AccountCreatedEvent.builder() + .id(id.toHexString()) + .customerId(customerId) + .balance(0.0) + .build()); + + // act + account.on(new ReleaseAccountCommand(ObjectId.get().toHexString(), "transaction")); + + // assert + verify(account, times(1)).applyEvent(any(AccountReleasedEvent.class)); + } + + @Test + public void givenAccountExists_WhenCancelTransferCommmand_CancelTransferEmitted() throws Exception { + // arrange + doNothing().when(account).applyEvent(any()); + account.on(AccountCreatedEvent.builder() + .id(id.toHexString()) + .customerId(customerId) + .balance(0.0) + .build()); + + // act + account.on(new CancelTransferCommand(ObjectId.get().toHexString(), 10.0, "trans")); + + // assert + verify(account, times(1)).applyEvent(any(TransferCanceledEvent.class)); + } + + @Test + public void givenAccountExists_WhenFailedToStartTransaction_FailedToStartEmitted() throws Exception { + // arrange + doNothing().when(account).applyEvent(any()); + account.on(AccountCreatedEvent.builder() + .id(id.toHexString()) + .customerId(customerId) + .balance(0.0) + .build()); + TransactionDto transaction = new TransactionDto("", ObjectId.get().toHexString(), "customer", 10.0, "dest"); + + // act + account.on(new FailToStartTransferTransactionCommand(transaction)); + + // assert + verify(account, times(1)).applyEvent(any(TransferFailedToStartEvent.class)); + } + @Test public void givenAcountCreatedEmitted_whenHandling_ThenUpdateIdBalanceCustomerId() { @@ -277,4 +370,77 @@ public void givenAcountUpdatedEmitted_whenHandling_ThenUpdateCustomerId() { // assert assertEquals(customerId, account.getCustomerId()); } + + @Test + public void givenTransferWithdrawConcludedEmitted_whenHandling_ThenIncrementTransfers() { + // arrange + String customerId = UUID.randomUUID().toString(); + + // act + account.on(TransferWithdrawConcludedEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .balance(20.0) + .build()); + + // assert + assertEquals(account.getActiveTransfers(), 1); + } + + @Test + public void givenTransferDepositConcludedEmitted_whenHandling_ThenIncrementTransfers() { + // arrange + String customerId = UUID.randomUUID().toString(); + + // act + account.on(TransferDepositConcludedEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .balance(20.0) + .build()); + + // assert + assertEquals(account.getActiveTransfers(), 1); + } + + @Test + public void givenAccountReleasedEmitted_whenHandling_ThenDecrementTransfers() { + // arrange + String customerId = UUID.randomUUID().toString(); + account.on(TransferDepositConcludedEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .balance(20.0) + .build()); + + // act + account.on(AccountReleasedEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .build()); + + // assert + assertEquals(account.getActiveTransfers(), 0); + } + + @Test + public void givenTransferCanceledEmitted_whenHandling_ThenDecrementTransfers() { + // arrange + String customerId = UUID.randomUUID().toString(); + account.on(TransferDepositConcludedEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .balance(20.0) + .build()); + + // act + account.on(TransferCanceledEvent.builder() + .id(id.toHexString()) + .transactionId(customerId) + .balance(20.0) + .build()); + + // assert + assertEquals(account.getActiveTransfers(), 0); + } } From 0e4abe3fb3079c56a31f03f60058e61ddd3a6a53 Mon Sep 17 00:00:00 2001 From: Justin Phillips Date: Fri, 29 Mar 2019 17:14:07 -0400 Subject: [PATCH 2/5] fixed syntax typo. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9f2a1302..e16aff8e 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,7 @@ sh ./scripts/run-transaction-pairwise-tests-with-cmd.sh Take down the services in the other terminal window. ```bash docker-compose -f docker-compose-pair-wise-account-cmd-transaction.yml down +``` # API Documentation: From ec65a72dbad402c9d646929079e0fce1cc647d7c Mon Sep 17 00:00:00 2001 From: Justin Phillips Date: Mon, 1 Apr 2019 17:11:07 -0400 Subject: [PATCH 3/5] Multiple changes, see details Removed the backing services compose file and merged the services into one master compose. Fixed rollback issues with transfers Fixed issue with transfer contract Fixed configuration issue with people-details service Streamlined event creation in account-cmd. --- README.md | 19 +- docker-compose-backing.yml | 73 -------- docker-compose.yml | 71 +++++-- .../account/cmd/aggregates/Account.java | 176 ++++++++++++------ .../cmd/commands/CancelTransferCommand.java | 6 +- .../ConcludeTransferDepositCommand.java | 19 -- .../cmd/commands/CreditAccountCommand.java | 14 ++ .../cmd/commands/DebitAccountCommand.java | 12 ++ ...FailToStartTransferTransactionCommand.java | 19 -- .../cmd/commands/FailTransactionCommand.java | 25 +++ ....java => RevertAccountBalanceCommand.java} | 9 +- ...Command.java => StartTransferCommand.java} | 4 +- .../StartTransferWithdrawCommand.java | 18 -- .../AccountSagaManagerConfiguration.java | 7 + .../cmd/controllers/AccountsController.java | 3 +- .../account/cmd/models/TransactionDto.java | 4 +- .../cmd/rules/StandardAccountRules.java | 4 +- .../account/cmd/sagas/TransactionSaga.java | 63 ++++--- .../account/events/BalanceRevertedEvent.java | 26 +++ .../events/TransferDepositConcludedEvent.java | 4 +- ...artEvent.java => TransferFailedEvent.java} | 9 +- .../events/factories/AccountEventType.java | 17 -- .../events/factories/EventFactory.java | 122 ------------ .../unit/isolation/AccountControllerTest.java | 4 +- .../cmd/tests/unit/isolation/AccountTest.java | 40 ++-- .../unit/social/TransactionSagaTest.java | 11 +- .../transactions/models/Transaction.java | 6 +- .../models/TransferTransactionDto.java | 6 + .../services/TransactionService.java | 2 +- .../unit/TransactionServiceUnitTest.java | 6 +- .../PersonDetailsEventHandler.java | 5 +- .../src/main/resources/application.yml | 5 + .../SagaManagerConfiguration.java | 3 + 33 files changed, 385 insertions(+), 427 deletions(-) delete mode 100644 docker-compose-backing.yml delete mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/ConcludeTransferDepositCommand.java delete mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailToStartTransferTransactionCommand.java create mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailTransactionCommand.java rename domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/{StartTransferDepositCommand.java => RevertAccountBalanceCommand.java} (58%) rename domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/{StartTransferTransactionCommand.java => StartTransferCommand.java} (75%) delete mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferWithdrawCommand.java create mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/BalanceRevertedEvent.java rename domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/{TransferFailedToStartEvent.java => TransferFailedEvent.java} (66%) delete mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/AccountEventType.java delete mode 100644 domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/EventFactory.java diff --git a/README.md b/README.md index e16aff8e..66d31621 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/AITestingOrg/banking-microservices-tutorial.svg?branch=master)](https://travis-ci.org/AITestingOrg/banking-microservices-tutorial) [![Coverage Status](https://coveralls.io/repos/github/AITestingOrg/banking-microservices-tutorial/badge.svg?branch=service-integration-testing)](https://coveralls.io/github/AITestingOrg/banking-microservices-tutorial?branch=service-integration-testing) -The Banking Microservices Example project is a small system used to show how microservices can be implemented and tested with Micronaut, Consul, Tyk, and Axon's Event Sourcing framework. The system can be run in multiple configurations using Docker. +The Banking Microservices Tutorial project is a small system used to show how microservices can be implemented and tested with Micronaut, Consul, Tyk, and Axon's Event Sourcing framework. The system can be run in multiple configurations using Docker. ![](documentation/images/micronaut.jpg)![](documentation/images/axon.png)![](documentation/images/consul.svg)![](documentation/images/mongo.png)![](documentation/images/express-gateway.png)![](documentation/images/junit5-banner.png) ## Architecture @@ -29,6 +29,9 @@ See each services readme for detailed requirement information ### Java 8 * https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html +### IntelliJ IDEA +* The recommended IDE for this project https://www.jetbrains.com/idea/, Community Edition is fine. + ### Lombok * IntelliJ IDEA installation: https://projectlombok.org/setup/intellij @@ -40,16 +43,20 @@ See each services readme for detailed requirement information # Assemble the binaries ./gradlew assemble # Start the backing services: service discovery, configuration, authentication, edge service -docker-compose -f docker-compose-backing.yml up --build -# After the backing services have succesfully loaded, start the domain services -docker-compose up +docker-compose up --build ``` ## Stop the Containers ```bash docker-compose down -docker-compose -f docker-compose.yml down -docker-compose -f docker-compose-backing.yml down +``` + +## Running with Mocks +To download the Mock images and test running on your machine use the following commands. +```bash +docker-compose -f docker-compose-sub-domain-testing.yml up +# After verifying everything spun up correctly tear it down. +docker-compose -f docker-compose-sub-domain-testing.yml down ``` diff --git a/docker-compose-backing.yml b/docker-compose-backing.yml deleted file mode 100644 index 66b729e0..00000000 --- a/docker-compose-backing.yml +++ /dev/null @@ -1,73 +0,0 @@ -version: '3' -services: - discovery-service: - image: bitnami/consul:latest - networks: - - bank - ports: - - '8300:8300' - - '8301:8301' - - '8301:8301/udp' - - '8500:8500' - - '8600:8600' - - '8600:8600/udp' - - people-gateway: - build: docker/express-gateway/ - ports: - - "8081:8080" - - "8443:8443" - - "9876:9876" - volumes: - - ./docker/express-gateway/people-configuration/system.config.yml:/usr/src/app/config/system.config.yml - - ./docker/express-gateway/people-configuration/gateway.config.yml:/usr/src/app/config/gateway.config.yml - networks: - - bank - depends_on: - - redis - - account-gateway: - build: docker/express-gateway/ - ports: - - "8080:8080" - - "8444:8443" - - "9877:9876" - volumes: - - ./docker/express-gateway/account-configuration/system.config.yml:/usr/src/app/config/system.config.yml - - ./docker/express-gateway/account-configuration/gateway.config.yml:/usr/src/app/config/gateway.config.yml - depends_on: - - redis - - mongo: - image: 'mongo:3.4.1' - ports: - - '27017:27017' - volumes: - - 'mongo:/data/mongo/db' - networks: - - bank - - redis: - image: redis - ports: - - "6379:6379" - volumes: - - 'redis:/data/redis' - networks: - - bank - - axonserver: - image: 'axoniq/axonserver' - ports: - - '8124:8124' - - '8024:8024' - networks: - - bank - -networks: - bank: - driver: bridge - -volumes: - redis: - mongo: diff --git a/docker-compose.yml b/docker-compose.yml index ffe9012b..3c2a3cc6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,64 @@ version: '2.1' services: + discovery-service: + image: bitnami/consul:latest + ports: + - '8300:8300' + - '8301:8301' + - '8301:8301/udp' + - '8500:8500' + - '8600:8600' + - '8600:8600/udp' + + people-gateway: + build: docker/express-gateway/ + ports: + - "8081:8080" + - "8443:8443" + - "9876:9876" + volumes: + - ./docker/express-gateway/people-configuration/system.config.yml:/usr/src/app/config/system.config.yml + - ./docker/express-gateway/people-configuration/gateway.config.yml:/usr/src/app/config/gateway.config.yml + depends_on: + - redis + + account-gateway: + build: docker/express-gateway/ + ports: + - "8080:8080" + - "8444:8443" + - "9877:9876" + volumes: + - ./docker/express-gateway/account-configuration/system.config.yml:/usr/src/app/config/system.config.yml + - ./docker/express-gateway/account-configuration/gateway.config.yml:/usr/src/app/config/gateway.config.yml + depends_on: + - redis + + mongo: + image: 'mongo:3.4.1' + ports: + - '27017:27017' + volumes: + - 'mongo:/data/mongo/db' + + redis: + image: redis + ports: + - "6379:6379" + volumes: + - 'redis:/data/redis' + + axonserver: + image: 'axoniq/axonserver' + ports: + - '8124:8124' + - '8024:8024' + people-details: build: domain-services/people-details/ mem_limit: 400m ports: - "8085:8085" - networks: - - banking-microservices-tutorial_bank restart: on-failure environment: - CONSUL_HOST=discovery-service @@ -19,8 +71,6 @@ services: mem_limit: 400m ports: - "8087:8087" - networks: - - banking-microservices-tutorial_bank restart: on-failure environment: - CONSUL_HOST=discovery-service @@ -33,8 +83,6 @@ services: mem_limit: 400m ports: - "8088:8088" - networks: - - banking-microservices-tutorial_bank restart: on-failure environment: - CONSUL_HOST=discovery-service @@ -47,8 +95,6 @@ services: mem_limit: 400m ports: - "8082:8082" - networks: - - banking-microservices-tutorial_bank restart: on-failure environment: - CONSUL_HOST=discovery-service @@ -61,8 +107,6 @@ services: mem_limit: 400m ports: - "8084:8084" - networks: - - banking-microservices-tutorial_bank restart: on-failure environment: - CONSUL_HOST=discovery-service @@ -83,13 +127,8 @@ services: - HOST_PORT=8086 - PEOPLE_DETAILS_HOST= - ES_JAVA_OPTS= "-Xms150mb -Xmx150mb" - networks: - - banking-microservices-tutorial_bank restart: on-failure -networks: - banking-microservices-tutorial_bank: - external: true - volumes: + redis: mongo: diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/aggregates/Account.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/aggregates/Account.java index ee4aac0e..771bcda8 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/aggregates/Account.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/aggregates/Account.java @@ -7,8 +7,6 @@ import com.ultimatesoftware.banking.account.cmd.rules.AccountRules; import com.ultimatesoftware.banking.account.cmd.rules.StandardAccountRules; import com.ultimatesoftware.banking.account.events.*; -import com.ultimatesoftware.banking.account.events.factories.AccountEventType; -import com.ultimatesoftware.banking.account.events.factories.EventFactory; import lombok.Getter; import lombok.NoArgsConstructor; import org.axonframework.commandhandling.CommandHandler; @@ -31,24 +29,24 @@ public class Account { private @Getter ObjectId id; private @Getter String customerId; private @Getter BigDecimal balance; - private @Getter int activeTransfers; + private @Getter boolean activeTransfer; private AccountRules accountRules = new StandardAccountRules(); @CommandHandler public Account(CreateAccountCommand createAccountCommand) throws Exception { - applyEvent(EventFactory.createEvent( - AccountEventType.CREATED, - createAccountCommand.getId().toHexString(), - createAccountCommand.getCustomerId(), - createAccountCommand.getBalance())); + applyEvent(AccountCreatedEvent.builder() + .id(createAccountCommand.getId().toHexString()) + .balance(createAccountCommand.getBalance()) + .customerId(createAccountCommand.getCustomerId()) + .build()); } public Account(ObjectId id, String customerId, BigDecimal balance) { this.id = id; this.customerId = customerId; this.balance = balance; - activeTransfers = 0; + activeTransfer = false; } public void setAccountRules(AccountRules accountRules) { @@ -58,31 +56,97 @@ public void setAccountRules(AccountRules accountRules) { @CommandHandler public void on(DebitAccountCommand debitAccountCommand) throws Exception { if (!this.accountRules.eligibleForDebit(this, debitAccountCommand.getAmount())) { - applyEvent(EventFactory.createEvent(AccountEventType.TRANSACTION_FAILED, debitAccountCommand.getId().toHexString(), debitAccountCommand.getTransactionId(), "Account balance not eligable for withdraw.")); - throw new AccountNotEligibleForDebitException(id.toHexString(), balance.doubleValue()); + if (debitAccountCommand.isTransfer()) { + applyEvent(TransferFailedEvent.builder() + .id(debitAccountCommand.getId().toHexString()) + .msg(String.format("Account %s balance not eligible for withdraw.", + debitAccountCommand.getId().toHexString())) + .transactionId(debitAccountCommand.getTransactionId()) + .build()); + } else { + applyEvent(TransactionFailedEvent.builder() + .id(debitAccountCommand.getId().toHexString()) + .msg(String.format("Account %s balance not eligible for withdraw.", + debitAccountCommand.getId().toHexString())) + .transactionId(debitAccountCommand.getTransactionId()) + .build()); + } + throw new AccountNotEligibleForDebitException(id.toHexString(), + balance.doubleValue()); } BigDecimal newBalance = balance.subtract(BigDecimal.valueOf(debitAccountCommand.getAmount())); - applyEvent(EventFactory.createEvent(AccountEventType.DEBITED, debitAccountCommand.getId().toHexString(), customerId, debitAccountCommand.getAmount(), newBalance.doubleValue(), - debitAccountCommand.getTransactionId())); + if (debitAccountCommand.isTransfer()) { + applyEvent(TransferWithdrawConcludedEvent.builder() + .id(debitAccountCommand.getId().toHexString()) + .balance(newBalance.doubleValue()) + .transactionId(debitAccountCommand.getTransactionId()) + .build()); + } else { + applyEvent(AccountDebitedEvent.builder() + .id(debitAccountCommand.getId().toHexString()) + .balance(newBalance.doubleValue()) + .debitAmount(debitAccountCommand.getAmount()) + .customerId(customerId) + .transactionId(debitAccountCommand.getTransactionId()) + .build()); + } } @CommandHandler public void on(CreditAccountCommand creditAccountCommand) throws Exception { if (!this.accountRules.eligibleForCredit(this, creditAccountCommand.getAmount())) { - applyEvent(EventFactory.createEvent(AccountEventType.TRANSACTION_FAILED, creditAccountCommand.getId().toHexString(), creditAccountCommand.getTransactionId(), "Account balance not eligable for deposit.")); + if (creditAccountCommand.isTransfer()) { + applyEvent(TransferFailedEvent.builder() + .id(creditAccountCommand.getId().toHexString()) + .msg(String.format("Account %s not eligible for deposit.", + creditAccountCommand.getId().toHexString())) + .transactionId(creditAccountCommand.getTransactionId()) + .build()); + } else { + applyEvent(TransactionFailedEvent.builder() + .id(creditAccountCommand.getId().toHexString()) + .transactionId(creditAccountCommand.getTransactionId()) + .msg(String.format("Account %s balance not eligible for deposit.", + id.toHexString())) + .build()); + } throw new AccountNotEligibleForCreditException(id.toHexString(), balance.doubleValue()); } BigDecimal newBalance = balance.add(BigDecimal.valueOf(creditAccountCommand.getAmount())); - applyEvent(EventFactory.createEvent(AccountEventType.CREDITED, creditAccountCommand.getId().toHexString(), customerId, - creditAccountCommand.getAmount(), newBalance.doubleValue(), - creditAccountCommand.getTransactionId().toString())); + if (creditAccountCommand.isTransfer()) { + applyEvent(TransferDepositConcludedEvent.builder() + .id(creditAccountCommand.getId().toHexString()) + .balance(newBalance.doubleValue()) + .transactionId(creditAccountCommand.getTransactionId()) + .build()); + } else { + applyEvent(AccountCreditedEvent.builder() + .id(creditAccountCommand.getId().toHexString()) + .customerId(customerId) + .balance(newBalance.doubleValue()) + .creditAmount(creditAccountCommand.getAmount()) + .transactionId(creditAccountCommand.getTransactionId()) + .build()); + } + } + + @CommandHandler + public void on(RevertAccountBalanceCommand revertAccountBalanceCommand) { + BigDecimal newBalance = balance.add(BigDecimal.valueOf(revertAccountBalanceCommand.getAmount())); + applyEvent(BalanceRevertedEvent.builder() + .id(revertAccountBalanceCommand.getId()) + .balance(newBalance) + .transactionId(revertAccountBalanceCommand.getTransactionId()) + .build()); } @CommandHandler public void on(DeleteAccountCommand deleteAccountCommand) throws Exception { if (this.accountRules.eligibleForDelete(this)) { - applyEvent(EventFactory.createEvent(AccountEventType.DELETED, deleteAccountCommand.getId().toHexString())); + applyEvent(AccountDeletedEvent.builder() + .id(deleteAccountCommand.getId().toHexString()) + .build()); return; } logger.warn("Account with ineligible balance requested for delete. Account ID: " + deleteAccountCommand.getId().toHexString()); @@ -91,56 +155,49 @@ public void on(DeleteAccountCommand deleteAccountCommand) throws Exception { @CommandHandler public void on(UpdateAccountCommand updateAccountCommand) throws Exception { - applyEvent(EventFactory.createEvent(AccountEventType.UPDATED, id.toHexString(), updateAccountCommand.getCustomerId())); + applyEvent(AccountUpdatedEvent.builder() + .id(updateAccountCommand.getId().toHexString()) + .customerId(updateAccountCommand.getCustomerId()) + .build()); } @CommandHandler - public void on(StartTransferTransactionCommand command) throws Exception { + public void on(StartTransferCommand command) throws Exception { logger.info("Transfer transaction started from {} successfully", id); - applyEvent(EventFactory.createEvent(AccountEventType.TRANSACTION_STARTED, id.toHexString(), command.getTransactionDto().getDestinationAccountId(), command.getTransactionDto().getAmount(), - command.getTransactionId())); - + applyEvent(TransferTransactionStartedEvent.builder() + .id(command.getId().toHexString()) + .amount(command.getTransactionDto().getAmount()) + .destinationAccountId(command.getTransactionDto().getDestinationAccountId()) + .transactionId(command.getTransactionId()) + .build()); } @CommandHandler - public void on(StartTransferWithdrawCommand command) throws Exception { - if (!this.accountRules.eligibleForDebit(this, command.getAmount())) { - applyEvent(EventFactory.createEvent(AccountEventType.TRANSFER_FAILED_TO_START, id.toHexString(), "", command.getTransactionId(), "")); - throw new AccountNotEligibleForDebitException(id.toHexString(), balance.doubleValue()); - } - - logger.info("Transfer concluded from {} successfully", id); - BigDecimal newBalance = balance.subtract(BigDecimal.valueOf(command.getAmount())); - applyEvent(EventFactory.createEvent(AccountEventType.TRANSFER_WITHDRAW_CONCLUDED, id.toHexString(), newBalance.doubleValue(), - command.getTransactionId())); - } - - @CommandHandler - public void on(ConcludeTransferDepositCommand concludeTransferDepositCommand) throws Exception { - logger.info("Transfer concluded to {} successfully", id); - BigDecimal newBalance = balance.add(BigDecimal.valueOf(concludeTransferDepositCommand.getAmount())); - applyEvent(EventFactory.createEvent(AccountEventType.TRANSFER_CONCLUDED, id.toHexString(), newBalance.doubleValue(), - concludeTransferDepositCommand.getTransactionId())); + public void on(FailTransactionCommand command) throws Exception { + logger.info("Transfer transaction %s failed.", id); + applyEvent(TransferFailedEvent.builder() + .id(command.getId().toHexString()) + .msg(command.getMsg()) + .transactionId(command.getTransactionId()) + .build()); } @CommandHandler public void on(ReleaseAccountCommand releaseAccountCommand) throws Exception { logger.info("Account Released {}", id); - applyEvent(EventFactory.createEvent(AccountEventType.RELEASED, releaseAccountCommand.getId().toHexString(), "", releaseAccountCommand.getTransactionId(), "")); + applyEvent(AccountReleasedEvent.builder() + .id(releaseAccountCommand.getId().toHexString()) + .transactionId(releaseAccountCommand.getTransactionId()) + .build()); } @CommandHandler public void on(CancelTransferCommand cancelTransferCommand) throws Exception { logger.info("Account transfer canceled from {}", id); - BigDecimal newBalance = balance.add(BigDecimal.valueOf(cancelTransferCommand.getAmount())); - applyEvent(EventFactory.createEvent(AccountEventType.TRANSFER_CANCELLED, cancelTransferCommand.getId().toHexString(), - newBalance.doubleValue(), cancelTransferCommand.getTransactionId())); - } - - @CommandHandler - public void on(FailToStartTransferTransactionCommand command) throws Exception { - logger.info("Transaction {} failed to start", command.getTransactionId()); - applyEvent(EventFactory.createEvent(AccountEventType.TRANSFER_FAILED_TO_START, command.getId().toHexString(), "", command.getTransactionId(), "")); + applyEvent(TransferCanceledEvent.builder() + .id(cancelTransferCommand.getId().toHexString()) + .transactionId(cancelTransferCommand.getTransactionId()) + .build()); } @EventSourcingHandler @@ -160,6 +217,12 @@ public void on(AccountCreditedEvent accountCreditedEvent) { balance = BigDecimal.valueOf(accountCreditedEvent.getBalance()); } + @EventSourcingHandler + public void on(BalanceRevertedEvent balanceRevertedEvent) { + balance = BigDecimal.valueOf(balanceRevertedEvent.getBalance()); + activeTransfer = false; + } + @EventSourcingHandler public void on(AccountUpdatedEvent accountUpdatedEvent) { customerId = accountUpdatedEvent.getCustomerId(); @@ -172,24 +235,19 @@ public void on(AccountDeletedEvent accountDeletedEvent) { @EventSourcingHandler public void on(TransferWithdrawConcludedEvent transferWithdrawConcludedEvent) { - activeTransfers++; + activeTransfer = true; balance = BigDecimal.valueOf(transferWithdrawConcludedEvent.getBalance()); } @EventSourcingHandler public void on(TransferDepositConcludedEvent transferDepositConcludedEvent) { - activeTransfers++; + activeTransfer = true; balance = BigDecimal.valueOf(transferDepositConcludedEvent.getBalance()); } - @EventSourcingHandler - public void on(TransferCanceledEvent transferCanceledEvent) { - activeTransfers--; - balance = BigDecimal.valueOf(transferCanceledEvent.getBalance()); - } @EventSourcingHandler public void on(AccountReleasedEvent accountReleasedEvent) { - activeTransfers--; + activeTransfer = false; } public void applyEvent(AccountEvent event) { diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CancelTransferCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CancelTransferCommand.java index e8de6806..ffc141fd 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CancelTransferCommand.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CancelTransferCommand.java @@ -8,11 +8,11 @@ public class CancelTransferCommand extends TransactionCommand{ @TargetAggregateIdentifier private ObjectId id; - private double amount; + private String msg; - public CancelTransferCommand(String id, double amount, String transactionId) { + public CancelTransferCommand(String id, String transactionId, String msg) { super(transactionId); this.id = new ObjectId(id); - this.amount = amount; + this.msg = msg; } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/ConcludeTransferDepositCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/ConcludeTransferDepositCommand.java deleted file mode 100644 index a2499d71..00000000 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/ConcludeTransferDepositCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ultimatesoftware.banking.account.cmd.commands; - -import lombok.Getter; -import org.axonframework.modelling.command.TargetAggregateIdentifier; -import org.bson.types.ObjectId; - -@Getter -public class ConcludeTransferDepositCommand extends TransactionCommand { - @TargetAggregateIdentifier - private ObjectId id; - private double amount; - - public ConcludeTransferDepositCommand(String id, double amount, String transactionId) { - super(transactionId); - this.id = new ObjectId(id); - this.amount = amount; - } - -} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CreditAccountCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CreditAccountCommand.java index 4518b129..b537912f 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CreditAccountCommand.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/CreditAccountCommand.java @@ -4,15 +4,29 @@ import org.axonframework.modelling.command.TargetAggregateIdentifier; import org.bson.types.ObjectId; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; + @Getter public class CreditAccountCommand extends TransactionCommand implements ICommand { @TargetAggregateIdentifier + @NotBlank private ObjectId id; + @Min(value = 0) private double amount; + private boolean transfer; public CreditAccountCommand(String id, double amount, String transactionId) { super(transactionId); this.id = new ObjectId(id); this.amount = amount; + this.transfer = false; + } + + public CreditAccountCommand(String id, double amount, String transactionId, boolean transfer) { + super(transactionId); + this.id = new ObjectId(id); + this.amount = amount; + this.transfer = transfer; } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/DebitAccountCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/DebitAccountCommand.java index cfae7416..beda4eae 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/DebitAccountCommand.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/DebitAccountCommand.java @@ -4,15 +4,27 @@ import org.axonframework.modelling.command.TargetAggregateIdentifier; import org.bson.types.ObjectId; +import javax.validation.constraints.Min; + @Getter public class DebitAccountCommand extends TransactionCommand implements ICommand { @TargetAggregateIdentifier private ObjectId id; + @Min(value = 0) private double amount; + private boolean transfer; public DebitAccountCommand(String id, double amount, String transactionId) { super(transactionId); this.id = new ObjectId(id); this.amount = amount; + this.transfer = false; + } + + public DebitAccountCommand(String id, double amount, String transactionId, boolean transfer) { + super(transactionId); + this.id = new ObjectId(id); + this.amount = amount; + this.transfer = transfer; } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailToStartTransferTransactionCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailToStartTransferTransactionCommand.java deleted file mode 100644 index c3442c21..00000000 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailToStartTransferTransactionCommand.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.ultimatesoftware.banking.account.cmd.commands; - -import com.ultimatesoftware.banking.account.cmd.models.TransactionDto; -import lombok.Getter; -import org.axonframework.modelling.command.TargetAggregateIdentifier; -import org.bson.types.ObjectId; - -@Getter -public class FailToStartTransferTransactionCommand extends TransactionCommand implements ICommand { - @TargetAggregateIdentifier - private ObjectId id; - private TransactionDto transactionDto; - - public FailToStartTransferTransactionCommand(TransactionDto transactionDto) { - super(transactionDto.getId()); - this.id = new ObjectId(transactionDto.getAccountId()); - this.transactionDto = transactionDto; - } -} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailTransactionCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailTransactionCommand.java new file mode 100644 index 00000000..1e614b2e --- /dev/null +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/FailTransactionCommand.java @@ -0,0 +1,25 @@ +package com.ultimatesoftware.banking.account.cmd.commands; + +import lombok.Getter; +import org.axonframework.modelling.command.TargetAggregateIdentifier; +import org.bson.types.ObjectId; + +@Getter +public class FailTransactionCommand extends TransactionCommand implements ICommand { + @TargetAggregateIdentifier + private ObjectId id; + private String msg; + + public FailTransactionCommand(String id, String destinationId, String transactionId) { + super(destinationId); + this.id = new ObjectId(id); + this.transactionId = transactionId; + } + + public FailTransactionCommand(String id, String destinationId, String transactionId, String msg) { + super(destinationId); + this.id = new ObjectId(id); + this.transactionId = transactionId; + this.msg = msg; + } +} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferDepositCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/RevertAccountBalanceCommand.java similarity index 58% rename from domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferDepositCommand.java rename to domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/RevertAccountBalanceCommand.java index 0fef7876..31a27850 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferDepositCommand.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/RevertAccountBalanceCommand.java @@ -5,14 +5,15 @@ import org.bson.types.ObjectId; @Getter -public class StartTransferDepositCommand extends TransactionCommand { +public class RevertAccountBalanceCommand implements ICommand { @TargetAggregateIdentifier private ObjectId id; private double amount; + private String transactionId; - public StartTransferDepositCommand(String id, double amount, String transactionId) { - super(transactionId); - this.id = new ObjectId(id); + public RevertAccountBalanceCommand(String id, double amount, String transactionId) { + this.id = new ObjectId(id); this.amount = amount; + this.transactionId = transactionId; } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferTransactionCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferCommand.java similarity index 75% rename from domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferTransactionCommand.java rename to domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferCommand.java index f20fad31..90072531 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferTransactionCommand.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferCommand.java @@ -6,12 +6,12 @@ import org.bson.types.ObjectId; @Getter -public class StartTransferTransactionCommand extends TransactionCommand implements ICommand { +public class StartTransferCommand extends TransactionCommand implements ICommand { @TargetAggregateIdentifier private ObjectId id; private TransactionDto transactionDto; - public StartTransferTransactionCommand(TransactionDto transactionDto) { + public StartTransferCommand(TransactionDto transactionDto) { super(transactionDto.getId()); this.id = new ObjectId(transactionDto.getAccountId()); this.transactionDto = transactionDto; diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferWithdrawCommand.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferWithdrawCommand.java deleted file mode 100644 index 3843e26c..00000000 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/commands/StartTransferWithdrawCommand.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.ultimatesoftware.banking.account.cmd.commands; - -import lombok.Getter; -import org.axonframework.modelling.command.TargetAggregateIdentifier; -import org.bson.types.ObjectId; - -@Getter -public class StartTransferWithdrawCommand extends TransactionCommand { - @TargetAggregateIdentifier - private ObjectId id; - private double amount; - - public StartTransferWithdrawCommand(String id, double amount, String transactionId) { - super(transactionId); - this.id = new ObjectId(id); - this.amount = amount; - } -} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java index aebc4792..3e908107 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java @@ -3,6 +3,8 @@ import com.ultimatesoftware.banking.account.cmd.sagas.TransactionSaga; import com.ultimatesoftware.banking.api.configuration.SagaManagerConfiguration; import io.micronaut.context.annotation.Infrastructure; +import io.micronaut.discovery.event.ServiceStartedEvent; +import io.micronaut.runtime.event.annotation.EventListener; import org.axonframework.axonserver.connector.AxonServerConfiguration; @Infrastructure @@ -11,4 +13,9 @@ public AccountSagaManagerConfiguration( AxonServerConfiguration axonServerConfiguration) { super(axonServerConfiguration, TransactionSaga.class); } + + @EventListener + public void configure(ServiceStartedEvent event) { + super.configure(); + } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/controllers/AccountsController.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/controllers/AccountsController.java index abed6b3f..f45fa3ea 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/controllers/AccountsController.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/controllers/AccountsController.java @@ -11,7 +11,6 @@ import io.micronaut.http.MediaType; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Delete; -import io.micronaut.http.annotation.Get; import io.micronaut.http.annotation.Post; import io.micronaut.http.annotation.Produces; import io.micronaut.http.annotation.Put; @@ -58,7 +57,7 @@ public HttpResponse credit(@Valid TransactionDto transaction) { @Put("/transfer") public HttpResponse transfer(@Valid TransactionDto transaction) { - StartTransferTransactionCommand command = new StartTransferTransactionCommand(transaction); + StartTransferCommand command = new StartTransferCommand(transaction); this.commandGateway.send(command); return HttpResponse.ok(new MessageDto(SUCCESS)); } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/models/TransactionDto.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/models/TransactionDto.java index fff90664..130f731e 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/models/TransactionDto.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/models/TransactionDto.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonRootName; import lombok.Getter; +import javax.validation.constraints.Min; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; @@ -23,6 +24,7 @@ public class TransactionDto { @NotNull @NotBlank private String customerId; + @Min(value = 0) private double amount; private String destinationAccountId; @@ -31,7 +33,7 @@ public TransactionDto( @JsonProperty("accountId") @NotNull @NotBlank String accountId, @JsonProperty("customerId") @NotNull @NotBlank String customerId, @JsonProperty("amount") double amount, - @JsonProperty("destinationId") String destinationAccountId) { + @JsonProperty("destinationAccountId") String destinationAccountId) { this.id = id; this.accountId = accountId; this.customerId = customerId; diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/rules/StandardAccountRules.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/rules/StandardAccountRules.java index 3384efcb..ae28d5dc 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/rules/StandardAccountRules.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/rules/StandardAccountRules.java @@ -7,7 +7,7 @@ public class StandardAccountRules implements AccountRules { public boolean eligibleForDelete(Account account) { - if (account.getActiveTransfers() == 0 && account.getBalance().compareTo(BigDecimal.ZERO) == 0) { + if (!account.isActiveTransfer() && account.getBalance().compareTo(BigDecimal.ZERO) == 0) { return true; } return false; @@ -15,7 +15,7 @@ public boolean eligibleForDelete(Account account) { public boolean eligibleForDebit(Account account, double debitAmount) { BigDecimal difference = account.getBalance().subtract(BigDecimal.valueOf(debitAmount)); - if (difference.compareTo(BigDecimal.ZERO) >= 0) { + if (!account.isActiveTransfer() && difference.compareTo(BigDecimal.ZERO) >= 0) { return true; } return false; diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java index 1ffb6c77..993ce3b2 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java @@ -18,54 +18,75 @@ public class TransactionSaga { private static final Logger logger = LoggerFactory.getLogger(TransactionSaga.class); + private boolean withdrawCompleted = false; + private boolean depositCompleted = false; private String transactionId; + private double amount; private String sourceAccountId; private String destinationAccountId; - private double amount; @Inject - private CommandGateway commandGateway; + private transient CommandGateway commandGateway; @StartSaga @SagaEventHandler(associationProperty = "transactionId") public void handle(TransferTransactionStartedEvent event) { - transactionId = event.getTransactionId(); - sourceAccountId = event.getId(); - destinationAccountId = event.getDestinationAccountId(); - amount = event.getAmount(); - logger.info("A new transfer transaction is started with id {}, from account {} to account {} and amount {}", - transactionId, sourceAccountId, destinationAccountId, amount); - StartTransferWithdrawCommand command = new StartTransferWithdrawCommand(sourceAccountId, amount, transactionId); - commandGateway.send(command); + event.getTransactionId(), event.getId(), event.getDestinationAccountId(), event.getAmount()); + try { + sourceAccountId = event.getId(); + destinationAccountId = event.getDestinationAccountId(); + amount = event.getAmount(); + transactionId = event.getTransactionId(); + DebitAccountCommand command = + new DebitAccountCommand(event.getId(), event.getAmount(), event.getTransactionId(), + true); + commandGateway.send(command); + } catch (Exception e) { + commandGateway.send(new FailTransactionCommand(sourceAccountId, destinationAccountId, transactionId)); + } } @SagaEventHandler(associationProperty = "transactionId") public void handle(TransferWithdrawConcludedEvent event) { logger.info("Transfer transaction with id {}, did transfer from {} successfully", - transactionId, sourceAccountId); - ConcludeTransferDepositCommand command - = new ConcludeTransferDepositCommand(destinationAccountId, amount, transactionId); - commandGateway.send(command); + event.getTransactionId(), event.getId()); + withdrawCompleted = true; + try { + CreditAccountCommand command + = new CreditAccountCommand(destinationAccountId, event.getBalance(), event.getTransactionId(), true); + commandGateway.send(command); + } catch (Exception e) { + commandGateway.send(new FailTransactionCommand(sourceAccountId, destinationAccountId, transactionId, e.getMessage())); + } } - @EndSaga @SagaEventHandler(associationProperty = "transactionId") - public void handle(TransferFailedToStartEvent event) { - logger.info("Transfer transaction {} failed to start", transactionId); + public void handle(TransferFailedEvent event) { + // change this name and kick of cancel + logger.info("Transfer transaction {} failed to start", event.getTransactionId()); + commandGateway.send(new CancelTransferCommand(sourceAccountId, transactionId, event.getMsg())); } @EndSaga @SagaEventHandler(associationProperty = "transactionId") public void handle(TransferCanceledEvent event) { - logger.info("Transaction {} was canceled.", transactionId); + logger.info("Transaction {} was canceled.", event.getTransactionId()); + if (withdrawCompleted) { + commandGateway.send(new RevertAccountBalanceCommand(sourceAccountId, amount, transactionId)); + } + + if (depositCompleted) { + commandGateway.send(new RevertAccountBalanceCommand(destinationAccountId, amount, transactionId)); + } } @EndSaga @SagaEventHandler(associationProperty = "transactionId") public void handle(TransferDepositConcludedEvent event) { - logger.info("Transaction {} concluded", transactionId); - commandGateway.send(new ReleaseAccountCommand(sourceAccountId, transactionId)); - commandGateway.send(new ReleaseAccountCommand(destinationAccountId, transactionId)); + logger.info("Transaction {} concluded", event.getTransactionId()); + depositCompleted = true; + commandGateway.send(new ReleaseAccountCommand(sourceAccountId, event.getTransactionId())); + commandGateway.send(new ReleaseAccountCommand(destinationAccountId, event.getTransactionId())); } } diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/BalanceRevertedEvent.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/BalanceRevertedEvent.java new file mode 100644 index 00000000..0b84772f --- /dev/null +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/BalanceRevertedEvent.java @@ -0,0 +1,26 @@ +package com.ultimatesoftware.banking.account.events; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import lombok.Builder; +import lombok.Getter; +import org.bson.types.ObjectId; + +import java.math.BigDecimal; + +@Getter +@JsonDeserialize(builder = BalanceRevertedEvent.BalanceRevertedEventBuilder.class) +public class BalanceRevertedEvent extends AccountEvent { + private final double balance; + private final String transactionId; + + @Builder + protected BalanceRevertedEvent(ObjectId id, BigDecimal balance, String transactionId) { + super(id.toHexString()); + this.balance = balance.doubleValue(); + this.transactionId = transactionId; + } + + @JsonPOJOBuilder(withPrefix = "") + public static class BalanceRevertedEventBuilder {} +} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferDepositConcludedEvent.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferDepositConcludedEvent.java index 37a8ea7c..28780a98 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferDepositConcludedEvent.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferDepositConcludedEvent.java @@ -9,11 +9,13 @@ @JsonDeserialize(builder = TransferDepositConcludedEvent.TransferDepositConcludedEventBuilder.class) public class TransferDepositConcludedEvent extends AccountTransactionEvent { private double balance; + private String destinationAccountId; @Builder - protected TransferDepositConcludedEvent(String id, double balance, String transactionId) { + protected TransferDepositConcludedEvent(String id, double balance, String transactionId, String destinationAccountId) { super(id, transactionId); this.balance = balance; + this.destinationAccountId = destinationAccountId; } @JsonPOJOBuilder(withPrefix = "") diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedToStartEvent.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedEvent.java similarity index 66% rename from domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedToStartEvent.java rename to domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedEvent.java index 72699db0..df6d6107 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedToStartEvent.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/TransferFailedEvent.java @@ -3,12 +3,17 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import lombok.Builder; +import lombok.Getter; +@Getter @JsonDeserialize(builder = TransactionFailedEvent.TransactionFailedEventBuilder.class) -public class TransferFailedToStartEvent extends AccountTransactionEvent { +public class TransferFailedEvent extends AccountTransactionEvent { + private String msg; + @Builder - protected TransferFailedToStartEvent(String id, String transactionId) { + protected TransferFailedEvent(String id, String transactionId, String msg) { super(id, transactionId); + this.msg = msg; } @JsonPOJOBuilder(withPrefix = "") diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/AccountEventType.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/AccountEventType.java deleted file mode 100644 index 8607e4f8..00000000 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/AccountEventType.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.ultimatesoftware.banking.account.events.factories; - -public enum AccountEventType { - CREATED, - CREDITED, - DEBITED, - DELETED, - RELEASED, - UPDATED, - TRANSACTION_FAILED, - TRANSFER_CANCELLED, - TRANSFER_CONCLUDED, - TRANSFER_FAILED_TO_START, - TRANSFER_WITHDRAW_CONCLUDED, - TRANSFER_DEPOSIT_CONCLUDED, - TRANSACTION_STARTED -} diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/EventFactory.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/EventFactory.java deleted file mode 100644 index d6d0910d..00000000 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/events/factories/EventFactory.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.ultimatesoftware.banking.account.events.factories; - -import com.ultimatesoftware.banking.account.events.*; - -public class EventFactory { - public static AccountEvent createEvent(AccountEventType type, String id, String customerId, double amount, double balance, String transactionId, String msg, String destinationAccountId) throws Exception { - switch(type) { - case CREATED: - return AccountCreatedEvent.builder() - .id(id) - .customerId(customerId) - .balance(balance) - .build(); - case DELETED: - return AccountDeletedEvent.builder() - .id(id) - .build(); - case CREDITED: - return AccountCreditedEvent.builder() - .id(id) - .customerId(customerId) - .balance(balance) - .creditAmount(amount) - .transactionId(transactionId) - .build(); - case DEBITED: - return AccountDebitedEvent.builder() - .id(id) - .customerId(customerId) - .balance(balance) - .debitAmount(amount) - .transactionId(transactionId) - .build(); - case RELEASED: - return AccountReleasedEvent.builder() - .id(id) - .transactionId(transactionId) - .build(); - case UPDATED: - return AccountUpdatedEvent.builder() - .id(id) - .customerId(customerId) - .build(); - case TRANSACTION_FAILED: - return TransactionFailedEvent.builder() - .id(id) - .transactionId(transactionId) - .msg(msg) - .build(); - case TRANSFER_CANCELLED: - return TransferCanceledEvent.builder() - .id(id) - .transactionId(transactionId) - .balance(balance) - .build(); - case TRANSFER_CONCLUDED: - return TransferDepositConcludedEvent.builder() - .id(id) - .transactionId(transactionId) - .balance(balance) - .build(); - case TRANSFER_FAILED_TO_START: - return TransferFailedToStartEvent.builder() - .id(id) - .transactionId(transactionId) - .build(); - case TRANSACTION_STARTED: - return TransferTransactionStartedEvent.builder() - .id(id) - .destinationAccountId(destinationAccountId) - .amount(amount) - .transactionId(transactionId) - .build(); - case TRANSFER_WITHDRAW_CONCLUDED: - return TransferWithdrawConcludedEvent.builder() - .id(id) - .transactionId(transactionId) - .balance(balance) - .build(); - case TRANSFER_DEPOSIT_CONCLUDED: - return TransferDepositConcludedEvent.builder() - .id(id) - .transactionId(transactionId) - .balance(balance) - .build(); - default: - throw new Exception(String.format("No event of type \"%s\" exists!", type.toString())); - } - } - - public static AccountEvent createEvent(AccountEventType type, String id, String customerId, String transactionId, String msg) throws Exception { - return createEvent(type, id, customerId, 0.0, 0.0, transactionId, msg, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, String transactionId, String msg) throws Exception { - return createEvent(type, id, null, 0.0, 0.0, transactionId, msg, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, double balance, String transactionId) throws Exception { - return createEvent(type, id, null, 0.0, balance, transactionId, null, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, String customerId) throws Exception { - return createEvent(type, id, customerId, 0.0, 0.0, null, null, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, String customerId, double balance) throws Exception { - return createEvent(type, id, customerId, 0.0, balance, null, null, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, String customerId, double amount, double balance, String transactionId) throws Exception { - return createEvent(type, id, customerId, amount, balance, transactionId, null, null); - } - - public static AccountEvent createEvent(AccountEventType type, String id, String destinationAccount, double amount, String transactionId) throws Exception { - return createEvent(type, id, null, amount, 0.0, transactionId, null, destinationAccount); - } - - public static AccountEvent createEvent(AccountEventType type, String id) throws Exception { - return createEvent(type, id, null, 0.0, 0.0, null, null, null); - } -} diff --git a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountControllerTest.java b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountControllerTest.java index 7d4e9e83..c50df827 100644 --- a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountControllerTest.java +++ b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountControllerTest.java @@ -4,7 +4,7 @@ import com.ultimatesoftware.banking.account.cmd.commands.CreateAccountCommand; import com.ultimatesoftware.banking.account.cmd.commands.DebitAccountCommand; import com.ultimatesoftware.banking.account.cmd.commands.DeleteAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.StartTransferTransactionCommand; +import com.ultimatesoftware.banking.account.cmd.commands.FailTransactionCommand; import com.ultimatesoftware.banking.account.cmd.controllers.AccountsController; import com.ultimatesoftware.banking.account.cmd.exceptions.PersonNotFoundException; import com.ultimatesoftware.banking.account.cmd.models.AccountDto; @@ -99,6 +99,6 @@ public void givenCorrectParameters_whenTransactionEndpointCalled_thenCorrectComm accountsController.transfer(transactionDto); // assert - Mockito.verify(commandGateway).send(Matchers.any()); + Mockito.verify(commandGateway).send(Matchers.any()); } } diff --git a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java index a5e992aa..a886d65f 100644 --- a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java +++ b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/isolation/AccountTest.java @@ -1,15 +1,7 @@ package com.ultimatesoftware.banking.account.cmd.tests.unit.isolation; import com.ultimatesoftware.banking.account.cmd.aggregates.Account; -import com.ultimatesoftware.banking.account.cmd.commands.CancelTransferCommand; -import com.ultimatesoftware.banking.account.cmd.commands.ConcludeTransferDepositCommand; -import com.ultimatesoftware.banking.account.cmd.commands.CreditAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.DebitAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.DeleteAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.FailToStartTransferTransactionCommand; -import com.ultimatesoftware.banking.account.cmd.commands.ReleaseAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.StartTransferTransactionCommand; -import com.ultimatesoftware.banking.account.cmd.commands.UpdateAccountCommand; +import com.ultimatesoftware.banking.account.cmd.commands.*; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForCreditException; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForDebitException; import com.ultimatesoftware.banking.account.cmd.exceptions.AccountNotEligibleForDeleteException; @@ -37,6 +29,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) public class AccountTest { @@ -189,19 +182,19 @@ public void givenAccountExists_WhenConcludeTransferDeposit_TransactionStratedEmi .customerId(customerId) .balance(0.0) .build()); - TransactionDto transaction = new TransactionDto("", ObjectId.get().toHexString(), "customer", 10.0, "dest"); // act - account.on(new StartTransferTransactionCommand(transaction)); + account.on(new FailTransactionCommand(ObjectId.get().toHexString(), "s", "s")); // assert - verify(account, times(1)).applyEvent(any(TransferTransactionStartedEvent.class)); + verify(account, times(1)).applyEvent(any(TransferFailedEvent.class)); } @Test public void givenAccountExists_WhenConcludeTransfer_TransferConcludedEmitted() throws Exception { // arrange doNothing().when(account).applyEvent(any()); + doReturn(true).when(accountRules).eligibleForCredit(any(), anyDouble()); account.on(AccountCreatedEvent.builder() .id(id.toHexString()) .customerId(customerId) @@ -209,7 +202,7 @@ public void givenAccountExists_WhenConcludeTransfer_TransferConcludedEmitted() t .build()); // act - account.on(new ConcludeTransferDepositCommand(ObjectId.get().toHexString(), 10.00, "transaction")); + account.on(new CreditAccountCommand(ObjectId.get().toHexString(), 10.00, "transaction", true)); // assert verify(account, times(1)).applyEvent(any(TransferDepositConcludedEvent.class)); @@ -243,7 +236,7 @@ public void givenAccountExists_WhenCancelTransferCommmand_CancelTransferEmitted( .build()); // act - account.on(new CancelTransferCommand(ObjectId.get().toHexString(), 10.0, "trans")); + account.on(new CancelTransferCommand(ObjectId.get().toHexString(), "trans", "msg")); // assert verify(account, times(1)).applyEvent(any(TransferCanceledEvent.class)); @@ -261,10 +254,10 @@ public void givenAccountExists_WhenFailedToStartTransaction_FailedToStartEmitted TransactionDto transaction = new TransactionDto("", ObjectId.get().toHexString(), "customer", 10.0, "dest"); // act - account.on(new FailToStartTransferTransactionCommand(transaction)); + account.on(new FailTransactionCommand(ObjectId.get().toHexString(), "dest", "trans")); // assert - verify(account, times(1)).applyEvent(any(TransferFailedToStartEvent.class)); + verify(account, times(1)).applyEvent(any(TransferFailedEvent.class)); } @@ -384,7 +377,7 @@ public void givenTransferWithdrawConcludedEmitted_whenHandling_ThenIncrementTran .build()); // assert - assertEquals(account.getActiveTransfers(), 1); + assertEquals(account.isActiveTransfer(), true); } @Test @@ -400,7 +393,7 @@ public void givenTransferDepositConcludedEmitted_whenHandling_ThenIncrementTrans .build()); // assert - assertEquals(account.getActiveTransfers(), 1); + assertEquals(account.isActiveTransfer(), true); } @Test @@ -420,7 +413,7 @@ public void givenAccountReleasedEmitted_whenHandling_ThenDecrementTransfers() { .build()); // assert - assertEquals(account.getActiveTransfers(), 0); + assertEquals(account.isActiveTransfer(), false); } @Test @@ -434,13 +427,14 @@ public void givenTransferCanceledEmitted_whenHandling_ThenDecrementTransfers() { .build()); // act - account.on(TransferCanceledEvent.builder() - .id(id.toHexString()) + account.on(BalanceRevertedEvent.builder() + .id(id) + .balance(BigDecimal.valueOf(10.00)) .transactionId(customerId) - .balance(20.0) .build()); // assert - assertEquals(account.getActiveTransfers(), 0); + assertEquals(account.isActiveTransfer(), false); + assertEquals(account.getBalance().doubleValue(), 10.00); } } diff --git a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/social/TransactionSagaTest.java b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/social/TransactionSagaTest.java index 7f035d76..c09429ac 100644 --- a/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/social/TransactionSagaTest.java +++ b/domain-services/account-cmd/src/test/java/com/ultimatesoftware/banking/account/cmd/tests/unit/social/TransactionSagaTest.java @@ -1,9 +1,10 @@ package com.ultimatesoftware.banking.account.cmd.tests.unit.social; -import com.ultimatesoftware.banking.account.cmd.commands.ConcludeTransferDepositCommand; +import com.ultimatesoftware.banking.account.cmd.commands.CreditAccountCommand; +import com.ultimatesoftware.banking.account.cmd.commands.DebitAccountCommand; import com.ultimatesoftware.banking.account.cmd.commands.ReleaseAccountCommand; -import com.ultimatesoftware.banking.account.cmd.commands.StartTransferWithdrawCommand; import com.ultimatesoftware.banking.account.cmd.sagas.TransactionSaga; +import com.ultimatesoftware.banking.account.events.AccountCreatedEvent; import com.ultimatesoftware.banking.account.events.TransferDepositConcludedEvent; import com.ultimatesoftware.banking.account.events.TransferTransactionStartedEvent; import com.ultimatesoftware.banking.account.events.TransferWithdrawConcludedEvent; @@ -30,13 +31,13 @@ public void setUp() { @Test public void onTransactionStarted_startTransferDispatched() { - sagaFixture.givenAggregate(accountId).published() + sagaFixture.givenAggregate(accountId).published(AccountCreatedEvent.builder().id(accountId).balance(0.00).build()) .whenAggregate(accountId).publishes(TransferTransactionStartedEvent.builder() .id(accountId) .destinationAccountId(destinationId) .amount(amount) .transactionId(transactionId)) - .expectDispatchedCommands(new StartTransferWithdrawCommand(accountId, amount, transactionId)); + .expectDispatchedCommands(new DebitAccountCommand(accountId, amount, transactionId, true)); } @@ -51,7 +52,7 @@ public void onTransferWithdrawConcluded_concludeCommandDispatched() { .id(accountId) .balance(amount) .transactionId(transactionId)) - .expectDispatchedCommands(new ConcludeTransferDepositCommand(destinationId, amount, transactionId)); + .expectDispatchedCommands(new CreditAccountCommand(destinationId, amount, transactionId, true)); } @Test diff --git a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/Transaction.java b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/Transaction.java index 756903c0..73690a55 100644 --- a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/Transaction.java +++ b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/Transaction.java @@ -20,7 +20,7 @@ public class Transaction extends Entity { private String accountId; private String customerId; private double amount; - private String destinationAccount; + private String destinationAccountId; private @Setter TransactionStatus status = TransactionStatus.IN_PROGRESS; @BsonCreator @@ -31,14 +31,14 @@ public Transaction( @BsonProperty("accountId") String accountId, @BsonProperty("customerId") String customerId, @BsonProperty("amount") double amount, - @BsonProperty("destinationAccount") String destinationAccount, + @BsonProperty("destinationAccount") String destinationAccountId, @BsonProperty("status") TransactionStatus status) { super(id); this.type = type; this.accountId = accountId; this.customerId = customerId; this.amount = amount; - this.destinationAccount = destinationAccount; + this.destinationAccountId = destinationAccountId; if (status != null) { this.status = status; } diff --git a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/TransferTransactionDto.java b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/TransferTransactionDto.java index 4ddf6713..3755d52a 100644 --- a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/TransferTransactionDto.java +++ b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/models/TransferTransactionDto.java @@ -1,11 +1,14 @@ package com.ultimatesoftware.banking.account.transactions.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import lombok.Builder; import lombok.Getter; @Getter @JsonIgnoreProperties(ignoreUnknown = true) +@JsonDeserialize(builder = TransferTransactionDto.TransferTransactionDtoBuilder.class) public class TransferTransactionDto extends TransactionDto { private String destinationAccountId; @@ -15,4 +18,7 @@ public TransferTransactionDto(String customerId, String accountId, Double amount super(customerId, accountId, amount); this.destinationAccountId = destinationAccountId; } + + @JsonPOJOBuilder(withPrefix = "") + public static class TransferTransactionDtoBuilder {} } diff --git a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/services/TransactionService.java b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/services/TransactionService.java index 74d10a94..c8bfbceb 100644 --- a/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/services/TransactionService.java +++ b/domain-services/account-transactions/src/main/java/com/ultimatesoftware/banking/account/transactions/services/TransactionService.java @@ -45,7 +45,7 @@ public String transfer(TransferTransactionDto transferTransactionDto) .type(TransactionType.TRANSFER) .amount(amount) .customerId(customerId) - .destinationAccount(destAccountId) + .destinationAccountId(destAccountId) .build(); transactionRepository.add(transaction).blockingGet(); diff --git a/domain-services/account-transactions/src/test/java/com/ultimatesoftware/banking/account/transactions/tests/unit/TransactionServiceUnitTest.java b/domain-services/account-transactions/src/test/java/com/ultimatesoftware/banking/account/transactions/tests/unit/TransactionServiceUnitTest.java index 04ae49b4..ac7bedd3 100644 --- a/domain-services/account-transactions/src/test/java/com/ultimatesoftware/banking/account/transactions/tests/unit/TransactionServiceUnitTest.java +++ b/domain-services/account-transactions/src/test/java/com/ultimatesoftware/banking/account/transactions/tests/unit/TransactionServiceUnitTest.java @@ -252,7 +252,7 @@ public void givenAcountAndCustomerExist_whenTransferingAValidAmount_thenTheTrans Transaction transaction = transactionCaptor.getValue(); assertEquals(TestConstants.ACCOUNT_ID.toHexString(), transaction.getAccountId()); assertEquals(TestConstants.CUSTOMER_ID.toHexString(), transaction.getCustomerId()); - assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccount()); + assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccountId()); assertEquals(5.00, transaction.getAmount(), 0.001); assertEquals(TransactionStatus.IN_PROGRESS, transaction.getStatus()); } @@ -303,7 +303,7 @@ public void givenAcountAndCustomerExist_whenTransferingATheEntireBalance_thenThe Transaction transaction = transactionCaptor.getValue(); assertEquals(TestConstants.ACCOUNT_ID.toHexString(), transaction.getAccountId()); assertEquals(TestConstants.CUSTOMER_ID.toHexString(), transaction.getCustomerId()); - assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccount()); + assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccountId()); assertEquals(5.00, transaction.getAmount(), 0.001); assertEquals(TransactionStatus.IN_PROGRESS, transaction.getStatus()); } @@ -341,7 +341,7 @@ public void givenAcountAndCustomerExist_whenTransferingSlightlyLessThanTheBalanc Transaction transaction = transactionCaptor.getValue(); assertEquals(TestConstants.ACCOUNT_ID.toHexString(), transaction.getAccountId()); assertEquals(TestConstants.CUSTOMER_ID.toHexString(), transaction.getCustomerId()); - assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccount()); + assertEquals(TestConstants.DESTINATION_ID.toHexString(), transaction.getDestinationAccountId()); assertEquals(4.99, transaction.getAmount(), 0.001); assertEquals(TransactionStatus.IN_PROGRESS, transaction.getStatus()); } diff --git a/domain-services/people-details/src/main/java/com/ultimatesoftware/banking/people.details/eventhandlers/PersonDetailsEventHandler.java b/domain-services/people-details/src/main/java/com/ultimatesoftware/banking/people.details/eventhandlers/PersonDetailsEventHandler.java index 87c00249..2f53110f 100644 --- a/domain-services/people-details/src/main/java/com/ultimatesoftware/banking/people.details/eventhandlers/PersonDetailsEventHandler.java +++ b/domain-services/people-details/src/main/java/com/ultimatesoftware/banking/people.details/eventhandlers/PersonDetailsEventHandler.java @@ -12,15 +12,14 @@ import org.axonframework.eventhandling.EventHandler; import org.bson.types.ObjectId; -import javax.inject.Singleton; - @Infrastructure public class PersonDetailsEventHandler extends AxonEventHandler { - private Repository mongoRepository; + private final Repository mongoRepository; public PersonDetailsEventHandler(Repository mongoRepository, AxonServerConfiguration axonServerConfiguration) { super(axonServerConfiguration); this.mongoRepository = mongoRepository; + LOG.info("Event handler on service started"); } @EventListener diff --git a/domain-services/people-details/src/main/resources/application.yml b/domain-services/people-details/src/main/resources/application.yml index 96c342a4..3baccf58 100644 --- a/domain-services/people-details/src/main/resources/application.yml +++ b/domain-services/people-details/src/main/resources/application.yml @@ -13,6 +13,11 @@ micronaut: mongodb: uri: mongodb://${MONGO_HOST:localhost}:${MONGO_PORT:27017} +axon: + axonserver: + servers: ${AXON_HOST:localhost} + component-name: account-query + consul: client: registration: diff --git a/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java b/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java index fb98c3ca..c36f8f07 100644 --- a/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java +++ b/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java @@ -19,6 +19,9 @@ public class SagaManagerConfiguration { public SagaManagerConfiguration(AxonServerConfiguration axonServerConfiguration, Class type) { this.axonServerConfiguration = axonServerConfiguration; this.type = type; + } + + public void configure() { LOG.info("Configuring Axon server for Saga Manager"); configurer = DefaultConfigurer.defaultConfiguration() .registerComponent(AxonServerConfiguration.class, c -> axonServerConfiguration) From e5cf95b9aada314c391773bf42ecce5b7f9ccb10 Mon Sep 17 00:00:00 2001 From: Justin Phillips Date: Mon, 1 Apr 2019 17:12:25 -0400 Subject: [PATCH 4/5] Added Axon Server config to people domain compose. --- docker-compose.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 3c2a3cc6..c328c4bd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -63,6 +63,7 @@ services: environment: - CONSUL_HOST=discovery-service - MONGO_HOST=mongo + - AXON_HOST=axonserver - HOST_PORT=8085 - ES_JAVA_OPTS= "-Xms450mb -Xmx450mb" @@ -75,6 +76,7 @@ services: environment: - CONSUL_HOST=discovery-service - MONGO_HOST=mongo + - AXON_HOST=axonserver - HOST_PORT=8087 - ES_JAVA_OPTS= "-Xms450mb -Xmx450mb" @@ -87,6 +89,7 @@ services: environment: - CONSUL_HOST=discovery-service - MONGO_HOST=mongo + - AXON_HOST=axonserver - HOST_PORT=8088 - ES_JAVA_OPTS= "-Xms450mb -Xmx450mb" From 7d7ef6df065d445bde22883e07b56e0e734482f0 Mon Sep 17 00:00:00 2001 From: Justin Phillips Date: Mon, 1 Apr 2019 17:34:05 -0400 Subject: [PATCH 5/5] Registered primary gateway with Axon injection service. --- docker-compose-sub-domain-testing.yml | 30 +++++++++---------- .../AccountSagaManagerConfiguration.java | 5 ++-- .../account/cmd/sagas/TransactionSaga.java | 2 -- .../SagaManagerConfiguration.java | 6 +++- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/docker-compose-sub-domain-testing.yml b/docker-compose-sub-domain-testing.yml index b914511e..146337ae 100644 --- a/docker-compose-sub-domain-testing.yml +++ b/docker-compose-sub-domain-testing.yml @@ -32,21 +32,21 @@ services: - ./docker/wiremock/people:/home/wiremock restart: on-failure - account-cmd: - build: domain-services/account-cmd/ - mem_limit: 400m - ports: - - "8082:8082" - restart: on-failure - environment: - - PEOPLE_GATEWAY=people-gateway-mock - - CONSUL_HOST=discovery-service - - MONGO_HOST=mongo - - AXON_HOST=axonserver - - HOST_PORT=8082 - depends_on: - - discovery-service - - axonserver +# account-cmd: +# build: domain-services/account-cmd/ +# mem_limit: 400m +# ports: +# - "8082:8082" +# restart: on-failure +# environment: +# - PEOPLE_GATEWAY=people-gateway-mock +# - CONSUL_HOST=discovery-service +# - MONGO_HOST=mongo +# - AXON_HOST=axonserver +# - HOST_PORT=8082 +# depends_on: +# - discovery-service +# - axonserver account-query: build: domain-services/account-query/ diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java index 3e908107..f1d1013f 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/configuration/AccountSagaManagerConfiguration.java @@ -6,12 +6,13 @@ import io.micronaut.discovery.event.ServiceStartedEvent; import io.micronaut.runtime.event.annotation.EventListener; import org.axonframework.axonserver.connector.AxonServerConfiguration; +import org.axonframework.commandhandling.gateway.CommandGateway; @Infrastructure public class AccountSagaManagerConfiguration extends SagaManagerConfiguration { public AccountSagaManagerConfiguration( - AxonServerConfiguration axonServerConfiguration) { - super(axonServerConfiguration, TransactionSaga.class); + AxonServerConfiguration axonServerConfiguration, CommandGateway commandGateway) { + super(axonServerConfiguration, commandGateway, TransactionSaga.class); } @EventListener diff --git a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java index 993ce3b2..8826a746 100644 --- a/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java +++ b/domain-services/account-cmd/src/main/java/com/ultimatesoftware/banking/account/cmd/sagas/TransactionSaga.java @@ -13,8 +13,6 @@ import javax.inject.Inject; -@Prototype -@NoArgsConstructor public class TransactionSaga { private static final Logger logger = LoggerFactory.getLogger(TransactionSaga.class); diff --git a/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java b/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java index c36f8f07..c3b649fc 100644 --- a/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java +++ b/libs/api/src/main/java/com/ultimatesoftware/banking/api/configuration/SagaManagerConfiguration.java @@ -3,6 +3,7 @@ import com.ultimatesoftware.banking.api.operations.AxonEventHandler; import io.micronaut.context.annotation.Requires; import org.axonframework.axonserver.connector.AxonServerConfiguration; +import org.axonframework.commandhandling.gateway.CommandGateway; import org.axonframework.config.Configuration; import org.axonframework.config.DefaultConfigurer; import org.slf4j.Logger; @@ -15,16 +16,19 @@ public class SagaManagerConfiguration { private Class type; private Configuration configurer; private final AxonServerConfiguration axonServerConfiguration; + private final CommandGateway commandGateway; - public SagaManagerConfiguration(AxonServerConfiguration axonServerConfiguration, Class type) { + public SagaManagerConfiguration(AxonServerConfiguration axonServerConfiguration, CommandGateway commandGateway, Class type) { this.axonServerConfiguration = axonServerConfiguration; this.type = type; + this.commandGateway = commandGateway; } public void configure() { LOG.info("Configuring Axon server for Saga Manager"); configurer = DefaultConfigurer.defaultConfiguration() .registerComponent(AxonServerConfiguration.class, c -> axonServerConfiguration) + .registerComponent(CommandGateway.class, c -> commandGateway) .eventProcessing(eventProcessingConfigurer -> eventProcessingConfigurer .registerSaga(type)).start(); LOG.info("Axon Saga Manager on service started");