diff --git a/build.gradle b/build.gradle index 0dc4da43..34b4a4a1 100644 --- a/build.gradle +++ b/build.gradle @@ -30,10 +30,11 @@ subprojects { group = "net.chrisrichardson.ftgo" repositories { - eventuateMavenRepoUrl.split('[ ,]').each { repoUrl -> maven { url repoUrl.trim() } } - mavenCentral() jcenter() + eventuateMavenRepoUrl.split('[ ,]').each { repoUrl -> maven { url repoUrl.trim() } } + + maven { url 'https://jitpack.io' diff --git a/deployment/kubernetes/cdc-service/ftgo-cdc-service.yml b/deployment/kubernetes/cdc-service/ftgo-cdc-service.yml index 449edef3..c5fadb70 100644 --- a/deployment/kubernetes/cdc-service/ftgo-cdc-service.yml +++ b/deployment/kubernetes/cdc-service/ftgo-cdc-service.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-cdc-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-cdc-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-cdc-service replicas: 1 strategy: rollingUpdate: @@ -27,7 +30,7 @@ spec: spec: containers: - name: ftgo-cdc-service - image: eventuateio/eventuate-cdc-service:0.4.0.RELEASE + image: eventuateio/eventuate-cdc-service:0.6.0.RC3 imagePullPolicy: Always ports: - containerPort: 8080 @@ -37,7 +40,7 @@ spec: - name: JAVA_OPTS value: "-Dsun.net.inetaddr.ttl=30" - name: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS - value: ftgo-kafka:29092 + value: ftgo-kafka:9092 - name: EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING value: ftgo-zookeeper:2181 - name: EVENTUATE_CDC_PIPELINE_PIPELINE1_TYPE diff --git a/deployment/kubernetes/scripts/kubernetes-deploy-all.sh b/deployment/kubernetes/scripts/kubernetes-deploy-all.sh index 790cef24..e0f73ec9 100755 --- a/deployment/kubernetes/scripts/kubernetes-deploy-all.sh +++ b/deployment/kubernetes/scripts/kubernetes-deploy-all.sh @@ -1,9 +1,11 @@ #! /bin/bash -e +set -vx + kubectl apply -f <(cat deployment/kubernetes/stateful-services/*.yml) ./deployment/kubernetes/scripts/kubernetes-wait-for-ready-pods.sh ftgo-mysql-0 ftgo-kafka-0 ftgo-dynamodb-local-0 ftgo-zookeeper-0 -kubectl apply -f <(cat deployment/kubernetes/cdc-services/*.yml) +kubectl apply -f <(cat deployment/kubernetes/cdc-service/*.yml) kubectl apply -f <(cat */src/deployment/kubernetes/*.yml) diff --git a/deployment/kubernetes/scripts/port-forwards.sh b/deployment/kubernetes/scripts/port-forwards.sh index b277763e..af72ad29 100755 --- a/deployment/kubernetes/scripts/port-forwards.sh +++ b/deployment/kubernetes/scripts/port-forwards.sh @@ -15,7 +15,7 @@ doforward() { doforward 'ftgo-accounting-service' 8085 8080 - +doforward 'ftgo-order-history-service' 8086 8080 doforward 'ftgo-consumer-service' 8081 8080 doforward 'ftgo-api-gateway' 8087 8080 doforward 'ftgo-order-service' 8082 8080 diff --git a/deployment/kubernetes/stateful-services/ftgo-dynamodb-local.yml b/deployment/kubernetes/stateful-services/ftgo-dynamodb-local.yml index 7413bee3..a84f8722 100644 --- a/deployment/kubernetes/stateful-services/ftgo-dynamodb-local.yml +++ b/deployment/kubernetes/stateful-services/ftgo-dynamodb-local.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-dynamodb-local --- -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: StatefulSet metadata: name: ftgo-dynamodb-local labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-dynamodb-local serviceName: "ftgo-dynamodb" replicas: 1 template: diff --git a/deployment/kubernetes/stateful-services/ftgo-kafka-deployment.yml b/deployment/kubernetes/stateful-services/ftgo-kafka-deployment.yml index 0190b53e..91aba08f 100644 --- a/deployment/kubernetes/stateful-services/ftgo-kafka-deployment.yml +++ b/deployment/kubernetes/stateful-services/ftgo-kafka-deployment.yml @@ -11,11 +11,14 @@ spec: selector: role: ftgo-kafka --- -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: StatefulSet metadata: name: ftgo-kafka spec: + selector: + matchLabels: + role: ftgo-kafka serviceName: "kafka" replicas: 1 template: diff --git a/deployment/kubernetes/stateful-services/ftgo-mysql-deployment.yml b/deployment/kubernetes/stateful-services/ftgo-mysql-deployment.yml index 73b98479..c71e8024 100644 --- a/deployment/kubernetes/stateful-services/ftgo-mysql-deployment.yml +++ b/deployment/kubernetes/stateful-services/ftgo-mysql-deployment.yml @@ -12,11 +12,14 @@ spec: selector: role: ftgo-mysql --- -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: StatefulSet metadata: name: ftgo-mysql spec: + selector: + matchLabels: + role: ftgo-mysql serviceName: "mysql" replicas: 1 template: diff --git a/deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml b/deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml index 4bfadd5d..becf34df 100644 --- a/deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml +++ b/deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml @@ -12,11 +12,14 @@ spec: selector: role: ftgo-zookeeper --- -apiVersion: apps/v1beta1 +apiVersion: apps/v1 kind: StatefulSet metadata: name: ftgo-zookeeper spec: + selector: + matchLabels: + role: ftgo-zookeeper serviceName: "zookeeper" replicas: 1 template: diff --git a/docker-compose.yml b/docker-compose.yml index 6ed56191..b4e94a4c 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -161,6 +161,7 @@ services: - kafka - zookeeper - cdc-service + - zipkin environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql/ftgo_accounting_service SPRING_DATASOURCE_USERNAME: ftgo_accounting_service_user @@ -169,6 +170,9 @@ services: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS: kafka:29092 EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING: zookeeper:2181 EVENTUATE_DATABASE_SCHEMA: ftgo_accounting_service + SPRING_SLEUTH_ENABLED: "true" + SPRING_SLEUTH_SAMPLER_PROBABILITY: 1 + SPRING_ZIPKIN_BASE_URL: http://zipkin:9411/ ftgo-delivery-service: build: ./ftgo-delivery-service ports: diff --git a/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountLimitExceededReply.java b/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountLimitExceededReply.java new file mode 100644 index 00000000..3a1bd0a7 --- /dev/null +++ b/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountLimitExceededReply.java @@ -0,0 +1,4 @@ +package net.chrisrichardson.ftgo.accountservice.api; + +public class AccountLimitExceededReply { +} diff --git a/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/CheckAccountLimitCommand.java b/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/CheckAccountLimitCommand.java new file mode 100644 index 00000000..ffee15b1 --- /dev/null +++ b/ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/CheckAccountLimitCommand.java @@ -0,0 +1,32 @@ +package net.chrisrichardson.ftgo.accountservice.api; + +import io.eventuate.tram.commands.common.Command; +import net.chrisrichardson.ftgo.common.Money; + +public class CheckAccountLimitCommand implements Command { + + private Money money; + private Long consumerId; + private Long orderId; + + private CheckAccountLimitCommand() { + } + + public CheckAccountLimitCommand(Long consumerId, Long orderId, Money money) { + this.money = money; + this.consumerId = consumerId; + this.orderId = orderId; + } + + public Money getMoney() { + return money; + } + + public Long getConsumerId() { + return consumerId; + } + + public Long getOrderId() { + return orderId; + } +} diff --git a/ftgo-accounting-service/src/deployment/kubernetes/ftgo-accounting-service.yml b/ftgo-accounting-service/src/deployment/kubernetes/ftgo-accounting-service.yml index 4076b11a..536faa77 100644 --- a/ftgo-accounting-service/src/deployment/kubernetes/ftgo-accounting-service.yml +++ b/ftgo-accounting-service/src/deployment/kubernetes/ftgo-accounting-service.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-accounting-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-accounting-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-accounting-service replicas: 1 strategy: rollingUpdate: @@ -37,23 +40,19 @@ spec: - name: JAVA_OPTS value: "-Dsun.net.inetaddr.ttl=30" - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://ftgo-mysql/eventuate + value: jdbc:mysql://ftgo-mysql/ftgo_accounting_service - name: SPRING_DATASOURCE_USERNAME - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: username + value: ftgo_accounting_service_user - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: password + value: ftgo_accounting_service_password - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME value: com.mysql.jdbc.Driver - name: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS value: ftgo-kafka:9092 - name: EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING value: ftgo-zookeeper:2181 + - name: EVENTUATE_DATABASE_SCHEMA + value: ftgo_accounting_service livenessProbe: httpGet: path: /actuator/health diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java index 95af838d..ef0ee881 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/Account.java @@ -3,25 +3,54 @@ import io.eventuate.Event; import io.eventuate.ReflectiveMutableCommandProcessingAggregate; import io.eventuate.tram.sagas.eventsourcingsupport.SagaReplyRequestedEvent; +import net.chrisrichardson.ftgo.common.Money; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.math.BigDecimal; import java.util.Collections; import java.util.List; +import java.util.Map; import static io.eventuate.EventUtil.events; public class Account extends ReflectiveMutableCommandProcessingAggregate { + public Money getBalance() { + return balance; + } + public boolean accountLimitSufficient(Money money){ + return balance.isGreaterThanOrEqual(money); + } + + public void setBalance(Money balance) { + this.balance = balance; + } + + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private Money balance; + public List process(CreateAccountCommand command) { - return events(new AccountCreatedEvent()); + logger.info(command.getCustomerId().toString()); + return events(new AccountCreatedEvent(command.getCustomerId(), command.getInitialBalance())); } public void apply(AccountCreatedEvent event) { - + this.balance = event.getInitialBalance(); + logger.info(this.balance.asString()); + logger.info(event.getCustomerId().toString()); } + public List process(CheckAccountLimitCommandInternal command) { + if(balance.isGreaterThanOrEqual(command.getMoney())){ + return events(new AccountLimitSufficientEvent()); + } + return events(new AccountLimitExceededEvent()); + } public List process(AuthorizeCommandInternal command) { - return events(new AccountAuthorizedEvent()); + return events(new AccountAuthorizedEvent(command.getOrderTotal())); } public List process(ReverseAuthorizationCommandInternal command) { @@ -32,7 +61,15 @@ public List process(ReviseAuthorizationCommandInternal command) { } public void apply(AccountAuthorizedEvent event) { + if(balance.isGreaterThanOrEqual(event.getMoney())) { + setBalance(getBalance().subtract(event.getMoney())); + } + } + + public void apply(AccountLimitSufficientEvent event) { + } + public void apply(AccountLimitExceededEvent event) { } public void apply(SagaReplyRequestedEvent event) { diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizedEvent.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizedEvent.java index 565e291c..5834113b 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizedEvent.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizedEvent.java @@ -1,6 +1,19 @@ package net.chrisrichardson.ftgo.accountingservice.domain; import io.eventuate.Event; +import net.chrisrichardson.ftgo.common.Money; public class AccountAuthorizedEvent implements Event { + private Money money; + + public AccountAuthorizedEvent() { + } + + public AccountAuthorizedEvent(Money money) { + this.money = money; + } + + public Money getMoney() { + return money; + } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCreatedEvent.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCreatedEvent.java index b13bc435..2e9397ff 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCreatedEvent.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCreatedEvent.java @@ -1,6 +1,31 @@ package net.chrisrichardson.ftgo.accountingservice.domain; import io.eventuate.Event; +import net.chrisrichardson.ftgo.common.Money; + +import java.math.BigDecimal; public class AccountCreatedEvent implements Event { + private Money initialBalance; + + private Long customerId; + + private AccountCreatedEvent() {} + + public AccountCreatedEvent(Long customerId, Money initialBalance){ + this.customerId = customerId; + this.initialBalance = initialBalance; + } + + public Money getInitialBalance() { + return initialBalance; + } + + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededEvent.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededEvent.java new file mode 100644 index 00000000..74dd7f05 --- /dev/null +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededEvent.java @@ -0,0 +1,6 @@ +package net.chrisrichardson.ftgo.accountingservice.domain; + +import io.eventuate.Event; + +public class AccountLimitExceededEvent implements Event { +} diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededException.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededException.java new file mode 100644 index 00000000..1508987d --- /dev/null +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitExceededException.java @@ -0,0 +1,4 @@ +package net.chrisrichardson.ftgo.accountingservice.domain; + +public class AccountLimitExceededException extends RuntimeException { +} diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitSufficientEvent.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitSufficientEvent.java new file mode 100644 index 00000000..81c5fd95 --- /dev/null +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountLimitSufficientEvent.java @@ -0,0 +1,6 @@ +package net.chrisrichardson.ftgo.accountingservice.domain; + +import io.eventuate.Event; + +public class AccountLimitSufficientEvent implements Event { +} diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountingService.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountingService.java index 4c4d1f7b..6262f05a 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountingService.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountingService.java @@ -3,8 +3,10 @@ import io.eventuate.sync.AggregateRepository; import io.eventuate.EntityWithIdAndVersion; import io.eventuate.SaveOptions; +import net.chrisrichardson.ftgo.common.Money; import org.springframework.beans.factory.annotation.Autowired; +import java.math.BigDecimal; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -14,8 +16,8 @@ public class AccountingService { @Autowired private AggregateRepository accountRepository; - public void create(String aggregateId) { - EntityWithIdAndVersion account = accountRepository.save(new CreateAccountCommand(), - Optional.of(new SaveOptions().withId(aggregateId))); + public void create(Long consumerId, String aggregateId) { + Money initialBalance = new Money(100); + accountRepository.save(new CreateAccountCommand(consumerId, initialBalance), Optional.of(new SaveOptions().withId(aggregateId))); } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CheckAccountLimitCommandInternal.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CheckAccountLimitCommandInternal.java new file mode 100644 index 00000000..66c373c0 --- /dev/null +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CheckAccountLimitCommandInternal.java @@ -0,0 +1,31 @@ +package net.chrisrichardson.ftgo.accountingservice.domain; + +import io.eventuate.tram.commands.common.Command; +import net.chrisrichardson.ftgo.common.Money; + +public class CheckAccountLimitCommandInternal implements AccountCommand, Command { + private Money money; + private String consumerId; + private String orderId; + + private CheckAccountLimitCommandInternal() { + } + + public CheckAccountLimitCommandInternal(String consumerId, String orderId, Money money) { + this.money = money; + this.consumerId = consumerId; + this.orderId = orderId; + } + + public Money getMoney() { + return money; + } + + public String getConsumerId() { + return consumerId; + } + + public String getOrderId() { + return orderId; + } +} diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CreateAccountCommand.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CreateAccountCommand.java index 1074d7a8..2c057de6 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CreateAccountCommand.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CreateAccountCommand.java @@ -1,4 +1,29 @@ package net.chrisrichardson.ftgo.accountingservice.domain; +import net.chrisrichardson.ftgo.common.Money; + +import java.math.BigDecimal; + public class CreateAccountCommand implements AccountCommand { + public Long getCustomerId() { + return customerId; + } + + public void setCustomerId(Long customerId) { + this.customerId = customerId; + } + + private Long customerId; + private Money initialBalance; + + private CreateAccountCommand(){} + + public CreateAccountCommand(Long customerId, Money initialBalance){ + this.customerId = customerId; + this.initialBalance = initialBalance; + } + + public Money getInitialBalance() { + return initialBalance; + } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingEventConsumer.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingEventConsumer.java index 314ad3bc..49a8391e 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingEventConsumer.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingEventConsumer.java @@ -5,6 +5,8 @@ import io.eventuate.tram.events.subscriber.DomainEventHandlersBuilder; import net.chrisrichardson.ftgo.accountingservice.domain.AccountingService; import net.chrisrichardson.ftgo.consumerservice.domain.ConsumerCreated; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +15,8 @@ public class AccountingEventConsumer { @Autowired private AccountingService accountingService; + private Logger logger = LoggerFactory.getLogger(getClass()); + public DomainEventHandlers domainEventHandlers() { return DomainEventHandlersBuilder .forAggregateType("net.chrisrichardson.ftgo.consumerservice.domain.Consumer") @@ -21,8 +25,8 @@ public DomainEventHandlers domainEventHandlers() { } private void createAccount(DomainEventEnvelope dee) { - accountingService.create(dee.getAggregateId()); + String consumerId = dee.getAggregateId(); + accountingService.create(Long.parseLong(consumerId), consumerId); } - } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandler.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandler.java index 4f3fac48..52280e1b 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandler.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandler.java @@ -3,17 +3,16 @@ import io.eventuate.sync.AggregateRepository; import io.eventuate.tram.commands.consumer.CommandHandlers; import io.eventuate.tram.commands.consumer.CommandMessage; +import io.eventuate.tram.messaging.common.Message; import io.eventuate.tram.sagas.participant.SagaCommandHandlersBuilder; import net.chrisrichardson.ftgo.accountingservice.domain.*; -import net.chrisrichardson.ftgo.accountservice.api.AccountDisabledReply; -import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand; -import net.chrisrichardson.ftgo.accountservice.api.ReverseAuthorizationCommand; -import net.chrisrichardson.ftgo.accountservice.api.ReviseAuthorization; +import net.chrisrichardson.ftgo.accountservice.api.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import static io.eventuate.tram.commands.consumer.CommandHandlerReplyBuilder.withFailure; +import static io.eventuate.tram.commands.consumer.CommandHandlerReplyBuilder.withSuccess; import static io.eventuate.tram.sagas.eventsourcingsupport.UpdatingOptionsBuilder.replyingTo; public class AccountingServiceCommandHandler { @@ -27,6 +26,7 @@ public CommandHandlers commandHandlers() { return SagaCommandHandlersBuilder .fromChannel("accountingService") .onMessage(AuthorizeCommand.class, this::authorize) + .onMessage(CheckAccountLimitCommand.class, this::checkAccountLimit) .onMessage(ReverseAuthorizationCommand.class, this::reverseAuthorization) .onMessage(ReviseAuthorization.class, this::reviseAuthorization) .build(); @@ -44,6 +44,24 @@ public void authorize(CommandMessage cm) { } + public Message checkAccountLimit(CommandMessage cm){ + CheckAccountLimitCommand command = cm.getCommand(); + + logger.info(command.getConsumerId().toString()); + logger.info(replyingTo(cm).build().toString()); + + logger.info(Long.toString(command.getOrderId())); + logger.info(command.getMoney().asString()); + + logger.info(accountRepository.find(Long.toString(command.getConsumerId())).getEntity().getBalance().asString()); + Account account = accountRepository.find(Long.toString(command.getConsumerId())).getEntity(); + if(account.accountLimitSufficient(cm.getCommand().getMoney())){ + return withSuccess(); + } else { + return withFailure(); + } + } + public void reverseAuthorization(CommandMessage cm) { ReverseAuthorizationCommand command = cm.getCommand(); @@ -71,6 +89,9 @@ public void reviseAuthorization(CommandMessage cm) { private AuthorizeCommandInternal makeAuthorizeCommandInternal(AuthorizeCommand command) { return new AuthorizeCommandInternal(Long.toString(command.getConsumerId()), Long.toString(command.getOrderId()), command.getOrderTotal()); } + private CheckAccountLimitCommandInternal makeCheckAccountLimitCommandInternal(CheckAccountLimitCommand command) { + return new CheckAccountLimitCommandInternal(Long.toString(command.getConsumerId()), Long.toString(command.getOrderId()), command.getMoney()); + } private ReverseAuthorizationCommandInternal makeReverseAuthorizeCommandInternal(ReverseAuthorizationCommand command) { return new ReverseAuthorizationCommandInternal(Long.toString(command.getConsumerId()), Long.toString(command.getOrderId()), command.getOrderTotal()); } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountingWebConfiguration.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountingWebConfiguration.java index fceb2952..93fd87a9 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountingWebConfiguration.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountingWebConfiguration.java @@ -1,12 +1,19 @@ package net.chrisrichardson.ftgo.accountingservice.web; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.eventuate.common.json.mapper.JSonMapper; import net.chrisrichardson.ftgo.accountingservice.domain.AccountServiceConfiguration; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; +import net.chrisrichardson.ftgo.common.CommonConfiguration; +import org.springframework.context.annotation.*; @Configuration -@Import(AccountServiceConfiguration.class) +@Import({AccountServiceConfiguration.class, CommonConfiguration.class}) @ComponentScan public class AccountingWebConfiguration { + + @Bean + @Primary + public ObjectMapper objectMapper() { + return JSonMapper.objectMapper; + } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountsController.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountsController.java index a16d7d56..35c0675e 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountsController.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountsController.java @@ -1,6 +1,7 @@ package net.chrisrichardson.ftgo.accountingservice.web; import io.eventuate.EntityNotFoundException; +import io.eventuate.EntityWithMetadata; import io.eventuate.sync.AggregateRepository; import net.chrisrichardson.ftgo.accountingservice.domain.Account; import net.chrisrichardson.ftgo.accountingservice.domain.AccountCommand; @@ -22,7 +23,9 @@ public class AccountsController { @RequestMapping(path="/{accountId}", method= RequestMethod.GET) public ResponseEntity getAccount(@PathVariable String accountId) { try { - return new ResponseEntity<>(new GetAccountResponse(accountId), HttpStatus.OK); + EntityWithMetadata accountEntity = accountRepository.find(accountId); + Account account = accountEntity.getEntity(); + return new ResponseEntity<>(new GetAccountResponse(accountId, account.getBalance()), HttpStatus.OK); } catch (EntityNotFoundException e) { return new ResponseEntity<>(HttpStatus.NOT_FOUND); } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/GetAccountResponse.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/GetAccountResponse.java index 9f0a6629..e79d6f94 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/GetAccountResponse.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/GetAccountResponse.java @@ -1,7 +1,10 @@ package net.chrisrichardson.ftgo.accountingservice.web; +import net.chrisrichardson.ftgo.common.Money; + public class GetAccountResponse { private String accountId; + private Money balance; public String getAccountId() { return accountId; @@ -11,11 +14,20 @@ public void setAccountId(String accountId) { this.accountId = accountId; } + public Money getBalance() { + return balance; + } + + public void setBalance(Money balance) { + this.balance = balance; + } + public GetAccountResponse() { } - public GetAccountResponse(String accountId) { + public GetAccountResponse(String accountId, Money balance) { this.accountId = accountId; + this.balance = balance; } } diff --git a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java index 5afb2de5..e90f4064 100644 --- a/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java +++ b/ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java @@ -3,4 +3,15 @@ import io.eventuate.tram.events.common.DomainEvent; public class ConsumerCreated implements DomainEvent { + private Long consumerId; + private ConsumerCreated() { + } + + public ConsumerCreated(Long consumerId) { + this.consumerId = consumerId; + } + + public Long getConsumerId() { + return consumerId; + } } diff --git a/ftgo-accounting-service/src/main/resources/application.properties b/ftgo-accounting-service/src/main/resources/application.properties index 70c4dcd6..6f7394c0 100644 --- a/ftgo-accounting-service/src/main/resources/application.properties +++ b/ftgo-accounting-service/src/main/resources/application.properties @@ -1,4 +1,5 @@ spring.application.name=ftgo-accounting-service +spring.sleuth.sampler.probability=1.0 management.endpoint.health.show-details=always diff --git a/ftgo-accounting-service/src/test/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandlerTest.java b/ftgo-accounting-service/src/test/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandlerTest.java index 702b2f06..3c390eda 100644 --- a/ftgo-accounting-service/src/test/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandlerTest.java +++ b/ftgo-accounting-service/src/test/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingServiceCommandHandlerTest.java @@ -71,7 +71,7 @@ public void shouldReply() { long consumerId = System.currentTimeMillis(); long orderId = 102L; - domainEventPublisher.publish("net.chrisrichardson.ftgo.consumerservice.domain.Consumer", consumerId, Collections.singletonList(new ConsumerCreated())); + domainEventPublisher.publish("net.chrisrichardson.ftgo.consumerservice.domain.Consumer", consumerId, Collections.singletonList(new ConsumerCreated(consumerId))); Eventually.eventually(() -> { accountRepository.find(Long.toString(consumerId)); diff --git a/ftgo-api-gateway/src/deployment/kubernetes/ftgo-api-gateway.yml b/ftgo-api-gateway/src/deployment/kubernetes/ftgo-api-gateway.yml index da9a31c7..d85da904 100644 --- a/ftgo-api-gateway/src/deployment/kubernetes/ftgo-api-gateway.yml +++ b/ftgo-api-gateway/src/deployment/kubernetes/ftgo-api-gateway.yml @@ -16,13 +16,16 @@ spec: # loadBalancerSourceRanges: # - 88.128.82.195/32 --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-api-gateway labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-api-gateway replicas: 1 strategy: rollingUpdate: diff --git a/ftgo-common/build.gradle b/ftgo-common/build.gradle index 51d5ccc1..04a17d65 100644 --- a/ftgo-common/build.gradle +++ b/ftgo-common/build.gradle @@ -13,8 +13,8 @@ dependencies { compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.7" - runtime "javax.xml.bind:jaxb-api:2.2.11" - runtime "com.sun.xml.bind:jaxb-core:2.2.11" - runtime "com.sun.xml.bind:jaxb-impl:2.2.11" + runtime "javax.xml.bind:jaxb-api:2.3.0" + runtime "com.sun.xml.bind:jaxb-core:2.3.0" + runtime "com.sun.xml.bind:jaxb-impl:2.3.0" runtime "javax.activation:activation:1.1.1" } diff --git a/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java b/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java index 0f75ec53..b413d419 100644 --- a/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java +++ b/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java @@ -61,6 +61,10 @@ public Money add(Money delta) { return new Money(amount.add(delta.amount)); } + public Money subtract(Money other) { + return new Money(amount.subtract(other.amount)); + } + public boolean isGreaterThanOrEqual(Money other) { return amount.compareTo(other.amount) >= 0; } diff --git a/ftgo-consumer-service/src/deployment/kubernetes/ftgo-consumer-service.yml b/ftgo-consumer-service/src/deployment/kubernetes/ftgo-consumer-service.yml index 28a7e8a4..c4a7d2ce 100644 --- a/ftgo-consumer-service/src/deployment/kubernetes/ftgo-consumer-service.yml +++ b/ftgo-consumer-service/src/deployment/kubernetes/ftgo-consumer-service.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-consumer-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-consumer-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-consumer-service replicas: 1 strategy: rollingUpdate: diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/Consumer.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/Consumer.java index 5206e643..cda73a52 100644 --- a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/Consumer.java +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/Consumer.java @@ -3,6 +3,8 @@ import io.eventuate.tram.events.publisher.ResultWithEvents; import net.chrisrichardson.ftgo.common.Money; import net.chrisrichardson.ftgo.common.PersonName; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.persistence.Access; import javax.persistence.AccessType; @@ -24,6 +26,8 @@ public class Consumer { @Embedded private PersonName name; + private static final Logger logger = LoggerFactory.getLogger(Consumer.class); + private Consumer() { } @@ -45,6 +49,8 @@ public PersonName getName() { } public static ResultWithEvents create(PersonName name) { - return new ResultWithEvents<>(new Consumer(name), new ConsumerCreated()); + Consumer newConsumer = new Consumer(name); +// return new ResultWithEvents<>(newConsumer, new ConsumerCreated(newConsumer.getId())); + return new ResultWithEvents<>(newConsumer, new ConsumerCreated()); } } diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java index 5afb2de5..9038bbc1 100644 --- a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java @@ -3,4 +3,15 @@ import io.eventuate.tram.events.common.DomainEvent; public class ConsumerCreated implements DomainEvent { + private Long consumerId; + + public ConsumerCreated(){} + + public ConsumerCreated(Long id){ + this.consumerId = id; + } + + public Long getConsumerId() { + return consumerId; + } } diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerService.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerService.java index 50e1bdfc..6f006e94 100644 --- a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerService.java +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerService.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; public class ConsumerService { @@ -19,7 +20,7 @@ public class ConsumerService { public void validateOrderForConsumer(long consumerId, Money orderTotal) { Optional consumer = consumerRepository.findById(consumerId); - consumer.orElseThrow(ConsumerNotFoundException::new).validateOrderByConsumer(orderTotal); + consumer.orElseThrow(ConsumerNotFoundException::new);//.validateOrderByConsumer(orderTotal); } @Transactional @@ -33,4 +34,9 @@ public ResultWithEvents create(PersonName name) { public Optional findById(long consumerId) { return consumerRepository.findById(consumerId); } + + + public List getAllConsumers() { + return (List) consumerRepository.findAll(); + } } diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/ConsumerController.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/ConsumerController.java index 76b2761c..f6267c96 100644 --- a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/ConsumerController.java +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/ConsumerController.java @@ -7,26 +7,43 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import static java.util.stream.Collectors.toList; + @RestController -@RequestMapping(path="/consumers") +@RequestMapping(path = "/consumers") public class ConsumerController { - private ConsumerService consumerService; + private ConsumerService consumerService; + + public ConsumerController(ConsumerService consumerService) { + this.consumerService = consumerService; + } + + @RequestMapping(method = RequestMethod.POST) + public CreateConsumerResponse create(@RequestBody CreateConsumerRequest request) { + ResultWithEvents result = consumerService.create(request.getName()); + return new CreateConsumerResponse(result.result.getId()); + } - public ConsumerController(ConsumerService consumerService) { - this.consumerService = consumerService; - } + @RequestMapping(method = RequestMethod.GET, path = "/{consumerId}") + public ResponseEntity get(@PathVariable long consumerId) { + return consumerService.findById(consumerId) + .map(consumer -> new ResponseEntity<>(new GetConsumerResponse(consumer.getName(), consumerId), HttpStatus.OK)) + .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); + } - @RequestMapping(method= RequestMethod.POST) - public CreateConsumerResponse create(@RequestBody CreateConsumerRequest request) { - ResultWithEvents result = consumerService.create(request.getName()); - return new CreateConsumerResponse(result.result.getId()); - } + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity get() { + return new ResponseEntity<>( + new GetConsumersResponse(consumerService.getAllConsumers() + .stream() + .map(this::makeGetConsumerResponse) + .collect(toList())), + HttpStatus.OK + ); + } - @RequestMapping(method= RequestMethod.GET, path="/{consumerId}") - public ResponseEntity get(@PathVariable long consumerId) { - return consumerService.findById(consumerId) - .map(consumer -> new ResponseEntity<>(new GetConsumerResponse(consumer.getName()), HttpStatus.OK)) - .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); - } + private GetConsumerResponse makeGetConsumerResponse(Consumer consumer) { + return new GetConsumerResponse(consumer.getName(), consumer.getId()); + } } diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumerResponse.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumerResponse.java index 0185bb91..c712d9ec 100644 --- a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumerResponse.java +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumerResponse.java @@ -4,13 +4,22 @@ public class GetConsumerResponse extends CreateConsumerResponse { private PersonName name; + private long consumerId; public PersonName getName() { return name; } - public GetConsumerResponse(PersonName name) { + public long getConsumerId() { + return consumerId; + } + + public void setConsumerId(long consumerId) { + this.consumerId = consumerId; + } + public GetConsumerResponse(PersonName name, long consumerId) { this.name = name; + this.consumerId = consumerId; } } diff --git a/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumersResponse.java b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumersResponse.java new file mode 100644 index 00000000..c681d030 --- /dev/null +++ b/ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumersResponse.java @@ -0,0 +1,19 @@ +package net.chrisrichardson.ftgo.consumerservice.web; + +import java.util.List; + +public class GetConsumersResponse { + private List consumers; + + public List getConsumers() { + return consumers; + } + + public void setConsumers(List consumers) { + this.consumers = consumers; + } + + public GetConsumersResponse(List consumers) { + this.consumers = consumers; + } +} diff --git a/ftgo-delivery-service/src/main/resources/application.properties b/ftgo-delivery-service/src/main/resources/application.properties index 1ad5dce5..1fc91833 100644 --- a/ftgo-delivery-service/src/main/resources/application.properties +++ b/ftgo-delivery-service/src/main/resources/application.properties @@ -7,6 +7,7 @@ management.endpoints.web.exposure.include=health,prometheus,beans,endpoints logging.level.org.springframework.cloud=INFO spring.jpa.generate-ddl=true +spring.jpa.properties.hibernate.hbm2ddl.auto=create logging.level.org.springframework.orm.jpa=INFO logging.level.org.hibernate.SQL=DEBUG logging.level.io.eventuate=DEBUG @@ -17,7 +18,7 @@ eventuate.database.schema=none spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_delivery_service spring.datasource.username=ftgo_delivery_service_user spring.datasource.password=ftgo_delivery_service_password -spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 diff --git a/ftgo-kitchen-service/src/deployment/kubernetes/ftgo-kitchen-service.yml b/ftgo-kitchen-service/src/deployment/kubernetes/ftgo-kitchen-service.yml index 341e6f8f..18df66ca 100644 --- a/ftgo-kitchen-service/src/deployment/kubernetes/ftgo-kitchen-service.yml +++ b/ftgo-kitchen-service/src/deployment/kubernetes/ftgo-kitchen-service.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-kitchen-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-kitchen-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-kitchen-service replicas: 1 strategy: rollingUpdate: @@ -37,23 +40,19 @@ spec: - name: JAVA_OPTS value: "-Dsun.net.inetaddr.ttl=30" - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://ftgo-mysql/eventuate + value: jdbc:mysql://ftgo-mysql/ftgo_kitchen_service - name: SPRING_DATASOURCE_USERNAME - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: username + value: ftgo_kitchen_service_user - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: password + value: ftgo_kitchen_service_password - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME value: com.mysql.jdbc.Driver - name: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS value: ftgo-kafka:9092 - name: EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING value: ftgo-zookeeper:2181 + - name: EVENTUATE_DATABASE_SCHEMA + value: ftgo_kitchen_service livenessProbe: httpGet: path: /actuator/health diff --git a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenService.java b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenService.java index f28a98b3..75f47ea3 100644 --- a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenService.java +++ b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenService.java @@ -3,13 +3,17 @@ import io.eventuate.tram.events.aggregates.ResultWithDomainEvents; import net.chrisrichardson.ftgo.common.RevisedOrderLineItem; import net.chrisrichardson.ftgo.kitchenservice.api.TicketDetails; +import net.chrisrichardson.ftgo.kitchenservice.api.TicketLineItem; import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.util.List; import java.util.Map; +import java.util.Optional; public class KitchenService { @@ -22,8 +26,10 @@ public class KitchenService { @Autowired private RestaurantRepository restaurantRepository; - public void createMenu(long id, RestaurantMenu menu) { - Restaurant restaurant = new Restaurant(id, menu.getMenuItems()); + private Logger logger = LoggerFactory.getLogger(getClass()); + + public void createMenu(long id, RestaurantMenu menu, long efficiency) { + Restaurant restaurant = new Restaurant(id, menu.getMenuItems(), efficiency); restaurantRepository.save(restaurant); } @@ -34,6 +40,18 @@ public void reviseMenu(long ticketId, RestaurantMenu revisedMenu) { } public Ticket createTicket(long restaurantId, Long ticketId, TicketDetails ticketDetails) { + Optional restaurant = restaurantRepository.findById(restaurantId); + Optional totalOrderQuantity = ticketDetails + .getLineItems() + .stream() + .map(TicketLineItem::getQuantity) + .reduce(Integer::sum); + if (restaurant.isPresent() && totalOrderQuantity.isPresent() && + restaurant.get().getEfficiency() < totalOrderQuantity.get()) { + logger.info("Restaurant efficiency exceeded!"); + throw new RestaurantCapacityExceededException(); + } + logger.info("Creating ticket..."); ResultWithDomainEvents rwe = Ticket.create(restaurantId, ticketId, ticketDetails); ticketRepository.save(rwe.result); domainEventPublisher.publish(rwe.result, rwe.events); diff --git a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/Restaurant.java b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/Restaurant.java index a1786f55..b3426669 100644 --- a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/Restaurant.java +++ b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/Restaurant.java @@ -26,12 +26,23 @@ public class Restaurant { @CollectionTable(name = "kitchen_service_restaurant_menu_items") private List menuItems; + public Long getEfficiency() { + return efficiency; + } + + public void setEfficiency(Long efficiency) { + this.efficiency = efficiency; + } + + private Long efficiency; + private Restaurant() { } - public Restaurant(long id, List menuItems) { + public Restaurant(long id, List menuItems, long efficiency) { this.id = id; this.menuItems = menuItems; + this.efficiency = efficiency; } public List reviseMenu(RestaurantMenu revisedMenu) { @@ -40,6 +51,7 @@ public List reviseMenu(RestaurantMenu revisedMenu) { public void verifyRestaurantDetails(TicketDetails ticketDetails) { // TODO - implement me + } public Long getId() { diff --git a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantCapacityExceededException.java b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantCapacityExceededException.java new file mode 100644 index 00000000..a57eb64f --- /dev/null +++ b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantCapacityExceededException.java @@ -0,0 +1,4 @@ +package net.chrisrichardson.ftgo.kitchenservice.domain; + +public class RestaurantCapacityExceededException extends RuntimeException { +} diff --git a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java index f5172f1f..cf8113bb 100644 --- a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java +++ b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceCommandHandler.java @@ -5,6 +5,7 @@ import io.eventuate.tram.messaging.common.Message; import io.eventuate.tram.sagas.participant.SagaCommandHandlersBuilder; import net.chrisrichardson.ftgo.kitchenservice.api.*; +import net.chrisrichardson.ftgo.kitchenservice.domain.RestaurantCapacityExceededException; import net.chrisrichardson.ftgo.kitchenservice.domain.RestaurantDetailsVerificationException; import net.chrisrichardson.ftgo.kitchenservice.domain.Ticket; import net.chrisrichardson.ftgo.kitchenservice.domain.KitchenService; @@ -48,7 +49,7 @@ private Message createTicket(CommandMessage Ticket ticket = kitchenService.createTicket(restaurantId, ticketId, ticketDetails); CreateTicketReply reply = new CreateTicketReply(ticket.getId()); return withLock(Ticket.class, ticket.getId()).withSuccess(reply); - } catch (RestaurantDetailsVerificationException e) { + } catch (RestaurantDetailsVerificationException | RestaurantCapacityExceededException e) { return withFailure(); } } diff --git a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceEventConsumer.java b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceEventConsumer.java index 4c916ea4..c708436a 100644 --- a/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceEventConsumer.java +++ b/ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/KitchenServiceEventConsumer.java @@ -27,7 +27,7 @@ private void createMenu(DomainEventEnvelope de) { String restaurantIds = de.getAggregateId(); long id = Long.parseLong(restaurantIds); RestaurantMenu menu = new RestaurantMenu(RestaurantEventMapper.toMenuItems(de.getEvent().getMenu().getMenuItems())); - kitchenService.createMenu(id, menu); + kitchenService.createMenu(id, menu, de.getEvent().getEfficiency()); } public void reviseMenu(DomainEventEnvelope de) { diff --git a/ftgo-kitchen-service/src/test/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenServiceInMemoryIntegrationTest.java b/ftgo-kitchen-service/src/test/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenServiceInMemoryIntegrationTest.java index edb12e4b..d92be2e8 100644 --- a/ftgo-kitchen-service/src/test/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenServiceInMemoryIntegrationTest.java +++ b/ftgo-kitchen-service/src/test/java/net/chrisrichardson/ftgo/kitchenservice/domain/KitchenServiceInMemoryIntegrationTest.java @@ -71,7 +71,7 @@ private String baseUrl(String path) { public void shouldCreateTicket() { long restaurantId = System.currentTimeMillis(); - Restaurant restaurant = new Restaurant(restaurantId, Collections.emptyList()); + Restaurant restaurant = new Restaurant(restaurantId, Collections.emptyList(), 50); restaurantRepository.save(restaurant); diff --git a/ftgo-order-history-service/src/deployment/kubernetes/ftgo-order-history-service.yml b/ftgo-order-history-service/src/deployment/kubernetes/ftgo-order-history-service.yml index c77fe573..bcea3b9a 100644 --- a/ftgo-order-history-service/src/deployment/kubernetes/ftgo-order-history-service.yml +++ b/ftgo-order-history-service/src/deployment/kubernetes/ftgo-order-history-service.yml @@ -9,13 +9,16 @@ spec: selector: svc: ftgo-order-history-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-order-history-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-order-history-service replicas: 1 strategy: rollingUpdate: diff --git a/ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderState.java b/ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderState.java index f3cb8d86..eb71444a 100644 --- a/ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderState.java +++ b/ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderState.java @@ -7,4 +7,5 @@ public enum OrderState { CANCEL_PENDING, CANCELLED, REVISION_PENDING, + COMPLETED } diff --git a/ftgo-order-service/build.gradle b/ftgo-order-service/build.gradle index 883c11d7..36f2d0f5 100644 --- a/ftgo-order-service/build.gradle +++ b/ftgo-order-service/build.gradle @@ -131,6 +131,7 @@ dependencies { compile project(":common-swagger") compile project(":ftgo-common-jpa") + compile 'org.jetbrains:annotations:13.0' compile "io.eventuate.tram.core:eventuate-tram-aggregate-domain-events:$eventuateTramVersion" compile "io.eventuate.tram.core:eventuate-tram-spring-jdbc-kafka:$eventuateTramVersion" compile "io.eventuate.tram.core:eventuate-tram-spring-commands:$eventuateTramVersion" @@ -154,8 +155,8 @@ dependencies { compile "io.grpc:grpc-protobuf:${grpcVersion}" compile "io.grpc:grpc-stub:${grpcVersion}" - compile "io.microservices.tools.canvas:microservice-canvas-springmvc:$microserviceCanvasVersion" - compile "io.microservices.tools.canvas:microservice-canvas-extractor-tram-sagas:$microserviceCanvasVersion" + //compile "io.microservices.tools.canvas:microservice-canvas-springmvc:$microserviceCanvasVersion" + //compile "io.microservices.tools.canvas:microservice-canvas-extractor-tram-sagas:$microserviceCanvasVersion" compile "io.eventuate.tram.core:eventuate-tram-spring-messaging:$eventuateTramVersion" compile "io.eventuate.tram.sagas:eventuate-tram-sagas-spring-orchestration:$eventuateTramSagasVersion" diff --git a/ftgo-order-service/src/deployment/kubernetes-prometheus/rbac.yml b/ftgo-order-service/src/deployment/kubernetes-prometheus/rbac.yml index 47955c72..7b04506b 100644 --- a/ftgo-order-service/src/deployment/kubernetes-prometheus/rbac.yml +++ b/ftgo-order-service/src/deployment/kubernetes-prometheus/rbac.yml @@ -1,4 +1,4 @@ -apiVersion: rbac.authorization.k8s.io/v1beta1 +apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: prometheus-operator diff --git a/ftgo-order-service/src/deployment/kubernetes/ftgo-order-service.yml b/ftgo-order-service/src/deployment/kubernetes/ftgo-order-service.yml index 1258554b..973f043b 100644 --- a/ftgo-order-service/src/deployment/kubernetes/ftgo-order-service.yml +++ b/ftgo-order-service/src/deployment/kubernetes/ftgo-order-service.yml @@ -17,13 +17,16 @@ spec: selector: svc: ftgo-order-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-order-service labels: application: ftgo spec: + selector: + matchLabels: + svc: ftgo-order-service replicas: 1 strategy: rollingUpdate: @@ -43,25 +46,21 @@ spec: name: httpport env: - name: JAVA_OPTS - value: "-Dsun.net.inetaddr.ttl=30" + value: "-Dsun.net.inetaddr.ttl=30 -Xmx192m" - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://ftgo-mysql/eventuate + value: jdbc:mysql://ftgo-mysql/ftgo_order_service - name: SPRING_DATASOURCE_USERNAME - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: username + value: ftgo_order_service_user - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: password + value: ftgo_order_service_password - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME value: com.mysql.jdbc.Driver - name: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS value: ftgo-kafka:9092 - name: EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING value: ftgo-zookeeper:2181 + - name: EVENTUATE_DATABASE_SCHEMA + value: ftgo_order_service livenessProbe: httpGet: path: /actuator/health diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/main/OrderServiceMain.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/main/OrderServiceMain.java index 9249122c..3479bb7a 100644 --- a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/main/OrderServiceMain.java +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/main/OrderServiceMain.java @@ -1,8 +1,8 @@ package net.chrisrichardson.ftgo.orderservice.main; import io.eventuate.tram.spring.jdbckafka.TramJdbcKafkaConfiguration; -import io.microservices.canvas.extractor.spring.annotations.ServiceDescription; -import io.microservices.canvas.springmvc.MicroserviceCanvasWebConfiguration; +//import io.microservices.canvas.extractor.spring.annotations.ServiceDescription; +//import io.microservices.canvas.springmvc.MicroserviceCanvasWebConfiguration; import net.chrisrichardson.eventstore.examples.customersandorders.commonswagger.CommonSwaggerConfiguration; import net.chrisrichardson.ftgo.orderservice.grpc.GrpcConfiguration; import net.chrisrichardson.ftgo.orderservice.messaging.OrderServiceMessagingConfiguration; @@ -14,9 +14,9 @@ @SpringBootApplication @Import({OrderWebConfiguration.class, OrderCommandHandlersConfiguration.class, OrderServiceMessagingConfiguration.class, - TramJdbcKafkaConfiguration.class, CommonSwaggerConfiguration.class, GrpcConfiguration.class, - MicroserviceCanvasWebConfiguration.class}) -@ServiceDescription(description="Manages Orders", capabilities = "Order Management") + TramJdbcKafkaConfiguration.class, CommonSwaggerConfiguration.class, GrpcConfiguration.class/*, + MicroserviceCanvasWebConfiguration.class*/}) +//@ServiceDescription(description="Manages Orders", capabilities = "Order Management") public class OrderServiceMain { public static void main(String[] args) { diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/AccountingServiceProxy.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/AccountingServiceProxy.java index f360939b..ce3c92bf 100644 --- a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/AccountingServiceProxy.java +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/AccountingServiceProxy.java @@ -5,6 +5,7 @@ import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder; import net.chrisrichardson.ftgo.accountservice.api.AccountingServiceChannels; import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand; +import net.chrisrichardson.ftgo.accountservice.api.CheckAccountLimitCommand; public class AccountingServiceProxy { @@ -14,4 +15,9 @@ public class AccountingServiceProxy { .withReply(Success.class) .build(); + public final CommandEndpoint checkAccountLimit= CommandEndpointBuilder + .forCommand(CheckAccountLimitCommand.class) + .withChannel(AccountingServiceChannels.accountingServiceChannel) + .withReply(Success.class) + .build(); } diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java index b7944eeb..9fc63040 100644 --- a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSaga.java @@ -21,6 +21,8 @@ public CreateOrderSaga(OrderServiceProxy orderService, ConsumerServiceProxy cons .withCompensation(orderService.reject, CreateOrderSagaState::makeRejectOrderCommand) .step() .invokeParticipant(consumerService.validateOrder, CreateOrderSagaState::makeValidateOrderByConsumerCommand) + .step() + .invokeParticipant(accountingService.checkAccountLimit, CreateOrderSagaState::makeCheckAccountLimitCommand) .step() .invokeParticipant(kitchenService.create, CreateOrderSagaState::makeCreateTicketCommand) .onReply(CreateTicketReply.class, CreateOrderSagaState::handleCreateTicketReply) diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSagaState.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSagaState.java index 274cea75..ee9b9b0b 100644 --- a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSagaState.java +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/createorder/CreateOrderSagaState.java @@ -1,6 +1,7 @@ package net.chrisrichardson.ftgo.orderservice.sagas.createorder; import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand; +import net.chrisrichardson.ftgo.accountservice.api.CheckAccountLimitCommand; import net.chrisrichardson.ftgo.consumerservice.api.ValidateOrderByConsumer; import net.chrisrichardson.ftgo.orderservice.api.events.OrderDetails; import net.chrisrichardson.ftgo.orderservice.api.events.OrderLineItem; @@ -101,6 +102,10 @@ ValidateOrderByConsumer makeValidateOrderByConsumerCommand() { return x; } + CheckAccountLimitCommand makeCheckAccountLimitCommand() { + return new CheckAccountLimitCommand(getOrderDetails().getConsumerId(), getOrderId(), getOrderDetails().getOrderTotal()); + } + AuthorizeCommand makeAuthorizeCommand() { return new AuthorizeCommand().withConsumerId(getOrderDetails().getConsumerId()).withOrderId(getOrderId()).withOrderTotal(getOrderDetails().getOrderTotal().asString()); } diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/GetOrdersResponse.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/GetOrdersResponse.java new file mode 100644 index 00000000..98cd66b9 --- /dev/null +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/GetOrdersResponse.java @@ -0,0 +1,19 @@ +package net.chrisrichardson.ftgo.orderservice.web; + +import java.util.List; + +public class GetOrdersResponse { + private List orders; + + public GetOrdersResponse(List orders) { + this.orders = orders; + } + + public List getOrders() { + return orders; + } + + public void setOrders(List orders) { + this.orders = orders; + } +} diff --git a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/OrderController.java b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/OrderController.java index 1a3c5d60..1a5afe28 100644 --- a/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/OrderController.java +++ b/ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/OrderController.java @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import java.util.List; import java.util.Optional; import static java.util.stream.Collectors.toList; @@ -20,55 +21,64 @@ @RequestMapping(path = "/orders") public class OrderController { - private OrderService orderService; + private OrderService orderService; - private OrderRepository orderRepository; + private OrderRepository orderRepository; - public OrderController(OrderService orderService, OrderRepository orderRepository) { - this.orderService = orderService; - this.orderRepository = orderRepository; - } + public OrderController(OrderService orderService, OrderRepository orderRepository) { + this.orderService = orderService; + this.orderRepository = orderRepository; + } - @RequestMapping(method = RequestMethod.POST) - public CreateOrderResponse create(@RequestBody CreateOrderRequest request) { - Order order = orderService.createOrder(request.getConsumerId(), - request.getRestaurantId(), - new DeliveryInformation(request.getDeliveryTime(), request.getDeliveryAddress()), - request.getLineItems().stream().map(x -> new MenuItemIdAndQuantity(x.getMenuItemId(), x.getQuantity())).collect(toList()) - ); - return new CreateOrderResponse(order.getId()); - } + @RequestMapping(method = RequestMethod.POST) + public CreateOrderResponse create(@RequestBody CreateOrderRequest request) { + Order order = orderService.createOrder(request.getConsumerId(), + request.getRestaurantId(), + new DeliveryInformation(request.getDeliveryTime(), request.getDeliveryAddress()), + request.getLineItems().stream().map(x -> new MenuItemIdAndQuantity(x.getMenuItemId(), x.getQuantity())).collect(toList()) + ); + return new CreateOrderResponse(order.getId()); + } - @RequestMapping(path = "/{orderId}", method = RequestMethod.GET) - public ResponseEntity getOrder(@PathVariable long orderId) { - Optional order = orderRepository.findById(orderId); - return order.map(o -> new ResponseEntity<>(makeGetOrderResponse(o), HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); - } + @RequestMapping(path = "/{orderId}", method = RequestMethod.GET) + public ResponseEntity getOrder(@PathVariable long orderId) { + Optional order = orderRepository.findById(orderId); + return order.map(o -> new ResponseEntity<>(makeGetOrderResponse(o), HttpStatus.OK)).orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); + } - private GetOrderResponse makeGetOrderResponse(Order order) { - return new GetOrderResponse(order.getId(), order.getState(), order.getOrderTotal()); - } + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity getAll() { + List orders = (List) orderRepository.findAll(); + return new ResponseEntity<>( + new GetOrdersResponse(orders.stream().map(this::makeGetOrderResponse).collect(toList())), + HttpStatus.OK + ); + } - @RequestMapping(path = "/{orderId}/cancel", method = RequestMethod.POST) - public ResponseEntity cancel(@PathVariable long orderId) { - try { - Order order = orderService.cancel(orderId); - return new ResponseEntity<>(makeGetOrderResponse(order), HttpStatus.OK); - } catch (OrderNotFoundException e) { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); + private GetOrderResponse makeGetOrderResponse(Order order) { + return new GetOrderResponse(order.getId(), order.getState(), order.getOrderTotal()); } - } - - @RequestMapping(path = "/{orderId}/revise", method = RequestMethod.POST) - public ResponseEntity revise(@PathVariable long orderId, @RequestBody ReviseOrderRequest request) { - try { - Order order = orderService.reviseOrder(orderId, new OrderRevision(Optional.empty(), request.getRevisedOrderLineItems())); - return new ResponseEntity<>(makeGetOrderResponse(order), HttpStatus.OK); - } catch (OrderNotFoundException e) { - return new ResponseEntity<>(HttpStatus.NOT_FOUND); + + @RequestMapping(path = "/{orderId}/cancel", method = RequestMethod.POST) + public ResponseEntity cancel(@PathVariable long orderId) { + try { + Order order = orderService.cancel(orderId); + return new ResponseEntity<>(makeGetOrderResponse(order), HttpStatus.OK); + } catch (OrderNotFoundException e) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } + + @RequestMapping(path = "/{orderId}/revise", method = RequestMethod.POST) + public ResponseEntity revise(@PathVariable long orderId, @RequestBody ReviseOrderRequest request) { + try { + Order order = orderService.reviseOrder(orderId, new OrderRevision(Optional.empty(), request.getRevisedOrderLineItems())); + return new ResponseEntity<>(makeGetOrderResponse(order), HttpStatus.OK); + } catch (OrderNotFoundException e) { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } } - } } diff --git a/ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json b/ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json index 7670229d..5972e82b 100644 --- a/ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json +++ b/ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json @@ -4,6 +4,9 @@ "name": { "type": "string" }, + "efficiency": { + "type": "integer" + }, "address": { "type": "object", "properties": { diff --git a/ftgo-restaurant-service/src/deployment/kubernetes/ftgo-restaurant-service.yml b/ftgo-restaurant-service/src/deployment/kubernetes/ftgo-restaurant-service.yml index bf251277..a8494a86 100644 --- a/ftgo-restaurant-service/src/deployment/kubernetes/ftgo-restaurant-service.yml +++ b/ftgo-restaurant-service/src/deployment/kubernetes/ftgo-restaurant-service.yml @@ -9,7 +9,7 @@ spec: selector: svc: ftgo-restaurant-service --- -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: name: ftgo-restaurant-service @@ -17,6 +17,9 @@ metadata: application: ftgo svc: ftgo-restaurant-service spec: + selector: + matchLabels: + svc: ftgo-restaurant-service replicas: 1 strategy: rollingUpdate: @@ -36,25 +39,21 @@ spec: name: httpport env: - name: JAVA_OPTS - value: "-Dsun.net.inetaddr.ttl=30" + value: "-Dsun.net.inetaddr.ttl=30 -Xmx192m" - name: SPRING_DATASOURCE_URL - value: jdbc:mysql://ftgo-mysql/eventuate + value: jdbc:mysql://ftgo-mysql/ftgo_restaurant_service - name: SPRING_DATASOURCE_USERNAME - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: username + value: ftgo_restaurant_service_user - name: SPRING_DATASOURCE_PASSWORD - valueFrom: - secretKeyRef: - name: ftgo-db-secret - key: password + value: ftgo_restaurant_service_password - name: SPRING_DATASOURCE_DRIVER_CLASS_NAME value: com.mysql.jdbc.Driver - name: EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS value: ftgo-kafka:9092 - name: EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING value: ftgo-zookeeper:2181 + - name: EVENTUATE_DATABASE_SCHEMA + value: ftgo_restaurant_service livenessProbe: httpGet: path: /actuator/health diff --git a/ftgo-restaurant-service/src/integration-test/java/net/chrisrichardson/ftgo/restaurantservice/contract/DeliveryserviceMessagingBase.java b/ftgo-restaurant-service/src/integration-test/java/net/chrisrichardson/ftgo/restaurantservice/contract/DeliveryserviceMessagingBase.java index b199da3e..f461ad08 100644 --- a/ftgo-restaurant-service/src/integration-test/java/net/chrisrichardson/ftgo/restaurantservice/contract/DeliveryserviceMessagingBase.java +++ b/ftgo-restaurant-service/src/integration-test/java/net/chrisrichardson/ftgo/restaurantservice/contract/DeliveryserviceMessagingBase.java @@ -42,11 +42,11 @@ public RestaurantDomainEventPublisher orderAggregateEventPublisher(DomainEventPu private RestaurantDomainEventPublisher restaurantDomainEventPublisher; protected void restaurantCreated() { - Restaurant restaurant = new Restaurant("Yummy Indian", new RestaurantMenu(Collections.emptyList())); + Restaurant restaurant = new Restaurant("Yummy Indian", new RestaurantMenu(Collections.emptyList()), 10L); restaurant.setId(99L); restaurantDomainEventPublisher.publish(restaurant, Collections.singletonList(new RestaurantCreated(restaurant.getName(), new Address("1 Main Street", "Unit 99", "Oakland", "CA", "94611"), - restaurant.getMenu()))); + restaurant.getMenu(), restaurant.getEfficiency()))); } } diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java index 7e8b7c0c..dfe4801b 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java @@ -7,15 +7,17 @@ public class CreateRestaurantRequest { private String name; private Address address; private RestaurantMenu menu; + private Long efficiency; // how many orders can be processed within an hour private CreateRestaurantRequest() { } - public CreateRestaurantRequest(String name, Address address, RestaurantMenu menu) { + public CreateRestaurantRequest(String name, Address address, RestaurantMenu menu, Long efficiency) { this.name = name; this.address = address; this.menu = menu; + this.efficiency = efficiency; } public String getName() { @@ -37,4 +39,13 @@ public void setMenu(RestaurantMenu menu) { public Address getAddress() { return address; } + + public Long getEfficiency() { + return efficiency; + } + + public void setEfficiency(Long efficiency) { + this.efficiency = efficiency; + } + } diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java index f4f0851b..ec43a760 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java @@ -19,12 +19,20 @@ public class Restaurant { private String name; + private Long efficiency; + @Embedded private RestaurantMenu menu; private Restaurant() { } + public Restaurant(String name, RestaurantMenu menu, Long efficiency) { + this.name = name; + this.menu = menu; + this.efficiency = efficiency; + } + public void setId(Long id) { this.id = id; } @@ -37,13 +45,6 @@ public void setName(String name) { this.name = name; } - - public Restaurant(String name, RestaurantMenu menu) { - this.name = name; - this.menu = menu; - } - - public Long getId() { return id; } @@ -51,4 +52,13 @@ public Long getId() { public RestaurantMenu getMenu() { return menu; } + + public Long getEfficiency() { + return efficiency; + } + + public void setEfficiency(Long efficiency) { + this.efficiency = efficiency; + } + } diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java index ecd4ae2a..dd3662ad 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java @@ -5,6 +5,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Collections; +import java.util.List; import java.util.Optional; @Transactional @@ -18,13 +19,17 @@ public class RestaurantService { private RestaurantDomainEventPublisher restaurantDomainEventPublisher; public Restaurant create(CreateRestaurantRequest request) { - Restaurant restaurant = new Restaurant(request.getName(), request.getMenu()); + Restaurant restaurant = new Restaurant(request.getName(), request.getMenu(), request.getEfficiency()); restaurantRepository.save(restaurant); - restaurantDomainEventPublisher.publish(restaurant, Collections.singletonList(new RestaurantCreated(request.getName(), request.getAddress(), request.getMenu()))); + restaurantDomainEventPublisher.publish(restaurant, Collections.singletonList(new RestaurantCreated(request.getName(), request.getAddress(), request.getMenu(), request.getEfficiency()))); return restaurant; } public Optional findById(long restaurantId) { return restaurantRepository.findById(restaurantId); } + + public List getAllRestaurants() { + return (List) restaurantRepository.findAll(); + } } diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreated.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreated.java index 7e320d11..62562a66 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreated.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreated.java @@ -8,6 +8,16 @@ public class RestaurantCreated implements RestaurantDomainEvent { private Address address; private RestaurantMenu menu; + public Long getEfficiency() { + return efficiency; + } + + public void setEfficiency(Long efficiency) { + this.efficiency = efficiency; + } + + private Long efficiency; + public String getName() { return name; } @@ -15,10 +25,11 @@ public String getName() { private RestaurantCreated() { } - public RestaurantCreated(String name, Address address, RestaurantMenu menu) { + public RestaurantCreated(String name, Address address, RestaurantMenu menu, Long efficiency) { this.name = name; this.address = address; this.menu = menu; + this.efficiency = efficiency; } public RestaurantMenu getMenu() { diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/GetRestaurantsResponse.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/GetRestaurantsResponse.java new file mode 100644 index 00000000..b66b193a --- /dev/null +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/GetRestaurantsResponse.java @@ -0,0 +1,19 @@ +package net.chrisrichardson.ftgo.restaurantservice.web; + +import java.util.List; + +public class GetRestaurantsResponse { + private List restaurants; + + public GetRestaurantsResponse(List restaurants) { + this.restaurants = restaurants; + } + + public List getRestaurants() { + return restaurants; + } + + public void setRestaurants(List restaurants) { + this.restaurants = restaurants; + } +} diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/RestaurantController.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/RestaurantController.java index f07f8042..432fb0fb 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/RestaurantController.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/RestaurantController.java @@ -8,6 +8,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.stream.Collectors; + @RestController @RequestMapping(path = "/restaurants") public class RestaurantController { @@ -28,9 +30,13 @@ public ResponseEntity get(@PathVariable long restaurantId .orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND)); } + @RequestMapping(method = RequestMethod.GET) + public ResponseEntity get() { + return new ResponseEntity<>(new GetRestaurantsResponse(restaurantService.getAllRestaurants().stream() + .map(this::makeGetRestaurantResponse).collect(Collectors.toList())), HttpStatus.OK); + } + private GetRestaurantResponse makeGetRestaurantResponse(Restaurant r) { return new GetRestaurantResponse(r.getId(), r.getName()); } - - } diff --git a/ftgo-restaurant-service/src/test/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreatedSerializationTest.java b/ftgo-restaurant-service/src/test/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreatedSerializationTest.java index a531d230..0aabd13b 100644 --- a/ftgo-restaurant-service/src/test/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreatedSerializationTest.java +++ b/ftgo-restaurant-service/src/test/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantCreatedSerializationTest.java @@ -34,7 +34,7 @@ public void shouldSerialize() throws JSONException { ValidatingJSONMapper mapper = ValidatingJSONMapper.forSchema("/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json"); RestaurantCreated event = new RestaurantCreated(AJANTA_RESTAURANT_NAME, RESTAURANT_ADDRESS, - new RestaurantMenu(Collections.singletonList(CHICKEN_VINDALOO_MENU_ITEM))); + new RestaurantMenu(Collections.singletonList(CHICKEN_VINDALOO_MENU_ITEM)), 10L); String json = mapper.toJSON(event); assertNotNull(json); } diff --git a/gradle.properties b/gradle.properties index 96079472..60f1fa8f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,9 @@ deployUrl=file:///Users/cer/.m2/testdeploy -eventuateMavenRepoUrl=https://dl.bintray.com/eventuateio-oss/eventuate-maven-release,https://dl.bintray.com/eventuateio-oss/eventuate-maven-milestone,https://dl.bintray.com/eventuateio-oss/microservice-canvas-tools-release,file:///Users/cer/.m2/testdeploy,https://dl.bintray.com/eventuateio-oss/eventuate-maven-rc,https://dl.bintray.com/eventuateio-oss/microservice-canvas-tools-rc,https://snapshots.repositories.eventuate.io/repository +#eventuateMavenRepoUrl=https://dl.bintray.com/eventuateio-oss/eventuate-maven-release,https://dl.bintray.com/eventuateio-oss/eventuate-maven-milestone,https://dl.bintray.com/eventuateio-oss/microservice-canvas-tools-release,file:///Users/cer/.m2/testdeploy,https://dl.bintray.com/eventuateio-oss/eventuate-maven-rc,https://dl.bintray.com/eventuateio-oss/microservice-canvas-tools-rc,https://snapshots.repositories.eventuate.io/repository +eventuateMavenRepoUrl=file:///Users/cer/.m2/testdeploy,https://snapshots.repositories.eventuate.io/repository + springBootVersion=2.1.1.RELEASE restAssuredVersion=2.9.0