From 65381f7f502f14e6e038bb4259e1b79430b588ca Mon Sep 17 00:00:00 2001 From: Michal Zeman <> Date: Sat, 30 Nov 2019 20:12:15 +0100 Subject: [PATCH] http api for account --- bank-account/account-api/build.gradle | 1 + .../api/AccountApplicationService.java | 19 +++++ .../account/api/AccountHandler.java | 62 ++++++++++++++ .../reactorddd/account/api/AccountQuery.java | 4 + .../api/model/CreateAccountRequest.java | 18 +++++ .../api/model/CreateAccountResponse.java | 22 +++++ .../api/model/DepositMoneyRequest.java | 18 +++++ .../api/model/DepositMoneyResponse.java | 22 +++++ .../api/model/WithdrawMoneyRequest.java | 18 +++++ .../api/model/WithdrawMoneyResponse.java | 22 +++++ .../account/domain/command/CreateAccount.java | 4 + .../account/domain/command/DepositMoney.java | 4 + .../account/domain/command/WithdrawMoney.java | 5 ++ .../account/domain/event/AccountCreated.java | 4 + .../account/domain/event/MoneyDeposited.java | 4 + .../account/domain/event/MoneyWithdrawn.java | 4 + bank-account/account-impl/build.gradle | 1 + .../impl/AccountApplicationServiceImpl.java | 46 +++++++++++ .../account/wiring/AccountConfiguration.java | 46 +++++++++++ .../BankAccountAppConfiguration.java | 31 +++++++ build.gradle | 44 +++++++++- .../common/api/command/CommandHandler.java | 4 +- .../common/api/command/CommandResponse.java | 15 ++++ .../ddd/common/api/command/CommandResult.java | 10 +-- .../ddd/common/api/error/ErrorMessage.java | 17 ++++ .../ddd/common/api/event/EventApplier.java | 2 +- .../ddd/common/api/view/DomainView.java | 5 ++ .../{ => bus}/ApplicationMessageBus.java | 2 +- .../impl/ApplicationMessageBusImpl.java | 7 +- .../common/components/http/ErrorMessage.java | 20 +++++ .../components/http/HttpErrorHandler.java | 20 +++++ .../common/components/http/HttpHandler.java | 16 ++++ .../persistance/view/ViewRepository.java | 16 ---- .../persistance/view/ViewRepositoryImpl.java | 50 ------------ .../build.gradle | 0 .../persistance/aggregate/AggregateActor.java | 5 +- .../aggregate/AggregateFacade.java | 12 +++ .../aggregate/AggregateFactory.java | 0 .../aggregate/AggregateRepository.java | 5 +- .../aggregate/impl/AggregateActorImpl.java | 28 +++---- .../aggregate/impl/AggregateFacadeImpl.java | 60 ++++++++++++++ .../impl/AggregateRepositoryImpl.java | 22 +++-- .../persistance/view/impl/ViewRepository.java | 19 +++++ .../view/impl/impl/ViewRepositoryImpl.java | 57 +++++++++++++ .../aggregate/impl/AggregateActorTest.java | 12 +-- .../impl/AggregateRepositoryImplTest.java | 2 +- .../aggregate/impl/TestAggregate.java | 0 .../aggregate/impl/TestAggregateCommand.java | 0 .../aggregate/impl/TestAggregateEvent.java | 0 .../aggregate/impl/TestFunctions.java | 36 +++++---- .../persistance/model/TestView.java | 80 +++++++++++++++++++ .../view/impl/ViewRepositoryImplTest.java | 74 +++++++++++++++++ settings.gradle | 5 +- 53 files changed, 864 insertions(+), 136 deletions(-) create mode 100644 bank-account/account-api/build.gradle create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountApplicationService.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountHandler.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountQuery.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountRequest.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountResponse.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyRequest.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyResponse.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyRequest.java create mode 100644 bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyResponse.java create mode 100644 bank-account/account-impl/build.gradle create mode 100644 bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/impl/AccountApplicationServiceImpl.java create mode 100644 bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/wiring/AccountConfiguration.java create mode 100644 bank-account/bank-account-application/src/main/java/com/mz/reactor/ddd/reactorddd/application/BankAccountAppConfiguration.java create mode 100644 common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResponse.java create mode 100644 common-api/src/main/java/com/mz/reactor/ddd/common/api/error/ErrorMessage.java create mode 100644 common-api/src/main/java/com/mz/reactor/ddd/common/api/view/DomainView.java rename common-components/src/main/java/com/mz/reactor/ddd/common/components/{ => bus}/ApplicationMessageBus.java (90%) rename common-components/src/main/java/com/mz/reactor/ddd/common/components/{ => bus}/impl/ApplicationMessageBusImpl.java (80%) create mode 100644 common-components/src/main/java/com/mz/reactor/ddd/common/components/http/ErrorMessage.java create mode 100644 common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpErrorHandler.java create mode 100644 common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpHandler.java delete mode 100644 common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepository.java delete mode 100644 common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepositoryImpl.java rename {common-persistance => common-persistence}/build.gradle (100%) rename {common-persistance => common-persistence}/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java (65%) create mode 100644 common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFacade.java rename {common-persistance => common-persistence}/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFactory.java (100%) rename {common-persistance => common-persistence}/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java (59%) rename {common-persistance => common-persistence}/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java (75%) create mode 100644 common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateFacadeImpl.java rename {common-persistance => common-persistence}/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java (75%) create mode 100644 common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepository.java create mode 100644 common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/impl/ViewRepositoryImpl.java rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java (93%) rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java (97%) rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregate.java (100%) rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateCommand.java (100%) rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateEvent.java (100%) rename {common-persistance => common-persistence}/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java (50%) create mode 100644 common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/model/TestView.java create mode 100644 common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepositoryImplTest.java diff --git a/bank-account/account-api/build.gradle b/bank-account/account-api/build.gradle new file mode 100644 index 0000000..d5bf60d --- /dev/null +++ b/bank-account/account-api/build.gradle @@ -0,0 +1 @@ +description('account api module') \ No newline at end of file diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountApplicationService.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountApplicationService.java new file mode 100644 index 0000000..1e8b4fe --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountApplicationService.java @@ -0,0 +1,19 @@ +package com.mz.reactor.ddd.reactorddd.account.api; + +import com.mz.reactor.ddd.reactorddd.account.domain.command.CreateAccount; +import com.mz.reactor.ddd.reactorddd.account.domain.command.DepositMoney; +import com.mz.reactor.ddd.reactorddd.account.domain.command.WithdrawMoney; +import com.mz.reactor.ddd.reactorddd.account.domain.event.AccountCreated; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyDeposited; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyWithdrawn; +import reactor.core.publisher.Mono; + +public interface AccountApplicationService { + + Mono execute(CreateAccount cmd); + + Mono execute(DepositMoney cmd); + + Mono execute(WithdrawMoney cmd); + +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountHandler.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountHandler.java new file mode 100644 index 0000000..4e00773 --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountHandler.java @@ -0,0 +1,62 @@ +package com.mz.reactor.ddd.reactorddd.account.api; + +import com.mz.reactor.ddd.common.components.http.HttpHandler; +import com.mz.reactor.ddd.reactorddd.account.api.model.*; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import static org.springframework.web.reactive.function.server.RequestPredicates.*; + +@Component +public class AccountHandler implements HttpHandler { + + private final AccountApplicationService service; + + public AccountHandler(AccountApplicationService service) { + this.service = service; + } + + public Mono createAccount(ServerRequest request) { + return request + .bodyToMono(CreateAccountRequest.class) + .map(CreateAccountRequest::payload) + .flatMap(service::execute) + .map(CreateAccountResponse::from) + .flatMap(this::mapToResponse); + } + + public Mono depositMoney(ServerRequest request) { + return request + .bodyToMono(DepositMoneyRequest.class) + .map(DepositMoneyRequest::payload) + .flatMap(service::execute) + .map(DepositMoneyResponse::from) + .flatMap(this::mapToResponse); + } + + public Mono withdrawMoney(ServerRequest request) { + return request + .bodyToMono(WithdrawMoneyRequest.class) + .map(WithdrawMoneyRequest::payload) + .flatMap(service::execute) + .map(WithdrawMoneyResponse::from) + .flatMap(this::mapToResponse); + } + + public RouterFunction route() { + var route = RouterFunctions + .route(POST("").and(accept(MediaType.APPLICATION_JSON_UTF8)), this::createAccount) + .andRoute(PUT("/moneys/withdraw").and(accept(MediaType.APPLICATION_JSON_UTF8)), this::withdrawMoney) + .andRoute(PUT("/moneys/deposit").and(accept(MediaType.APPLICATION_JSON_UTF8)), this::withdrawMoney); + + return RouterFunctions.route() + .nest(path("/accounts"), () -> route) + .build(); + } + +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountQuery.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountQuery.java new file mode 100644 index 0000000..e4da423 --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/AccountQuery.java @@ -0,0 +1,4 @@ +package com.mz.reactor.ddd.reactorddd.account.api; + +public interface AccountQuery { +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountRequest.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountRequest.java new file mode 100644 index 0000000..45026db --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountRequest.java @@ -0,0 +1,18 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.command.CreateAccount; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableCreateAccountRequest.class) +@JsonDeserialize(as = ImmutableCreateAccountRequest.class) +public interface CreateAccountRequest { + + CreateAccount payload(); + + static ImmutableCreateAccountRequest.Builder builder() { + return ImmutableCreateAccountRequest.builder(); + } +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountResponse.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountResponse.java new file mode 100644 index 0000000..777d3cd --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/CreateAccountResponse.java @@ -0,0 +1,22 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.event.AccountCreated; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableCreateAccountResponse.class) +@JsonDeserialize(as = ImmutableCreateAccountResponse.class) +public interface CreateAccountResponse { + + AccountCreated payload(); + + static ImmutableCreateAccountResponse.Builder builder() { + return ImmutableCreateAccountResponse.builder(); + } + + static CreateAccountResponse from(AccountCreated payload) { + return builder().payload(payload).build(); + } +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyRequest.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyRequest.java new file mode 100644 index 0000000..4442df5 --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyRequest.java @@ -0,0 +1,18 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.command.DepositMoney; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableDepositMoneyRequest.class) +@JsonDeserialize(as = ImmutableDepositMoneyRequest.class) +public interface DepositMoneyRequest { + + DepositMoney payload(); + + static ImmutableDepositMoneyRequest.Builder builder() { + return ImmutableDepositMoneyRequest.builder(); + } +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyResponse.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyResponse.java new file mode 100644 index 0000000..9c3b9bf --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/DepositMoneyResponse.java @@ -0,0 +1,22 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyDeposited; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableDepositMoneyResponse.class) +@JsonDeserialize(as = ImmutableDepositMoneyResponse.class) +public interface DepositMoneyResponse { + + MoneyDeposited payload(); + + static ImmutableDepositMoneyResponse.Builder builder() { + return ImmutableDepositMoneyResponse.builder(); + } + + static DepositMoneyResponse from(MoneyDeposited payload) { + return builder().payload(payload).build(); + } +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyRequest.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyRequest.java new file mode 100644 index 0000000..2283143 --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyRequest.java @@ -0,0 +1,18 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.command.WithdrawMoney; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableWithdrawMoneyRequest.class) +@JsonDeserialize(as = ImmutableWithdrawMoneyRequest.class) +public interface WithdrawMoneyRequest { + + WithdrawMoney payload(); + + static ImmutableWithdrawMoneyRequest.Builder builder() { + return ImmutableWithdrawMoneyRequest.builder(); + } +} diff --git a/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyResponse.java b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyResponse.java new file mode 100644 index 0000000..8086ef0 --- /dev/null +++ b/bank-account/account-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/api/model/WithdrawMoneyResponse.java @@ -0,0 +1,22 @@ +package com.mz.reactor.ddd.reactorddd.account.api.model; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyWithdrawn; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableWithdrawMoneyResponse.class) +@JsonDeserialize(as = ImmutableWithdrawMoneyResponse.class) +public interface WithdrawMoneyResponse { + + MoneyWithdrawn payload(); + + static ImmutableWithdrawMoneyResponse.Builder builder() { + return ImmutableWithdrawMoneyResponse.builder(); + } + + static WithdrawMoneyResponse from(MoneyWithdrawn moneyWithdrawn) { + return builder().payload(moneyWithdrawn).build(); + } +} diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/CreateAccount.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/CreateAccount.java index e6c8b5d..42841fe 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/CreateAccount.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/CreateAccount.java @@ -1,10 +1,14 @@ package com.mz.reactor.ddd.reactorddd.account.domain.command; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableCreateAccount.class) +@JsonDeserialize(as = ImmutableCreateAccount.class) public interface CreateAccount extends AccountCommand { BigDecimal balance(); diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/DepositMoney.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/DepositMoney.java index 9a5a210..1ccca8b 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/DepositMoney.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/DepositMoney.java @@ -1,10 +1,14 @@ package com.mz.reactor.ddd.reactorddd.account.domain.command; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableDepositMoney.class) +@JsonDeserialize(as = ImmutableDepositMoney.class) public interface DepositMoney extends AccountCommand { BigDecimal amount(); diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/WithdrawMoney.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/WithdrawMoney.java index 6c6b72f..99913d7 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/WithdrawMoney.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/command/WithdrawMoney.java @@ -1,10 +1,15 @@ package com.mz.reactor.ddd.reactorddd.account.domain.command; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.mz.reactor.ddd.reactorddd.account.domain.event.ImmutableMoneyWithdrawn; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableWithdrawMoney.class) +@JsonDeserialize(as = ImmutableWithdrawMoney.class) public interface WithdrawMoney extends AccountCommand { BigDecimal amount(); diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/AccountCreated.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/AccountCreated.java index b759e3c..5703fee 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/AccountCreated.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/AccountCreated.java @@ -1,11 +1,15 @@ package com.mz.reactor.ddd.reactorddd.account.domain.event; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.mz.reactor.ddd.reactorddd.account.domain.command.CreateAccount; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableAccountCreated.class) +@JsonDeserialize(as = ImmutableAccountCreated.class) public interface AccountCreated extends AccountEvent { BigDecimal balance(); diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyDeposited.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyDeposited.java index 22ae486..defe7a6 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyDeposited.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyDeposited.java @@ -1,10 +1,14 @@ package com.mz.reactor.ddd.reactorddd.account.domain.event; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableMoneyDeposited.class) +@JsonDeserialize(as = ImmutableMoneyDeposited.class) public interface MoneyDeposited extends AccountEvent { BigDecimal amount(); diff --git a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyWithdrawn.java b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyWithdrawn.java index 4c31872..ec7644e 100644 --- a/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyWithdrawn.java +++ b/bank-account/account-domain-api/src/main/java/com/mz/reactor/ddd/reactorddd/account/domain/event/MoneyWithdrawn.java @@ -1,11 +1,15 @@ package com.mz.reactor.ddd.reactorddd.account.domain.event; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.mz.reactor.ddd.reactorddd.account.domain.command.WithdrawMoney; import org.immutables.value.Value; import java.math.BigDecimal; @Value.Immutable +@JsonSerialize(as = ImmutableMoneyWithdrawn.class) +@JsonDeserialize(as = ImmutableMoneyWithdrawn.class) public interface MoneyWithdrawn extends AccountEvent { BigDecimal amount(); diff --git a/bank-account/account-impl/build.gradle b/bank-account/account-impl/build.gradle new file mode 100644 index 0000000..257e51a --- /dev/null +++ b/bank-account/account-impl/build.gradle @@ -0,0 +1 @@ +description('account implementation of infrastructure layer') \ No newline at end of file diff --git a/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/impl/AccountApplicationServiceImpl.java b/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/impl/AccountApplicationServiceImpl.java new file mode 100644 index 0000000..549d2ee --- /dev/null +++ b/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/impl/AccountApplicationServiceImpl.java @@ -0,0 +1,46 @@ +package com.mz.reactor.ddd.reactorddd.account.impl; + +import com.mz.reactor.ddd.common.components.bus.ApplicationMessageBus; +import com.mz.reactor.ddd.reactorddd.account.api.AccountApplicationService; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountAggregate; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountState; +import com.mz.reactor.ddd.reactorddd.account.domain.command.AccountCommand; +import com.mz.reactor.ddd.reactorddd.account.domain.command.CreateAccount; +import com.mz.reactor.ddd.reactorddd.account.domain.command.DepositMoney; +import com.mz.reactor.ddd.reactorddd.account.domain.command.WithdrawMoney; +import com.mz.reactor.ddd.reactorddd.account.domain.event.AccountCreated; +import com.mz.reactor.ddd.reactorddd.account.domain.event.AccountEvent; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyDeposited; +import com.mz.reactor.ddd.reactorddd.account.domain.event.MoneyWithdrawn; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.AggregateFacade; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +@Service +public class AccountApplicationServiceImpl implements AccountApplicationService { + + private final AggregateFacade aggregateFacade; + + public AccountApplicationServiceImpl( + ApplicationMessageBus bus, + @Qualifier("accountAggregateFacade") AggregateFacade aggregateFacade + ) { + this.aggregateFacade = aggregateFacade; + } + + @Override + public Mono execute(CreateAccount cmd) { + return this.aggregateFacade.executeReturnEvent(cmd, cmd.aggregateId()).cast(AccountCreated.class); + } + + @Override + public Mono execute(DepositMoney cmd) { + return this.aggregateFacade.executeReturnEvent(cmd, cmd.aggregateId()).cast(MoneyDeposited.class); + } + + @Override + public Mono execute(WithdrawMoney cmd) { + return this.aggregateFacade.executeReturnEvent(cmd, cmd.aggregateId()).cast(MoneyWithdrawn.class); + } +} diff --git a/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/wiring/AccountConfiguration.java b/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/wiring/AccountConfiguration.java new file mode 100644 index 0000000..3809686 --- /dev/null +++ b/bank-account/account-impl/src/main/java/com/mz/reactor/ddd/reactorddd/account/wiring/AccountConfiguration.java @@ -0,0 +1,46 @@ +package com.mz.reactor.ddd.reactorddd.account.wiring; + +import com.mz.reactor.ddd.common.api.valueobject.Id; +import com.mz.reactor.ddd.common.components.bus.ApplicationMessageBus; +import com.mz.reactor.ddd.common.components.bus.impl.ApplicationMessageBusImpl; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountAggregate; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountCommandHandler; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountEventApplier; +import com.mz.reactor.ddd.reactorddd.account.domain.AccountState; +import com.mz.reactor.ddd.reactorddd.account.domain.command.AccountCommand; +import com.mz.reactor.ddd.reactorddd.account.domain.event.AccountEvent; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.AggregateFacade; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.AggregateRepository; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.impl.AggregateFacadeImpl; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.impl.AggregateRepositoryImpl; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +import java.util.function.Function; + +@Configuration +public class AccountConfiguration { + + public static final String ACCOUNT_AGGREGATE_REPOSITORY = "accountAggregateRepository"; + + private final AccountEventApplier accountEventApplier = new AccountEventApplier(); + private final AccountCommandHandler accountCommandHandler = new AccountCommandHandler(); + private final Function aggregateFactory = id -> new AccountAggregate(id.toString()); + private final Function stateFactory = AccountAggregate::getState; + + @Bean(ACCOUNT_AGGREGATE_REPOSITORY) + public AggregateRepository getAggregateRepository() { + return new AggregateRepositoryImpl<>(accountCommandHandler, accountEventApplier, aggregateFactory, stateFactory); + } + + @Bean("accountAggregateFacade") + public AggregateFacade getAggregateFacade( + @Qualifier(ACCOUNT_AGGREGATE_REPOSITORY) AggregateRepository aggregateRepository, + ApplicationMessageBus bus + ) { + return new AggregateFacadeImpl<>(aggregateRepository, bus::publishMessage, s -> {}); + } + +} diff --git a/bank-account/bank-account-application/src/main/java/com/mz/reactor/ddd/reactorddd/application/BankAccountAppConfiguration.java b/bank-account/bank-account-application/src/main/java/com/mz/reactor/ddd/reactorddd/application/BankAccountAppConfiguration.java new file mode 100644 index 0000000..951b03f --- /dev/null +++ b/bank-account/bank-account-application/src/main/java/com/mz/reactor/ddd/reactorddd/application/BankAccountAppConfiguration.java @@ -0,0 +1,31 @@ +package com.mz.reactor.ddd.reactorddd.application; + +import com.mz.reactor.ddd.common.components.http.HttpErrorHandler; +import com.mz.reactor.ddd.reactorddd.account.api.AccountHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +@Configuration +@ComponentScan(basePackages = {"com.mz.reactor.ddd.*"}) +@Import({com.mz.reactor.ddd.reactorddd.account.wiring.AccountConfiguration.class}) +public class BankAccountAppConfiguration { + + @Bean + public RouterFunction statisticRoute(AccountHandler handler) { + return RouterFunctions.route() + .add(handler.route()) + .GET("/health", req -> ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON_UTF8) + .body(Mono.just("Tick"), String.class)) + .onError(Throwable.class, HttpErrorHandler.FN::onError) + .build(); + } + +} diff --git a/build.gradle b/build.gradle index 24560e6..eba418c 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,11 @@ project(':bank-account:bank-account-application') { dependencies { implementation 'org.springframework.boot:spring-boot-starter-webflux' - // https://mvnrepository.com/artifact/io.projectreactor/reactor-core + implementation project(':common-api') + implementation project(':common-components') + implementation project(':common-persistence') + implementation project(':bank-account:account-impl') + implementation project(':bank-account:account-api') implementation project(':bank-account:account-domain') implementation project(':bank-account:transaction-domain') testImplementation 'org.springframework.boot:spring-boot-starter-test' @@ -100,6 +104,27 @@ project(':bank-account:account-domain-api') { } } +project(':bank-account:account-api') { + dependencies { + api project(':common-api') + api project(':common-components') + api project(':shared-spring-dependecies') + api project(':bank-account:account-domain-api') + } +} + +project(':bank-account:account-impl') { + dependencies { + api project(':common-api') + api project(':common-components') + api project(':common-persistence') + api project(':shared-spring-dependecies') + implementation project(':bank-account:account-domain-api') + implementation project(':bank-account:account-api') + implementation project(':bank-account:account-domain') + } +} + project(':bank-account:transaction-domain') { dependencies { api project(':common-api') @@ -116,11 +141,23 @@ project(':bank-account:transaction-domain-api') { project(':shared-dependencies') { dependencies { api 'org.immutables:value:2.7.5' + api 'com.fasterxml.jackson.core:jackson-databind:2.9.8' api group: 'org.apache.commons', name: 'commons-lang3', version: '3.9' } } -project(':common-persistance') { +project(':shared-spring-dependecies') { + apply plugin: 'io.spring.dependency-management' + + dependencies { + api group: 'io.projectreactor', name: 'reactor-core' + api 'org.springframework:spring-context' + api 'org.springframework:spring-webflux' + api 'org.springframework:spring-core' + } +} + +project(':common-persistence') { dependencies { api project(':common-api') @@ -134,8 +171,7 @@ project(':common-components') { dependencies { api project(':common-api') - implementation group: 'io.projectreactor', name: 'reactor-core' - implementation 'org.springframework:spring-context' + api project(':shared-spring-dependecies') testImplementation 'io.projectreactor:reactor-test' } } diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandHandler.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandHandler.java index 9bbb3d5..01d07ed 100644 --- a/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandHandler.java +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandHandler.java @@ -1,8 +1,10 @@ package com.mz.reactor.ddd.common.api.command; +import com.mz.reactor.ddd.common.api.event.DomainEvent; + @FunctionalInterface public interface CommandHandler { - CommandResult execute(A aggregate, C command); + CommandResult execute(A aggregate, C command); } diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResponse.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResponse.java new file mode 100644 index 0000000..03fdc04 --- /dev/null +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResponse.java @@ -0,0 +1,15 @@ +package com.mz.reactor.ddd.common.api.command; + +import org.immutables.value.Value; + +@Value.Immutable +public interface CommandResponse { + + CommandResult result(); + + S state(); + + static ImmutableCommandResponse.Builder builder() { + return ImmutableCommandResponse.builder(); + } +} diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResult.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResult.java index 77a9b53..02bc58d 100644 --- a/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResult.java +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/command/CommandResult.java @@ -8,7 +8,7 @@ import java.util.Optional; import java.util.UUID; @Value.Immutable -public interface CommandResult { +public interface CommandResult { enum StatusCode { OK, @@ -21,7 +21,7 @@ public interface CommandResult { StatusCode statusCode(); - List events(); + List events(); Optional error(); @@ -29,18 +29,18 @@ public interface CommandResult { return ImmutableCommandResult.builder(); } - static CommandResult fromError(RuntimeException error, DomainEvent event, Command command) { + static CommandResult fromError(RuntimeException error, D event, Command command) { return builder() .commandId(Optional.ofNullable(command) .map(Command::commandId) .orElseGet(() -> UUID.randomUUID().toString())) .statusCode(StatusCode.BAD_COMMAND) - .events(Optional.ofNullable(event).map(List::of).orElseGet(() -> List.of())) + .events(Optional.ofNullable(event).map(List::of).orElseGet(List::of)) .error(error) .build(); } - static CommandResult badCommand(Command cmd) { + static CommandResult badCommand(Command cmd) { return builder() .commandId(Optional.ofNullable(cmd) .map(Command::commandId) diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/error/ErrorMessage.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/error/ErrorMessage.java new file mode 100644 index 0000000..7d61a2e --- /dev/null +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/error/ErrorMessage.java @@ -0,0 +1,17 @@ +package com.mz.reactor.ddd.common.api.error; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableErrorMessage.class) +@JsonDeserialize(as = ImmutableErrorMessage.class) +public interface ErrorMessage { + + String error(); + + static ImmutableErrorMessage.Builder builder() { + return ImmutableErrorMessage.builder(); + } +} diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/event/EventApplier.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/event/EventApplier.java index 71d938c..6bcee2c 100644 --- a/common-api/src/main/java/com/mz/reactor/ddd/common/api/event/EventApplier.java +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/event/EventApplier.java @@ -1,7 +1,7 @@ package com.mz.reactor.ddd.common.api.event; @FunctionalInterface -public interface EventApplier { +public interface EventApplier { A apply(A aggregate, E event); diff --git a/common-api/src/main/java/com/mz/reactor/ddd/common/api/view/DomainView.java b/common-api/src/main/java/com/mz/reactor/ddd/common/api/view/DomainView.java new file mode 100644 index 0000000..4749677 --- /dev/null +++ b/common-api/src/main/java/com/mz/reactor/ddd/common/api/view/DomainView.java @@ -0,0 +1,5 @@ +package com.mz.reactor.ddd.common.api.view; + +public interface DomainView { + String id(); +} diff --git a/common-components/src/main/java/com/mz/reactor/ddd/common/components/ApplicationMessageBus.java b/common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/ApplicationMessageBus.java similarity index 90% rename from common-components/src/main/java/com/mz/reactor/ddd/common/components/ApplicationMessageBus.java rename to common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/ApplicationMessageBus.java index e41a9ee..3588625 100644 --- a/common-components/src/main/java/com/mz/reactor/ddd/common/components/ApplicationMessageBus.java +++ b/common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/ApplicationMessageBus.java @@ -1,4 +1,4 @@ -package com.mz.reactor.ddd.common.components; +package com.mz.reactor.ddd.common.components.bus; import com.mz.reactor.ddd.common.api.Message; import reactor.core.publisher.Flux; diff --git a/common-components/src/main/java/com/mz/reactor/ddd/common/components/impl/ApplicationMessageBusImpl.java b/common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/impl/ApplicationMessageBusImpl.java similarity index 80% rename from common-components/src/main/java/com/mz/reactor/ddd/common/components/impl/ApplicationMessageBusImpl.java rename to common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/impl/ApplicationMessageBusImpl.java index 23c3cd6..fa4cc1a 100644 --- a/common-components/src/main/java/com/mz/reactor/ddd/common/components/impl/ApplicationMessageBusImpl.java +++ b/common-components/src/main/java/com/mz/reactor/ddd/common/components/bus/impl/ApplicationMessageBusImpl.java @@ -1,8 +1,9 @@ -package com.mz.reactor.ddd.common.components.impl; +package com.mz.reactor.ddd.common.components.bus.impl; import com.mz.reactor.ddd.common.api.Message; -import com.mz.reactor.ddd.common.components.ApplicationMessageBus; +import com.mz.reactor.ddd.common.components.bus.ApplicationMessageBus; import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.FluxSink; import reactor.core.publisher.ReplayProcessor; @@ -10,7 +11,7 @@ import reactor.core.scheduler.Schedulers; import java.util.Optional; -@Component +@Service public class ApplicationMessageBusImpl implements ApplicationMessageBus { private final ReplayProcessor messages = ReplayProcessor.create(1); diff --git a/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/ErrorMessage.java b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/ErrorMessage.java new file mode 100644 index 0000000..144d482 --- /dev/null +++ b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/ErrorMessage.java @@ -0,0 +1,20 @@ +package com.mz.reactor.ddd.common.components.http; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.immutables.value.Value; + +/** + * Created by zemi on 02/10/2018. + */ +@Value.Immutable +@JsonSerialize(as = ImmutableErrorMessage.class) +@JsonDeserialize(as = ImmutableErrorMessage.class) +public interface ErrorMessage { + + String error(); + + static ImmutableErrorMessage.Builder builder() { + return ImmutableErrorMessage.builder(); + } +} diff --git a/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpErrorHandler.java b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpErrorHandler.java new file mode 100644 index 0000000..6a93c08 --- /dev/null +++ b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpErrorHandler.java @@ -0,0 +1,20 @@ +package com.mz.reactor.ddd.common.components.http; + +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; + +public enum HttpErrorHandler { + FN; + + public Mono onError(E e, ServerRequest req) { + return Mono.just(ErrorMessage.builder().error(e.getMessage()).build()) + .flatMap(error -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR) + .contentType(MediaType.APPLICATION_JSON_UTF8) + .body(fromObject(error))); + } +} diff --git a/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpHandler.java b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpHandler.java new file mode 100644 index 0000000..ed8b719 --- /dev/null +++ b/common-components/src/main/java/com/mz/reactor/ddd/common/components/http/HttpHandler.java @@ -0,0 +1,16 @@ +package com.mz.reactor.ddd.common.components.http; + +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +import static org.springframework.web.reactive.function.BodyInserters.fromObject; + +public interface HttpHandler { + + default Mono mapToResponse(T result) { + return ServerResponse.ok() + .contentType(MediaType.APPLICATION_JSON_UTF8).body(fromObject(result)); + } + +} diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepository.java b/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepository.java deleted file mode 100644 index 5be291a..0000000 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.mz.reactor.ddd.reactorddd.persistance.view; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import java.util.List; -import java.util.function.Predicate; - -public interface ViewRepository { - - Mono findBy(Predicate query); - - Mono> findAllByList(Predicate query); - - abstract Flux findAllBy(Predicate query); -} diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepositoryImpl.java b/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepositoryImpl.java deleted file mode 100644 index 4c33e1f..0000000 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/ViewRepositoryImpl.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.mz.reactor.ddd.reactorddd.persistance.view; - -import reactor.core.publisher.*; -import reactor.core.scheduler.Schedulers; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Predicate; - -public class ViewRepositoryImpl implements ViewRepository { - - private Set storage = new LinkedHashSet<>(); - - UnicastProcessor storageProcessor = UnicastProcessor.create(); - - FluxSink sink = storageProcessor.sink(); - - public ViewRepositoryImpl() { - storageProcessor - .subscribeOn(Schedulers.single()) - .subscribe(view -> storage.add(view)); - } - - public void addView(S view) { - sink.next(view); - } - - @Override - public Mono findBy(Predicate query) { - return Mono.just(query) - .flatMap(q -> storage.stream() - .filter(q) - .findFirst() - .map(Mono::just) - .orElseGet(Mono::empty) - ); - } - - @Override - public Mono> findAllByList(Predicate query) { - return findAllBy(query).collectList(); - } - - @Override - public Flux findAllBy(Predicate query) { - return Flux.fromStream(storage.stream() - .filter(query)); - } -} diff --git a/common-persistance/build.gradle b/common-persistence/build.gradle similarity index 100% rename from common-persistance/build.gradle rename to common-persistence/build.gradle diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java similarity index 65% rename from common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java rename to common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java index f12cca5..a45f0ac 100644 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateActor.java @@ -2,16 +2,17 @@ package com.mz.reactor.ddd.reactorddd.persistance.aggregate; import com.mz.reactor.ddd.common.api.command.Command; import com.mz.reactor.ddd.common.api.command.CommandResult; +import com.mz.reactor.ddd.common.api.event.DomainEvent; import reactor.core.publisher.Mono; import java.util.function.Function; -public interface AggregateActor { +public interface AggregateActor { Mono getState(Function stateFactory); void onDestroy(); - Mono execute(C cmd); + Mono> execute(C cmd); } diff --git a/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFacade.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFacade.java new file mode 100644 index 0000000..7b38897 --- /dev/null +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFacade.java @@ -0,0 +1,12 @@ +package com.mz.reactor.ddd.reactorddd.persistance.aggregate; + +import com.mz.reactor.ddd.common.api.command.Command; +import com.mz.reactor.ddd.common.api.event.DomainEvent; +import reactor.core.publisher.Mono; + +public interface AggregateFacade { + + Mono execute(C command, String aggregateID); + + Mono executeReturnEvent(C command, String aggregateID); +} diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFactory.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFactory.java similarity index 100% rename from common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFactory.java rename to common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateFactory.java diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java similarity index 59% rename from common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java rename to common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java index fc7fd56..7e07594 100644 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/AggregateRepository.java @@ -2,12 +2,13 @@ package com.mz.reactor.ddd.reactorddd.persistance.aggregate; import com.mz.reactor.ddd.common.api.command.Command; import com.mz.reactor.ddd.common.api.command.CommandResult; +import com.mz.reactor.ddd.common.api.event.DomainEvent; import com.mz.reactor.ddd.common.api.valueobject.Id; import reactor.core.publisher.Mono; -public interface AggregateRepository { +public interface AggregateRepository { - Mono execute(C cmd, Id aggregateId); + Mono> execute(C cmd, Id aggregateId); Mono findById(Id id); } diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java similarity index 75% rename from common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java rename to common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java index 22bb937..233de62 100644 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorImpl.java @@ -19,15 +19,15 @@ import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; -public class AggregateActorImpl implements AggregateActor { +public class AggregateActorImpl implements AggregateActor { private final Id id; private final CommandHandler commandHandler; - private final EventApplier eventApplier; + private final EventApplier eventApplier; - private final BiFunction, List> persistAll; + private final BiFunction, List> persistAll; private A aggregate; @@ -35,17 +35,17 @@ public class AggregateActorImpl implements AggregateActor< private final FluxSink commandSink = commandProcessor.sink(); - private final ReplayProcessor commandResultReplayProcessor = ReplayProcessor.create(); + private final ReplayProcessor> commandResultReplayProcessor = ReplayProcessor.create(); - private final FluxSink commandResultSink = commandResultReplayProcessor.sink(); + private final FluxSink> commandResultSink = commandResultReplayProcessor.sink(); public AggregateActorImpl( Id id, CommandHandler commandHandler, - EventApplier eventApplier, + EventApplier eventApplier, Function aggregateFactory, - List domainEvents, - BiFunction, List> persistAll + List domainEvents, + BiFunction, List> persistAll ) { this.id = id; this.commandHandler = commandHandler; @@ -64,18 +64,18 @@ public class AggregateActorImpl implements AggregateActor< } private void handleCommand(C cmd) { - var commandResult = commandHandler.execute(this.aggregate, cmd); - this.aggregate = persistAll + var commandResult = commandHandler.execute(this.aggregate, cmd); + this.aggregate = (A) persistAll .andThen(events -> events.stream() .reduce(this.aggregate, eventApplier::apply, (a1, a2) -> a2)) .apply(id, commandResult.events()); commandResultSink.next(commandResult); } - public Mono execute(C cmd) { - Mono result = commandResultReplayProcessor.publishOn(Schedulers.elastic()) + @Override + public Mono> execute(C cmd) { + Mono> result = commandResultReplayProcessor.publishOn(Schedulers.elastic()) .filter(r -> r.commandId().equals(cmd.commandId())) - .cast(CommandResult.class) .next(); commandSink.next(cmd); return result.timeout(Duration.ofSeconds(10)); @@ -100,7 +100,7 @@ public class AggregateActorImpl implements AggregateActor< public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - AggregateActorImpl that = (AggregateActorImpl) o; + var that = (AggregateActorImpl) o; return id.equals(that.id); } diff --git a/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateFacadeImpl.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateFacadeImpl.java new file mode 100644 index 0000000..f713994 --- /dev/null +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateFacadeImpl.java @@ -0,0 +1,60 @@ +package com.mz.reactor.ddd.reactorddd.persistance.aggregate.impl; + +import com.mz.reactor.ddd.common.api.Message; +import com.mz.reactor.ddd.common.api.command.Command; +import com.mz.reactor.ddd.common.api.command.CommandResult; +import com.mz.reactor.ddd.common.api.event.DomainEvent; +import com.mz.reactor.ddd.common.api.valueobject.Id; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.AggregateFacade; +import com.mz.reactor.ddd.reactorddd.persistance.aggregate.AggregateRepository; +import reactor.core.publisher.Mono; + +import java.util.function.Consumer; +import java.util.function.Function; + + +public class AggregateFacadeImpl implements AggregateFacade { + + private final AggregateRepository aggregateRepository; + private final Consumer publishChanged; + private final Consumer publishDocument; + + public AggregateFacadeImpl( + AggregateRepository aggregateRepository, + Consumer publishChanged, + Consumer publishDocument + ) { + this.aggregateRepository = aggregateRepository; + this.publishChanged = publishChanged; + this.publishDocument = publishDocument; + } + + @Override + public Mono execute(C command, String aggregateID) { + return aggregateRepository.execute(command, new Id(aggregateID)) + .flatMap(processResult(aggregateID)); + } + + @Override + public Mono executeReturnEvent(C command, String aggregateID) { + var result = aggregateRepository.execute(command, new Id(aggregateID)); + return result.map(r -> r.events().stream().findAny().get()); + } + + private Function, Mono> processResult(String aggregateId) { + return result -> { + switch (result.statusCode()) { + case OK: + return aggregateRepository.findById(new Id(aggregateId)) + .doOnSuccess(publishDocument) + .doOnSuccess(s -> result.events().forEach(publishChanged)); + case FAILED: + return Mono.error(result.error().orElseGet(() -> new RuntimeException("Generic error"))); + case NOT_MODIFIED: + default: + return Mono.empty(); + } + }; + } + +} diff --git a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java similarity index 75% rename from common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java rename to common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java index eb254f8..5be94b6 100644 --- a/common-persistance/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImpl.java @@ -21,21 +21,19 @@ import java.util.stream.Stream; import static java.util.stream.Collectors.toList; -public class AggregateRepositoryImpl implements AggregateRepository { +public class AggregateRepositoryImpl implements AggregateRepository { -// private final Map> eventSource = new HashMap<>(); + private final AtomicReference>> eventSource = new AtomicReference<>(new HashMap<>()); - private final AtomicReference>> eventSource = new AtomicReference<>(new HashMap<>()); - - private final Cache> cache = CacheBuilder.newBuilder() + private final Cache> cache = CacheBuilder.newBuilder() .expireAfterAccess(Duration.ofMinutes(10)) - .removalListener((RemovalListener) notification -> notification.getValue().onDestroy()) + .removalListener((RemovalListener>) notification -> notification.getValue().onDestroy()) .build(); private final CommandHandler commandHandler; - private final EventApplier eventApplier; + private final EventApplier eventApplier; private final Function aggregateFactory; @@ -43,7 +41,7 @@ public class AggregateRepositoryImpl implements Aggrega public AggregateRepositoryImpl( CommandHandler commandHandler, - EventApplier eventApplier, + EventApplier eventApplier, Function aggregateFactory, Function stateFactory ) { @@ -53,7 +51,7 @@ public class AggregateRepositoryImpl implements Aggrega this.stateFactory = stateFactory; } - private List persistAll(Id id, List events) { + private List persistAll(Id id, List events) { eventSource.updateAndGet(esMap -> { var eventsToStore = Optional.ofNullable(esMap.get(id)) .map(es -> Stream.concat(es.stream(), events.stream()) @@ -66,12 +64,12 @@ public class AggregateRepositoryImpl implements Aggrega return events; } - private Mono> getAggregate(Id id) { + private Mono> getAggregate(Id id) { return Mono.just(id) .map(this::getFromCache); } - private AggregateActor getFromCache(Id id) { + private AggregateActor getFromCache(Id id) { try { return cache.get(id, () -> new AggregateActorImpl<>( @@ -87,7 +85,7 @@ public class AggregateRepositoryImpl implements Aggrega } @Override - public Mono execute(C cmd, Id aggregateId) { + public Mono> execute(C cmd, Id aggregateId) { return getAggregate(aggregateId) .flatMap(a -> a.execute(cmd)); } diff --git a/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepository.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepository.java new file mode 100644 index 0000000..c486c37 --- /dev/null +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepository.java @@ -0,0 +1,19 @@ +package com.mz.reactor.ddd.reactorddd.persistance.view.impl; + +import com.mz.reactor.ddd.common.api.view.DomainView; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.function.Predicate; + +public interface ViewRepository { + + void addView(S view); + + Mono findBy(Predicate query); + + Mono> findAllListBy(Predicate query); + + Flux findAllBy(Predicate query); +} diff --git a/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/impl/ViewRepositoryImpl.java b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/impl/ViewRepositoryImpl.java new file mode 100644 index 0000000..4cc835c --- /dev/null +++ b/common-persistence/src/main/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/impl/ViewRepositoryImpl.java @@ -0,0 +1,57 @@ +package com.mz.reactor.ddd.reactorddd.persistance.view.impl.impl; + +import com.mz.reactor.ddd.common.api.view.DomainView; +import com.mz.reactor.ddd.reactorddd.persistance.view.impl.ViewRepository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.FluxSink; +import reactor.core.publisher.Mono; +import reactor.core.publisher.UnicastProcessor; +import reactor.core.scheduler.Schedulers; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; + +public class ViewRepositoryImpl implements ViewRepository { + + private final AtomicReference> storage = new AtomicReference<>(new HashMap<>()); + + UnicastProcessor storageProcessor = UnicastProcessor.create(); + + FluxSink sink = storageProcessor.sink(); + + public ViewRepositoryImpl() { + storageProcessor + .parallel() + .subscribe(view -> storage.updateAndGet(sm -> { + sm.put(view.id(), view); + return sm; + })); + } + + @Override + public void addView(S view) { + sink.next(view); + } + + @Override + public Mono findBy(Predicate query) { + return findAllBy(query) + .singleOrEmpty(); + } + + @Override + public Mono> findAllListBy(Predicate query) { + return findAllBy(query).collectList(); + } + + @Override + public Flux findAllBy(Predicate query) { + return Optional.ofNullable(query) + .map(Flux.fromStream(storage.get().values().stream())::filter) + .orElse(Flux.empty()); + } +} diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java similarity index 93% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java index bd65a0a..deffeec 100644 --- a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java +++ b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateActorTest.java @@ -22,7 +22,7 @@ class AggregateActorTest { .withValue(10) .build(); - var subject = new AggregateActorImpl( + var subject = new AggregateActorImpl( new Id(UUID.randomUUID().toString()), TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, @@ -31,7 +31,7 @@ class AggregateActorTest { TestFunctions.FN.persistAll ); - Mono result = subject.execute(command); + Mono> result = subject.execute(command); StepVerifier.create(result) .expectNextMatches(r -> r.commandId().equals(commandId) && r.statusCode().equals(CommandResult.StatusCode.OK)) @@ -40,7 +40,7 @@ class AggregateActorTest { @Test void onDestroy() { - var subject = new AggregateActorImpl( + var subject = new AggregateActorImpl( new Id(UUID.randomUUID().toString()), TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, @@ -60,7 +60,7 @@ class AggregateActorTest { @Test void executeParallel() { - var subject = new AggregateActorImpl( + var subject = new AggregateActorImpl( new Id(UUID.randomUUID().toString()), TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, @@ -84,7 +84,7 @@ class AggregateActorTest { @Test public void testRecoveryState() { - var subject = new AggregateActorImpl( + var subject = new AggregateActorImpl( new Id(UUID.randomUUID().toString()), TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, @@ -105,7 +105,7 @@ class AggregateActorTest { @Test public void test_RecoveryStateAndExecuteCommand() { - var subject = new AggregateActorImpl( + var subject = new AggregateActorImpl( new Id(UUID.randomUUID().toString()), TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java similarity index 97% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java index db73d85..13923e3 100644 --- a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java +++ b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/AggregateRepositoryImplTest.java @@ -18,7 +18,7 @@ class AggregateRepositoryImplTest { private final Function> getState = a -> Tuples.of(a.getId(), a.getValue()); - AggregateRepositoryImpl> subject = + AggregateRepositoryImpl> subject = new AggregateRepositoryImpl<>( TestFunctions.FN.commandHandler, TestFunctions.FN.eventApplier, diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregate.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregate.java similarity index 100% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregate.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregate.java diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateCommand.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateCommand.java similarity index 100% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateCommand.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateCommand.java diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateEvent.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateEvent.java similarity index 100% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateEvent.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestAggregateEvent.java diff --git a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java similarity index 50% rename from common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java rename to common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java index 236fcbf..9ceec42 100644 --- a/common-persistance/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java +++ b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/aggregate/impl/TestFunctions.java @@ -2,7 +2,6 @@ package com.mz.reactor.ddd.reactorddd.persistance.aggregate.impl; import com.mz.reactor.ddd.common.api.command.CommandHandler; import com.mz.reactor.ddd.common.api.command.CommandResult; -import com.mz.reactor.ddd.common.api.event.DomainEvent; import com.mz.reactor.ddd.common.api.event.EventApplier; import com.mz.reactor.ddd.common.api.valueobject.Id; @@ -13,28 +12,31 @@ import java.util.function.Function; public enum TestFunctions { FN; - public final CommandHandler commandHandler = (aggregate, command) -> { - try { - var event = aggregate.validate(command); - return CommandResult.builder() - .commandId(command.commandId()) - .statusCode(CommandResult.StatusCode.OK) - .addEvents(event) - .build(); - } catch (Exception e) { - return CommandResult.fromError( - new RuntimeException(e), - null, - command - ); + public final CommandHandler commandHandler = new CommandHandler() { + @Override + public CommandResult execute(TestAggregate aggregate, TestAggregateCommand command) { + try { + TestAggregateEvent event = aggregate.validate(command); + return CommandResult.builder() + .commandId(command.commandId()) + .statusCode(CommandResult.StatusCode.OK) + .addEvents(event) + .build(); + } catch (Exception e) { + return CommandResult.fromError( + new RuntimeException(e), + null, + command + ); + } } }; - public final EventApplier eventApplier = (aggregate, event) -> aggregate.apply((TestAggregateEvent) event); + public final EventApplier eventApplier = (aggregate, event) -> aggregate.apply((TestAggregateEvent) event); public final Function aggregateFactory = TestAggregate::new; - public final BiFunction, List> persistAll = (id, events) -> events; + public final BiFunction, List> persistAll = (id, events) -> events; public Function mapTest1(String val1, String val2) { return v -> val1 + " and " + val2 + " not " + v; diff --git a/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/model/TestView.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/model/TestView.java new file mode 100644 index 0000000..2c20a72 --- /dev/null +++ b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/model/TestView.java @@ -0,0 +1,80 @@ +package com.mz.reactor.ddd.reactorddd.persistance.model; + +import com.mz.reactor.ddd.common.api.view.DomainView; + +public class TestView implements DomainView { + private final String id; + + private final String value; + + private TestView(Builder builder) { + id = builder.id; + value = builder.value; + } + + public String getId() { + return id; + } + + public String getValue() { + return value; + } + + @Override + public String id() { + return id; + } + + public static Builder newBuilder() { + return new Builder(); + } + + public static Builder newBuilder(TestView copy) { + Builder builder = new Builder(); + builder.id = copy.getId(); + builder.value = copy.getValue(); + return builder; + } + + /** + * {@code TestView} builder static inner class. + */ + public static final class Builder { + private String id; + private String value; + + private Builder() { + } + + /** + * Sets the {@code id} and returns a reference to this Builder so that the methods can be chained together. + * + * @param val the {@code id} to set + * @return a reference to this Builder + */ + public Builder withId(String val) { + id = val; + return this; + } + + /** + * Sets the {@code value} and returns a reference to this Builder so that the methods can be chained together. + * + * @param val the {@code value} to set + * @return a reference to this Builder + */ + public Builder withValue(String val) { + value = val; + return this; + } + + /** + * Returns a {@code TestView} built from the parameters previously set. + * + * @return a {@code TestView} built with parameters of this {@code TestView.Builder} + */ + public TestView build() { + return new TestView(this); + } + } +} diff --git a/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepositoryImplTest.java b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepositoryImplTest.java new file mode 100644 index 0000000..a1e09f5 --- /dev/null +++ b/common-persistence/src/test/java/com/mz/reactor/ddd/reactorddd/persistance/view/impl/ViewRepositoryImplTest.java @@ -0,0 +1,74 @@ +package com.mz.reactor.ddd.reactorddd.persistance.view.impl; + +import com.mz.reactor.ddd.reactorddd.persistance.model.TestView; +import com.mz.reactor.ddd.reactorddd.persistance.view.impl.impl.ViewRepositoryImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; +import reactor.test.StepVerifier; + +import java.util.UUID; +import java.util.function.Predicate; + +class ViewRepositoryImplTest { + + ViewRepository subject; + + private final String id1 = UUID.randomUUID().toString(); + private final String value1 = UUID.randomUUID().toString(); + + private final String id2 = UUID.randomUUID().toString(); + private final String value2 = UUID.randomUUID().toString(); + + @BeforeEach + public void before() { + subject = new ViewRepositoryImpl<>(); + subject.addView(TestView.newBuilder().withId(id1).withValue(value1).build()); + subject.addView(TestView.newBuilder().withId(id2).withValue(value2).build()); + + Flux.range(0, 1000000) + .publishOn(Schedulers.elastic()) + .map(String::valueOf) + .doOnNext(v -> subject.addView(TestView.newBuilder().withId(v).withValue(v).build())) + .collectList().block(); + + } + + @Test + void findAllBy_predictionIsForAll_isReturnedAll() { + var source = subject.findAllBy(v -> true); + StepVerifier.create(source) + .expectNextCount(1000002) + .verifyComplete(); + } + + @Test + void findAllBy_predictionForTwo_isReturnedTwo() { + Predicate prediction1 = v -> id1.equals(v.getId()); + Predicate prediction2 = v -> id2.equals(v.getId()); + var source = subject.findAllBy(prediction1.or(prediction2)); + StepVerifier.create(source) + .expectNextCount(2) + .verifyComplete(); + } + + @Test + void findAllListBy_predictionForTwo_isReturnedTwo() { + Predicate prediction1 = v -> id1.equals(v.getId()); + Predicate prediction2 = v -> id2.equals(v.getId()); + var source = subject.findAllListBy(prediction1.or(prediction2)); + StepVerifier.create(source) + .expectNextMatches(list -> list.size() == 2) + .verifyComplete(); + } + + @Test + void findBy_filteredById_isReturnedOne() { + Predicate prediction1 = v -> id1.equals(v.getId()); + var source = subject.findBy(prediction1); + StepVerifier.create(source) + .expectNextMatches(item -> item.getId().equals(id1)) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1d3292e..048d529 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,7 +4,10 @@ include 'bank-account:bank-account-application' include 'bank-account:account-domain' include 'bank-account:transaction-domain' include 'shared-dependencies' -include 'common-persistance' +include 'shared-spring-dependecies' +include 'common-persistence' include 'common-components' include 'bank-account:account-domain-api' include 'bank-account:transaction-domain-api' +include 'bank-account:account-api' +include 'bank-account:account-impl' \ No newline at end of file