├── .circleci ├── config.yml ├── generate-config.sh ├── setenv-circle-ci.sh └── upgrade-docker-compose.sh ├── .gitattributes ├── .gitignore ├── LICENSE.md ├── README.adoc ├── TODO.txt ├── _wait-for-services.sh ├── build-and-restart-service.sh ├── build-and-test-all.sh ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── groovy │ ├── ComponentTestsPlugin.groovy │ ├── FtgoApiDependencyResolverPlugin.groovy │ ├── FtgoJSONSchema2PojoPlugin.groovy │ ├── FtgoJSONSchemaToPojoCodeGen.groovy │ ├── FtgoOpenApiCodeGenPlugin.groovy │ ├── FtgoResolveAPIDependencies.groovy │ ├── FtgoServicePlugin.groovy │ ├── IntegrationTestsPlugin.groovy │ ├── JSONSchemaSource.groovy │ ├── WaitForMySql.java │ └── WaitForMySqlPlugin.java ├── common-swagger ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── eventstore │ └── examples │ └── customersandorders │ └── commonswagger │ └── CommonSwaggerConfiguration.java ├── deployment └── kubernetes │ ├── cdc-service │ └── ftgo-cdc-service.yml │ ├── misc │ └── create-db-secret.sh │ ├── scripts │ ├── kubernetes-delete-all.sh │ ├── kubernetes-delete-volumes.sh │ ├── kubernetes-deploy-all.sh │ ├── kubernetes-deploy-and-test.sh │ ├── kubernetes-kill-port-forwarding.sh │ ├── kubernetes-run-end-to-end-tests.sh │ ├── kubernetes-wait-for-ready-pods.sh │ └── port-forwards.sh │ └── stateful-services │ ├── ftgo-db-secret.yml │ ├── ftgo-dynamodb-local.yml │ ├── ftgo-kafka-deployment.yml │ ├── ftgo-mysql-deployment.yml │ └── ftgo-zookeeper-deployment.yml ├── docker-compose-api-gateway-graphql.yml ├── docker-compose.yml ├── dynamodblocal-init ├── Dockerfile ├── build-docker.sh ├── create-dynamodb-tables.sh ├── ftgo-order-history.json ├── run-docker.sh └── wait-for-dynamodblocal.sh ├── dynamodblocal ├── Dockerfile └── build-docker.sh ├── ftgo-accounting-service-api-spec └── src │ └── main │ └── resources │ └── messages │ └── AuthorizeCommand.json ├── ftgo-accounting-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── accountservice │ └── api │ ├── AccountDisabledReply.java │ ├── AccountingServiceChannels.java │ ├── ReverseAuthorizationCommand.java │ └── ReviseAuthorization.java ├── ftgo-accounting-service-contracts ├── build.gradle └── src │ └── main │ └── resources │ └── contracts │ └── Authorize.groovy ├── ftgo-accounting-service ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ └── kubernetes │ │ └── ftgo-accounting-service.yml │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ ├── accountingservice │ │ │ ├── domain │ │ │ │ ├── Account.java │ │ │ │ ├── AccountAuthorizationFailed.java │ │ │ │ ├── AccountAuthorizedEvent.java │ │ │ │ ├── AccountCommand.java │ │ │ │ ├── AccountCreatedEvent.java │ │ │ │ ├── AccountDisabledException.java │ │ │ │ ├── AccountServiceConfiguration.java │ │ │ │ ├── AccountingService.java │ │ │ │ ├── AuthorizeCommandInternal.java │ │ │ │ ├── CreateAccountCommand.java │ │ │ │ ├── ReverseAuthorizationCommandInternal.java │ │ │ │ └── ReviseAuthorizationCommandInternal.java │ │ │ ├── main │ │ │ │ └── AccountingServiceMain.java │ │ │ ├── messaging │ │ │ │ ├── AccountServiceChannelConfiguration.java │ │ │ │ ├── AccountingEventConsumer.java │ │ │ │ ├── AccountingMessagingConfiguration.java │ │ │ │ └── AccountingServiceCommandHandler.java │ │ │ └── web │ │ │ │ ├── AccountingWebConfiguration.java │ │ │ │ ├── AccountsController.java │ │ │ │ └── GetAccountResponse.java │ │ │ ├── accountservice │ │ │ └── api │ │ │ │ └── AuthorizeCommand.java │ │ │ └── consumerservice │ │ │ └── domain │ │ │ └── ConsumerCreated.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── accountingservice │ └── messaging │ └── AccountingServiceCommandHandlerTest.java ├── ftgo-api-gateway-graphql ├── .dockerignore ├── Dockerfile ├── jest.config.js ├── package-lock.json ├── package.json ├── queries.txt ├── src │ ├── ConsumerServiceProxy.js │ ├── OrderServiceProxy.js │ ├── RestaurantServiceProxy.js │ ├── index.js │ ├── schema.js │ └── server.ts ├── tests │ ├── common │ │ └── ftgo-graphql-client.js │ ├── end-to-end │ │ └── client.end2end.test.js │ └── unit │ │ ├── client.test.js │ │ └── schema.test.js └── tsconfig.json ├── ftgo-api-gateway ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ ├── kubernetes-node-port │ │ └── ftgo-api-gateway-NodePort.yml │ └── kubernetes │ │ └── ftgo-api-gateway.yml │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── apiagateway │ │ │ ├── ApiGatewayApplication.java │ │ │ ├── consumers │ │ │ ├── ConsumerConfiguration.java │ │ │ └── ConsumerDestinations.java │ │ │ ├── orders │ │ │ ├── OrderConfiguration.java │ │ │ ├── OrderDestinations.java │ │ │ ├── OrderDetails.java │ │ │ └── OrderHandlers.java │ │ │ └── proxies │ │ │ ├── AccountingService.java │ │ │ ├── BillInfo.java │ │ │ ├── DeliveryInfo.java │ │ │ ├── DeliveryService.java │ │ │ ├── KitchenService.java │ │ │ ├── OrderInfo.java │ │ │ ├── OrderNotFoundException.java │ │ │ ├── OrderServiceProxy.java │ │ │ └── TicketInfo.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── apiagateway │ │ ├── ApiGatewayIntegrationTest.java │ │ ├── ApiGatewayIntegrationTestConfiguration.java │ │ └── contract │ │ ├── OrderServiceProxyIntegrationTest.java │ │ └── TestConfiguration.java │ └── resources │ └── application.properties ├── ftgo-common-jpa ├── build.gradle └── src │ └── main │ └── resources │ └── META-INF │ └── orm.xml ├── ftgo-common ├── build.gradle └── src │ ├── main │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── common │ │ ├── Address.java │ │ ├── CommonConfiguration.java │ │ ├── CommonJsonMapperInitializer.java │ │ ├── Money.java │ │ ├── MoneyModule.java │ │ ├── NotYetImplementedException.java │ │ ├── PersonName.java │ │ ├── RevisedOrderLineItem.java │ │ └── UnsupportedStateTransitionException.java │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── common │ ├── MoneySerializationTest.java │ └── MoneyTest.java ├── ftgo-consumer-service-api-spec └── src │ └── main │ └── resources │ ├── ValidateOrderByConsumer.json │ └── ftgo-consumer-service-swagger.json ├── ftgo-consumer-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── consumerservice │ └── api │ └── ConsumerServiceChannels.java ├── ftgo-consumer-service-contracts ├── build.gradle └── src │ └── main │ └── resources │ └── contracts │ └── VerifyConsumer.groovy ├── ftgo-consumer-service ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ └── kubernetes │ │ └── ftgo-consumer-service.yml │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── consumerservice │ │ │ ├── api │ │ │ └── ValidateOrderByConsumer.java │ │ │ ├── domain │ │ │ ├── Consumer.java │ │ │ ├── ConsumerCreated.java │ │ │ ├── ConsumerNotFoundException.java │ │ │ ├── ConsumerRepository.java │ │ │ ├── ConsumerService.java │ │ │ ├── ConsumerServiceCommandHandlers.java │ │ │ ├── ConsumerServiceConfiguration.java │ │ │ └── ConsumerVerificationFailedException.java │ │ │ ├── main │ │ │ └── ConsumerServiceMain.java │ │ │ └── web │ │ │ ├── ConsumerController.java │ │ │ ├── ConsumerWebConfiguration.java │ │ │ ├── CreateConsumerRequest.java │ │ │ ├── CreateConsumerResponse.java │ │ │ └── GetConsumerResponse.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── consumerservice │ ├── ConsumerServiceInMemoryIntegrationTest.java │ ├── api │ └── ValidateOrderByConsumerTest.java │ └── web │ └── ConsumerControllerTest.java ├── ftgo-delivery-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── deliveryservice │ └── api │ └── web │ ├── ActionInfo.java │ ├── CourierAvailability.java │ ├── DeliveryActionType.java │ ├── DeliveryInfo.java │ ├── DeliveryState.java │ └── DeliveryStatus.java ├── ftgo-delivery-service ├── Dockerfile ├── build.gradle └── src │ ├── component-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── deliveryservice │ │ ├── DeliveryServiceInProcessComponentTest.java │ │ ├── DeliveryServiceOutOfProcessComponentTest.java │ │ └── RestaurantEventMother.java │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── deliveryservice │ │ └── domain │ │ ├── CourierJpaTest.java │ │ ├── DeliveryJpaTest.java │ │ └── RestaurantJpaTest.java │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── deliveryservice │ │ │ ├── domain │ │ │ ├── Action.java │ │ │ ├── Courier.java │ │ │ ├── CourierRepository.java │ │ │ ├── CustomCourierRepository.java │ │ │ ├── CustomCourierRepositoryImpl.java │ │ │ ├── Delivery.java │ │ │ ├── DeliveryRepository.java │ │ │ ├── DeliveryService.java │ │ │ ├── DeliveryServiceDomainConfiguration.java │ │ │ ├── Plan.java │ │ │ ├── Restaurant.java │ │ │ └── RestaurantRepository.java │ │ │ ├── main │ │ │ └── DeliveryServiceMain.java │ │ │ ├── messaging │ │ │ ├── DeliveryMessageHandlers.java │ │ │ ├── DeliveryServiceMessagingConfiguration.java │ │ │ └── RestaurantEventMapper.java │ │ │ └── web │ │ │ ├── DeliveryServiceController.java │ │ │ └── DeliveryServiceWebConfiguration.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── deliveryservice │ └── domain │ ├── DeliveryServiceTest.java │ └── DeliveryServiceTestData.java ├── ftgo-end-to-end-tests ├── build.gradle ├── src │ └── test │ │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── endtoendtests │ │ │ └── EndToEndTests.java │ │ └── resources │ │ └── contracts │ │ └── create-revise-cancel.feature └── swagger-codegen-config │ ├── consumer-service.json │ └── restaurant-service.json ├── ftgo-kitchen-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── kitchenservice │ └── api │ ├── BeginCancelTicketCommand.java │ ├── BeginReviseTicketCommand.java │ ├── CancelCreateTicket.java │ ├── ChangeTicketLineItemQuantity.java │ ├── ConfirmCancelTicketCommand.java │ ├── ConfirmCreateTicket.java │ ├── ConfirmReviseTicketCommand.java │ ├── CreateTicket.java │ ├── CreateTicketReply.java │ ├── KitchenServiceChannels.java │ ├── TicketDetails.java │ ├── TicketLineItem.java │ ├── UndoBeginCancelTicketCommand.java │ ├── UndoBeginReviseTicketCommand.java │ ├── events │ ├── TicketAcceptedEvent.java │ ├── TicketCancelled.java │ └── TicketDomainEvent.java │ └── web │ └── TicketAcceptance.java ├── ftgo-kitchen-service-contracts ├── build.gradle └── src │ └── main │ └── resources │ └── contracts │ ├── deliveryservice │ └── messaging │ │ └── TicketAcceptedEvent.groovy │ └── messaging │ ├── ConfirmCreateTicket.groovy │ └── CreateTicket.groovy ├── ftgo-kitchen-service ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ └── kubernetes │ │ └── ftgo-kitchen-service.yml │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── kitchenservice │ │ └── contract │ │ ├── DeliveryserviceMessagingBase.java │ │ └── MessagingBase.java │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── kitchenservice │ │ │ ├── domain │ │ │ ├── CancelCommand.java │ │ │ ├── ChangeLineItemQuantityCommand.java │ │ │ ├── KitchenDomainConfiguration.java │ │ │ ├── KitchenService.java │ │ │ ├── MenuItem.java │ │ │ ├── Restaurant.java │ │ │ ├── RestaurantDetailsVerificationException.java │ │ │ ├── RestaurantMenu.java │ │ │ ├── RestaurantRepository.java │ │ │ ├── Ticket.java │ │ │ ├── TicketCreatedEvent.java │ │ │ ├── TicketDomainEventPublisher.java │ │ │ ├── TicketNotFoundException.java │ │ │ ├── TicketPickedUpEvent.java │ │ │ ├── TicketPreparationCompletedEvent.java │ │ │ ├── TicketPreparationStartedEvent.java │ │ │ ├── TicketRepository.java │ │ │ ├── TicketRevised.java │ │ │ └── TicketState.java │ │ │ ├── main │ │ │ └── KitchenServiceMain.java │ │ │ ├── messagehandlers │ │ │ ├── KitchenServiceCommandHandler.java │ │ │ ├── KitchenServiceEventConsumer.java │ │ │ ├── KitchenServiceMessageHandlersConfiguration.java │ │ │ └── RestaurantEventMapper.java │ │ │ └── web │ │ │ ├── GetRestaurantResponse.java │ │ │ ├── KitchenController.java │ │ │ ├── KitchenServiceWebConfiguration.java │ │ │ └── RestaurantController.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── kitchenservice │ │ └── domain │ │ ├── KitchenServiceInMemoryIntegrationTest.java │ │ └── TicketDomainEventPublisherTest.java │ └── resources │ └── application.properties ├── ftgo-order-history-service ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ └── kubernetes │ │ └── ftgo-order-history-service.yml │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── cqrs │ │ └── orderhistory │ │ └── dynamodb │ │ └── OrderHistoryDaoDynamoDbTest.java │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── cqrs │ │ │ └── orderhistory │ │ │ ├── DeliveryPickedUp.java │ │ │ ├── Location.java │ │ │ ├── OrderHistory.java │ │ │ ├── OrderHistoryDao.java │ │ │ ├── OrderHistoryFilter.java │ │ │ ├── dynamodb │ │ │ ├── AvMapBuilder.java │ │ │ ├── DeliveryStatus.java │ │ │ ├── DynamoDBHealthIndicator.java │ │ │ ├── Expressions.java │ │ │ ├── Maps.java │ │ │ ├── Order.java │ │ │ ├── OrderHistoryDaoDynamoDb.java │ │ │ ├── OrderHistoryDynamoDBConfiguration.java │ │ │ └── SourceEvent.java │ │ │ ├── main │ │ │ └── OrderHistoryServiceMain.java │ │ │ ├── messaging │ │ │ ├── OrderHistoryEventHandlers.java │ │ │ └── OrderHistoryServiceMessagingConfiguration.java │ │ │ └── web │ │ │ ├── GetOrderResponse.java │ │ │ ├── GetOrdersResponse.java │ │ │ ├── OrderHistoryController.java │ │ │ └── OrderHistoryWebConfiguration.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ ├── cqrs │ │ └── orderhistory │ │ │ └── web │ │ │ └── OrderHistoryControllerTest.java │ │ └── orderhistory │ │ └── contracts │ │ └── OrderHistoryEventHandlersTest.java │ └── resources │ └── application.properties ├── ftgo-order-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── orderservice │ └── api │ ├── OrderServiceChannels.java │ ├── events │ ├── OrderAuthorized.java │ ├── OrderCancelled.java │ ├── OrderCreatedEvent.java │ ├── OrderDetails.java │ ├── OrderDomainEvent.java │ ├── OrderLineItem.java │ ├── OrderRejected.java │ └── OrderState.java │ └── web │ ├── CreateOrderRequest.java │ ├── CreateOrderResponse.java │ └── ReviseOrderRequest.java ├── ftgo-order-service-contracts ├── build.gradle └── src │ └── main │ └── resources │ └── contracts │ ├── deliveryservice │ └── messaging │ │ └── OrderCreatedEvent.groovy │ ├── http │ ├── GetNonExistentOrder.groovy │ └── GetOrder.groovy │ └── messaging │ └── OrderCreatedEvent.groovy ├── ftgo-order-service ├── Dockerfile ├── build.gradle └── src │ ├── attic │ ├── AbstractOrderServiceComponentTest.java │ ├── OrderServiceExternalComponentTest.java │ ├── OrderServiceInProcessComponentTest.java │ ├── OrderServiceOutOfProcessComponentTest.java │ └── OrderServiceOutOfProcessComponentV0Test.java │ ├── component-test │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── orderservice │ │ │ └── cucumber │ │ │ ├── OrderServiceComponentTest.java │ │ │ └── OrderServiceComponentTestStepDefinitions.java │ └── resources │ │ └── features │ │ └── place-order.feature │ ├── deployment │ ├── kubernetes-prometheus │ │ ├── prometheus.yml │ │ └── rbac.yml │ └── kubernetes │ │ └── ftgo-order-service.yml │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── orderservice │ │ ├── contract │ │ ├── DeliveryserviceMessagingBase.java │ │ ├── HttpBase.java │ │ └── MessagingBase.java │ │ ├── domain │ │ ├── OrderJpaTest.java │ │ ├── OrderJpaTestConfiguration.java │ │ ├── OrderServiceIntegrationTest.java │ │ └── RestaurantJpaTest.java │ │ ├── grpc │ │ ├── OrderServiceClient.java │ │ ├── OrderServiceGrpIntegrationTest.java │ │ └── OrderServiceGrpIntegrationTestConfiguration.java │ │ └── sagaparticipants │ │ └── KitchenServiceProxyIntegrationTest.java │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── orderservice │ │ │ ├── domain │ │ │ ├── DeliveryInformation.java │ │ │ ├── InvalidMenuItemIdException.java │ │ │ ├── LineItemQuantityChange.java │ │ │ ├── MenuItem.java │ │ │ ├── OptimisticOfflineLockException.java │ │ │ ├── Order.java │ │ │ ├── OrderAuthorizedCancelRequested.java │ │ │ ├── OrderCancelRequested.java │ │ │ ├── OrderDomainEventPublisher.java │ │ │ ├── OrderLineItemChangeQueued.java │ │ │ ├── OrderLineItems.java │ │ │ ├── OrderMinimumNotMetException.java │ │ │ ├── OrderNotFoundException.java │ │ │ ├── OrderRejectedCancelRequested.java │ │ │ ├── OrderRepository.java │ │ │ ├── OrderRevised.java │ │ │ ├── OrderRevision.java │ │ │ ├── OrderRevisionProposed.java │ │ │ ├── OrderRevisionRejected.java │ │ │ ├── OrderService.java │ │ │ ├── OrderServiceConfiguration.java │ │ │ ├── OrderServiceWithRepositoriesConfiguration.java │ │ │ ├── PaymentInformation.java │ │ │ ├── Restaurant.java │ │ │ ├── RestaurantNotFoundException.java │ │ │ ├── RestaurantRepository.java │ │ │ ├── Result.java │ │ │ └── RevisedOrder.java │ │ │ ├── grpc │ │ │ ├── GrpcConfiguration.java │ │ │ └── OrderServiceServer.java │ │ │ ├── main │ │ │ └── OrderServiceMain.java │ │ │ ├── messaging │ │ │ ├── OrderEventConsumer.java │ │ │ ├── OrderServiceMessagingConfiguration.java │ │ │ └── RestaurantEventMapper.java │ │ │ ├── sagaparticipants │ │ │ ├── AccountingServiceProxy.java │ │ │ ├── ApproveOrderCommand.java │ │ │ ├── BeginCancelCommand.java │ │ │ ├── BeginReviseOrderCommand.java │ │ │ ├── BeginReviseOrderReply.java │ │ │ ├── ConfirmCancelOrderCommand.java │ │ │ ├── ConfirmReviseOrderCommand.java │ │ │ ├── ConsumerServiceProxy.java │ │ │ ├── KitchenServiceProxy.java │ │ │ ├── OrderCommand.java │ │ │ ├── OrderServiceProxy.java │ │ │ ├── RejectOrderCommand.java │ │ │ ├── ReverseOrderUpdateCommand.java │ │ │ ├── UndoBeginCancelCommand.java │ │ │ └── UndoBeginReviseOrderCommand.java │ │ │ ├── sagas │ │ │ ├── cancelorder │ │ │ │ ├── CancelOrderSaga.java │ │ │ │ ├── CancelOrderSagaData.java │ │ │ │ └── CancelOrderSagaState.java │ │ │ ├── createorder │ │ │ │ ├── CreateOrderSaga.java │ │ │ │ └── CreateOrderSagaState.java │ │ │ └── reviseorder │ │ │ │ ├── ReviseOrderSaga.java │ │ │ │ ├── ReviseOrderSagaData.java │ │ │ │ └── ReviseOrderSagaState.java │ │ │ ├── service │ │ │ ├── OrderCommandHandlers.java │ │ │ └── OrderCommandHandlersConfiguration.java │ │ │ └── web │ │ │ ├── GetOrderResponse.java │ │ │ ├── GetRestaurantResponse.java │ │ │ ├── MenuItemIdAndQuantity.java │ │ │ ├── OrderController.java │ │ │ ├── OrderWebConfiguration.java │ │ │ ├── RestaurantController.java │ │ │ └── TraceIdResponseFilter.java │ ├── proto │ │ └── OrderService.proto │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── orderservice │ ├── OrderDetailsMother.java │ ├── RestaurantMother.java │ ├── TramCommandsAndEventsIntegrationData.java │ ├── domain │ ├── OrderDomainEventPublisherTest.java │ ├── OrderServiceTest.java │ ├── OrderTest.java │ └── TestMessageConsumer2.java │ ├── messaging │ └── OrderEventConsumerTest.java │ ├── sagas │ └── createorder │ │ └── CreateOrderSagaTest.java │ └── web │ └── OrderControllerTest.java ├── ftgo-restaurant-service-api-spec └── src │ └── main │ └── resources │ └── ftgo-restaurant-service-api-spec │ ├── messages │ ├── MenuItem.json │ ├── RestaurantCreated.json │ └── RestaurantMenuRevised.json │ └── web │ └── ftgo-restaurant-service-swagger.json ├── ftgo-restaurant-service-api ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── restaurantservice │ └── RestaurantServiceChannels.java ├── ftgo-restaurant-service-aws-lambda ├── build.gradle ├── serverless.yml └── src │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── restaurantservice │ │ └── lambda │ │ └── RestaurantServiceLambdaConfigurationTest.java │ └── main │ ├── java │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── restaurantservice │ │ ├── aws │ │ ├── AbstractHttpHandler.java │ │ ├── ApiGatewayRequest.java │ │ ├── ApiGatewayResponse.java │ │ ├── AwsLambdaError.java │ │ ├── Identity.java │ │ └── RequestContext.java │ │ ├── domain │ │ ├── CreateRestaurantRequest.java │ │ ├── MenuItem.java │ │ ├── Restaurant.java │ │ ├── RestaurantMenu.java │ │ ├── RestaurantRepository.java │ │ ├── RestaurantService.java │ │ └── RestaurantServiceDomainConfiguration.java │ │ ├── events │ │ ├── RestaurantCreated.java │ │ ├── RestaurantDomainEvent.java │ │ └── RestaurantMenuRevised.java │ │ ├── lambda │ │ ├── AbstractAutowiringHttpRequestHandler.java │ │ ├── CreateRestaurantRequestHandler.java │ │ ├── FindRestaurantRequestHandler.java │ │ ├── GetRestaurantResponse.java │ │ └── RestaurantServiceLambdaConfiguration.java │ │ └── web │ │ └── CreateRestaurantResponse.java │ └── resources │ └── application.properties ├── ftgo-restaurant-service-contracts ├── build.gradle └── src │ └── main │ └── resources │ └── contracts │ └── deliveryservice │ └── messaging │ └── RestaurantCreatedEvent.groovy ├── ftgo-restaurant-service ├── Dockerfile ├── build.gradle └── src │ ├── deployment │ └── kubernetes │ │ └── ftgo-restaurant-service.yml │ ├── integration-test │ └── java │ │ └── net │ │ └── chrisrichardson │ │ └── ftgo │ │ └── restaurantservice │ │ └── contract │ │ └── DeliveryserviceMessagingBase.java │ ├── main │ ├── java │ │ └── net │ │ │ └── chrisrichardson │ │ │ └── ftgo │ │ │ └── restaurantservice │ │ │ ├── RestaurantServiceMain.java │ │ │ ├── domain │ │ │ ├── CreateRestaurantRequest.java │ │ │ ├── MenuItem.java │ │ │ ├── Restaurant.java │ │ │ ├── RestaurantDomainEventPublisher.java │ │ │ ├── RestaurantMenu.java │ │ │ ├── RestaurantRepository.java │ │ │ ├── RestaurantService.java │ │ │ └── RestaurantServiceDomainConfiguration.java │ │ │ ├── events │ │ │ ├── RestaurantCreated.java │ │ │ ├── RestaurantDomainEvent.java │ │ │ └── RestaurantMenuRevised.java │ │ │ └── web │ │ │ ├── CreateRestaurantResponse.java │ │ │ ├── GetRestaurantResponse.java │ │ │ └── RestaurantController.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── restaurantservice │ ├── domain │ └── RestaurantDomainEventPublisherTest.java │ └── events │ └── RestaurantCreatedSerializationTest.java ├── ftgo-test-util-json-schema ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── testutil │ └── jsonschema │ └── ValidatingJSONMapper.java ├── ftgo-test-util ├── build.gradle └── src │ └── main │ └── java │ └── net │ └── chrisrichardson │ └── ftgo │ └── testutil │ └── FtgoTestUtil.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── initialize-dynamodb.sh ├── mysql-cli.sh ├── mysql ├── Dockerfile └── compile-schema-per-service.sh ├── open-swagger-uis.sh ├── publish-docker-images.sh ├── run-end-to-end-tests.sh ├── run-graphql-api-gateway-tests.sh ├── scan-order-history-view.sh ├── set-env.sh ├── settings.gradle ├── show-swagger-ui-urls.sh ├── skaffold.yaml ├── start-infrastructure-services.sh ├── start-services.sh ├── truncate-table.sh ├── wait-for-mysql.sh └── wait-for-services.sh /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | setup: true 3 | orbs: 4 | eventuate-gradle-build-and-test: "eventuate_io/eventuate-gradle-build-and-test@0.2.1" 5 | continuation: circleci/continuation@0.1.2 6 | jobs: 7 | setup: 8 | executor: continuation/default 9 | steps: 10 | - checkout # checkout code 11 | - run: # run a command 12 | name: Generate config 13 | command: | 14 | ./.circleci/generate-config.sh > generated_config.yml 15 | - continuation/continue: 16 | configuration_path: generated_config.yml 17 | 18 | workflows: 19 | setup: 20 | jobs: 21 | - setup 22 | -------------------------------------------------------------------------------- /.circleci/generate-config.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | cat > generated_config.yml <> generated_config.yml < ~/docker-compose 6 | chmod +x ~/docker-compose 7 | sudo mv ~/docker-compose /usr/local/bin/docker-compose 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | mysql/*.sh text eol=lf 2 | dynamodblocal-init/*.sh text eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | *.idea/ 4 | *.iml 5 | *.log 6 | *.pid 7 | out 8 | target 9 | .serverless 10 | *.pid 11 | .classpath 12 | .project 13 | .settings 14 | bin 15 | node_modules 16 | dist 17 | ftgo-api-gateway-graphql/jest_0 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2016 Eventuate, Inc. All rights reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /_wait-for-services.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | path=$1 4 | shift 5 | ports=$* 6 | 7 | echo $path 8 | echo $ports 9 | 10 | host=${DOCKER_HOST_IP:-localhost} 11 | 12 | done=false 13 | 14 | 15 | while [[ "$done" = false ]]; do 16 | for port in $ports; do 17 | url=http://${host}:${port}$path 18 | curl --fail $url >& /dev/null 19 | if [[ "$?" -eq "0" ]]; then 20 | done=true 21 | else 22 | done=false 23 | echo $url 24 | break 25 | fi 26 | done 27 | if [[ "$done" = true ]]; then 28 | echo connected 29 | break; 30 | fi 31 | echo -n . 32 | sleep 1 33 | done 34 | -------------------------------------------------------------------------------- /build-and-restart-service.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | for SN in $* ; do 4 | 5 | ./gradlew :${SN?}:assemble 6 | docker-compose build ${SN?} 7 | docker-compose up -d ${SN?} 8 | done 9 | 10 | docker-compose logs -f $* 11 | 12 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | test.enabled=false 2 | 3 | repositories { 4 | mavenCentral() 5 | jcenter() 6 | maven { 7 | url "https://plugins.gradle.org/m2/" 8 | } 9 | } 10 | 11 | dependencies { 12 | compile 'mysql:mysql-connector-java:8.0.21' 13 | compile 'com.amazonaws:aws-java-sdk-dynamodb:1.11.158' 14 | compile 'commons-lang:commons-lang:2.6' 15 | 16 | compile 'org.jsonschema2pojo:jsonschema2pojo-core:1.0.1' 17 | 18 | compile "gradle.plugin.org.hidetake:gradle-swagger-generator-plugin:2.18.1" 19 | } 20 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/FtgoApiDependencyResolverPlugin.groovy: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Plugin 2 | import org.gradle.api.Project 3 | import org.gradle.api.internal.artifacts.dependencies.DefaultProjectDependency 4 | 5 | class FtgoApiDependencyResolverPlugin implements Plugin { 6 | 7 | @Override 8 | void apply(Project project) { 9 | 10 | project.ext.ftgoApiSpecsDir = "${project.buildDir}/ftgo-api-specs" 11 | 12 | def c = project.configurations.create('ftgoApiSpecification') 13 | 14 | project.configurations.implementation.extendsFrom(c) 15 | 16 | def resolveTask = project.task("ftgoResolveAPIDependencies", 17 | type: FtgoResolveAPIDependencies, 18 | group: 'build setup', 19 | description: "fetch API dependencies") 20 | 21 | project.afterEvaluate { 22 | project.configurations.ftgoApiSpecification.allDependencies.each { 23 | if (it instanceof DefaultProjectDependency) { 24 | def buildTask = it.dependencyProject.tasks.getByPath("build") 25 | resolveTask.dependsOn(buildTask) 26 | } 27 | } 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/FtgoOpenApiCodeGenPlugin.groovy: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Plugin 2 | import org.gradle.api.Project 3 | 4 | class FtgoOpenApiCodeGenPlugin implements Plugin { 5 | 6 | @Override 7 | void apply(Project project) { 8 | project.pluginManager.apply("org.hidetake.swagger.generator") 9 | project.apply(plugin: FtgoApiDependencyResolverPlugin) 10 | 11 | project.afterEvaluate { 12 | project.swaggerSources.each { 13 | def name = it.name 14 | project.swaggerSources[name].code.dependsOn(project.tasks.getByPath("ftgoResolveAPIDependencies")) 15 | project.compileJava.dependsOn(project.swaggerSources[name].code) 16 | project.sourceSets.main.java.srcDir "${project.swaggerSources[name].code.outputDir}/src/main/java" 17 | project.sourceSets.main.resources.srcDir "${project.swaggerSources[name].code.outputDir}/src/main/resources" 18 | } 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/FtgoResolveAPIDependencies.groovy: -------------------------------------------------------------------------------- 1 | import org.gradle.api.tasks.Sync 2 | 3 | class FtgoResolveAPIDependencies extends Sync { 4 | 5 | FtgoResolveAPIDependencies() { 6 | 7 | 8 | from { 9 | project.configurations.ftgoApiSpecification.resolve().collect { 10 | project.zipTree(it) 11 | } 12 | } 13 | include("**/*.json") 14 | exclude("**/META-INF/**") 15 | into(project.ext.ftgoApiSpecsDir ) 16 | 17 | includeEmptyDirs = false 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/JSONSchemaSource.groovy: -------------------------------------------------------------------------------- 1 | import groovy.transform.ToString 2 | import org.gradle.api.file.FileCollection 3 | 4 | @ToString(includes = 'name', includePackage = false) 5 | class JSONSchemaSource { 6 | 7 | final String name 8 | 9 | def JSONSchemaSource(String name) { 10 | this.name = name 11 | } 12 | 13 | FtgoJSONSchemaToPojoCodeGen codeGen 14 | 15 | String sourceSet = "main" 16 | 17 | void setSource(FileCollection source) { 18 | this.codeGen.source = source 19 | } 20 | 21 | void setTargetPackage(String targetPackage) { 22 | this.codeGen.targetPackage = targetPackage 23 | } 24 | 25 | void setIncludeAdditionalProperties(boolean includeAdditionalProperties) { 26 | this.codeGen.includeAdditionalProperties = includeAdditionalProperties 27 | } 28 | 29 | void setGenerateBuilders(boolean generateBuilders) { 30 | this.codeGen.generateBuilders = generateBuilders 31 | } 32 | 33 | void setUseLongIntegers(boolean useLongIntegers) { 34 | this.codeGen.useLongIntegers = useLongIntegers 35 | } 36 | 37 | File getTargetDirectory() { 38 | return this.codeGen.targetDirectory 39 | } 40 | 41 | void setSourceSet(String sourceSet) { 42 | this.sourceSet = sourceSet 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/WaitForMySqlPlugin.java: -------------------------------------------------------------------------------- 1 | import org.gradle.api.Plugin; 2 | import org.gradle.api.Project; 3 | 4 | public class WaitForMySqlPlugin implements Plugin { 5 | @Override 6 | public void apply(Project project) { 7 | project.getTasks().create("waitForMySql", WaitForMySql.class); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /common-swagger/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "io.eventuate.util:eventuate-util-spring-swagger" 3 | } 4 | -------------------------------------------------------------------------------- /common-swagger/src/main/java/net/chrisrichardson/eventstore/examples/customersandorders/commonswagger/CommonSwaggerConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.eventstore.examples.customersandorders.commonswagger; 2 | 3 | import io.eventuate.util.spring.swagger.EventuateSwaggerConfig; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class CommonSwaggerConfiguration { 9 | 10 | @Bean 11 | public EventuateSwaggerConfig eventuateSwaggerConfig() { 12 | return () -> "net.chrisrichardson.ftgo"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /deployment/kubernetes/misc/create-db-secret.sh: -------------------------------------------------------------------------------- 1 | kubectl create secret generic ftgo-db-secret \ 2 | --from-literal=username=mysqluser \ 3 | --from-literal=password=mysqlpw -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-delete-all.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | kubectl delete -f <(cat */src/deployment/kubernetes/*.yml deployment/kubernetes/*/*.yml) 4 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-delete-volumes.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | kubectl delete pvc ftgo-dynamodb-persistent-storage-ftgo-dynamodb-local-0 ftgo-kafka-persistent-storage-ftgo-kafka-0 ftgo-mysql-persistent-storage-ftgo-mysql-0 ftgo-zookeeper-persistent-storage-ftgo-zookeeper-0 4 | 5 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-deploy-all.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | kubectl apply -f <(cat deployment/kubernetes/stateful-services/*.yml) 4 | 5 | ./deployment/kubernetes/scripts/kubernetes-wait-for-ready-pods.sh ftgo-mysql-0 ftgo-kafka-0 ftgo-dynamodb-local-0 ftgo-zookeeper-0 6 | 7 | kubectl apply -f <(cat deployment/kubernetes/cdc-services/*.yml) 8 | 9 | kubectl apply -f <(cat */src/deployment/kubernetes/*.yml) 10 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-deploy-and-test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | set -e 5 | 6 | ./deployment/kubernetes/scripts/kubernetes-deploy-all.sh 7 | 8 | ./deployment/kubernetes/scripts/kubernetes-run-end-to-end-tests.sh 9 | 10 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-kill-port-forwarding.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | kill $(cat port-forward-*.pid) 6 | 7 | rm port-forward-*.pid 8 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-run-end-to-end-tests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | set -e 4 | 5 | ./deployment/kubernetes/scripts/kubernetes-wait-for-ready-pods.sh $(kubectl get pod -l application=ftgo -o=jsonpath='{.items[*].metadata.name}') 6 | 7 | ./deployment/kubernetes/scripts/port-forwards.sh 8 | 9 | DOCKER_HOST_IP=localhost ./gradlew :ftgo-end-to-end-tests:cleanTest :ftgo-end-to-end-tests:test 10 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/kubernetes-wait-for-ready-pods.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | pods=$* 4 | 5 | done=false 6 | 7 | while [[ "$done" = false ]]; do 8 | for pod in $pods; do 9 | outcome=$(kubectl get pod $pod -o=jsonpath='{.status.containerStatuses[0].ready}') 10 | if [[ "$outcome" == "true" ]]; then 11 | done=true 12 | else 13 | done=false 14 | break 15 | fi 16 | done 17 | if [[ "$done" = true ]]; then 18 | echo connected 19 | break; 20 | fi 21 | echo -n . 22 | sleep 1 23 | done 24 | -------------------------------------------------------------------------------- /deployment/kubernetes/scripts/port-forwards.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | 4 | #declare -A MYMAP=( ['ftgo-appi-gateway']=8087 ) 5 | 6 | doforward() { 7 | service=$1 8 | port=$2 9 | remotePort=$3 10 | pod=$(kubectl get pods --selector=svc=$service -o jsonpath='{.items[*].metadata.name}') 11 | echo $service $pod $port 12 | kubectl port-forward $pod ${port}:${remotePort} & 13 | echo $! > port-forward-${service}.pid 14 | } 15 | 16 | 17 | doforward 'ftgo-accounting-service' 8085 8080 18 | 19 | doforward 'ftgo-consumer-service' 8081 8080 20 | doforward 'ftgo-api-gateway' 8087 8080 21 | doforward 'ftgo-order-service' 8082 8080 22 | doforward 'ftgo-restaurant-service' 8084 8080 23 | doforward 'ftgo-kitchen-service' 8083 8080 24 | 25 | exit 0 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /deployment/kubernetes/stateful-services/ftgo-db-secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | data: 4 | password: bXlzcWxwdw== 5 | username: bXlzcWx1c2Vy 6 | kind: Secret 7 | metadata: 8 | name: ftgo-db-secret 9 | type: Opaque 10 | --- 11 | -------------------------------------------------------------------------------- /deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: ftgo-zookeeper 5 | labels: 6 | name: ftgo-zookeeper 7 | spec: 8 | ports: 9 | - port: 2181 10 | targetPort: 2181 11 | clusterIP: None 12 | selector: 13 | role: ftgo-zookeeper 14 | --- 15 | apiVersion: apps/v1beta1 16 | kind: StatefulSet 17 | metadata: 18 | name: ftgo-zookeeper 19 | spec: 20 | serviceName: "zookeeper" 21 | replicas: 1 22 | template: 23 | metadata: 24 | labels: 25 | role: ftgo-zookeeper 26 | spec: 27 | terminationGracePeriodSeconds: 10 28 | containers: 29 | - name: ftgo-zookeeper 30 | image: confluentinc/cp-zookeeper:5.2.4 31 | ports: 32 | - containerPort: 2181 33 | env: 34 | - name: ZOOKEEPER_CLIENT_PORT 35 | value: "2181" 36 | volumeMounts: 37 | - name: ftgo-zookeeper-persistent-storage 38 | mountPath: /var/lib/kafka/data 39 | volumeClaimTemplates: 40 | - metadata: 41 | name: ftgo-zookeeper-persistent-storage 42 | spec: 43 | accessModes: [ "ReadWriteOnce" ] 44 | resources: 45 | requests: 46 | storage: 1Gi 47 | --- 48 | -------------------------------------------------------------------------------- /docker-compose-api-gateway-graphql.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | ftgo-api-gateway-graphql: 4 | build: ./ftgo-api-gateway-graphql 5 | ports: 6 | - "8088:3000" 7 | environment: 8 | ORDER_HISTORY_SERVICE_URL: http://ftgo-order-history-service:8080 9 | CONSUMER_SERVICE_URL: http://ftgo-consumer-service:8080 10 | RESTAURANT_SERVICE_URL: http://ftgo-restaurant-service:8080 11 | -------------------------------------------------------------------------------- /dynamodblocal-init/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7.16-alpine3.9 2 | RUN pip install awscli --upgrade 3 | COPY create-dynamodb-tables.sh . 4 | COPY ftgo-order-history.json . 5 | COPY wait-for-dynamodblocal.sh . 6 | RUN chmod +x *.sh 7 | HEALTHCHECK --interval=10s --retries=10 --timeout=3s CMD [[ -f /tables-created ]] 8 | 9 | CMD ./wait-for-dynamodblocal.sh && ./create-dynamodb-tables.sh 10 | -------------------------------------------------------------------------------- /dynamodblocal-init/build-docker.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | docker build -t test-dynamodblocal-init . 4 | -------------------------------------------------------------------------------- /dynamodblocal-init/create-dynamodb-tables.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh -e 2 | 3 | echo Initializing DynamoDB at endpoint ${AWS_DYNAMODB_ENDPOINT_URL} 4 | 5 | if aws dynamodb --region us-west-1 --endpoint-url ${AWS_DYNAMODB_ENDPOINT_URL?} describe-table --table-name ftgo-order-history ; then 6 | echo table exists 7 | else 8 | 9 | echo creating table 10 | aws dynamodb $* create-table --region us-west-2 --endpoint-url ${AWS_DYNAMODB_ENDPOINT_URL?} --cli-input-json file://ftgo-order-history.json 11 | 12 | fi 13 | 14 | touch /tables-created 15 | 16 | while [[ true ]] ; do 17 | echo sleeping... 18 | sleep 3600 19 | done -------------------------------------------------------------------------------- /dynamodblocal-init/ftgo-order-history.json: -------------------------------------------------------------------------------- 1 | { 2 | "TableName": "ftgo-order-history", 3 | "KeySchema": [ 4 | { 5 | "KeyType": "HASH", 6 | "AttributeName": "orderId" 7 | } 8 | ], 9 | "AttributeDefinitions": [ 10 | { 11 | "AttributeName": "consumerId", 12 | "AttributeType": "S" 13 | }, 14 | { 15 | "AttributeName": "creationDate", 16 | "AttributeType": "N" 17 | }, 18 | { 19 | "AttributeName": "orderId", 20 | "AttributeType": "S" 21 | } 22 | ], 23 | "GlobalSecondaryIndexes": [ 24 | { 25 | "IndexName": "ftgo-order-history-by-consumer-id-and-creation-time", 26 | "Projection": { 27 | "ProjectionType": "ALL" 28 | }, 29 | "ProvisionedThroughput": { 30 | "WriteCapacityUnits": 3, 31 | "ReadCapacityUnits": 3 32 | }, 33 | "KeySchema": [ 34 | { 35 | "KeyType": "HASH", 36 | "AttributeName": "consumerId" 37 | }, 38 | { 39 | "KeyType": "RANGE", 40 | "AttributeName": "creationDate" 41 | } 42 | ] 43 | } 44 | ], 45 | "ProvisionedThroughput": { 46 | "WriteCapacityUnits": 3, 47 | "ReadCapacityUnits": 3 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /dynamodblocal-init/run-docker.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | docker run -it --rm -e AWS_DYNAMODB_ENDPOINT_URL -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY test-dynamodblocal-init 4 | -------------------------------------------------------------------------------- /dynamodblocal-init/wait-for-dynamodblocal.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | done=false 4 | 5 | while [[ "$done" = false ]]; do 6 | curl -q ${AWS_DYNAMODB_ENDPOINT_URL?} >& /dev/null 7 | if [[ "$?" -eq "0" ]]; then 8 | done=true 9 | else 10 | done=false 11 | break 12 | fi 13 | if [[ "$done" = true ]]; then 14 | echo connected 15 | break; 16 | fi 17 | echo -n . 18 | sleep 1 19 | done 20 | -------------------------------------------------------------------------------- /dynamodblocal/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM amazon/dynamodb-local:1.18.0 2 | ENTRYPOINT java -jar DynamoDBLocal.jar -inMemory -sharedDb -port 8000 3 | HEALTHCHECK --start-period=5s --interval=5s CMD curl http://localhost:8000 || exit 1 4 | -------------------------------------------------------------------------------- /dynamodblocal/build-docker.sh: -------------------------------------------------------------------------------- 1 | docker build -t test-dynamodblocal . 2 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api-spec/src/main/resources/messages/AuthorizeCommand.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "consumerId": { 5 | "type": "integer", 6 | "format": "int64" 7 | }, 8 | "orderId": { 9 | "type": "integer", 10 | "format": "int64" 11 | }, 12 | "orderTotal": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "consumerId", 18 | "orderId", 19 | "orderTotal" 20 | ], 21 | "javaInterfaces": ["io.eventuate.tram.commands.common.Command"] 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | 3 | compile "io.eventuate.tram.sagas:eventuate-tram-sagas-spring-participant" 4 | compile project(":ftgo-common") 5 | 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountDisabledReply.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountservice.api; 2 | 3 | public class AccountDisabledReply { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AccountingServiceChannels.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountservice.api; 2 | 3 | 4 | public class AccountingServiceChannels { 5 | 6 | public static String accountingServiceChannel = "accountingService"; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/ReverseAuthorizationCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountservice.api; 2 | 3 | 4 | import io.eventuate.tram.commands.common.Command; 5 | import net.chrisrichardson.ftgo.common.Money; 6 | 7 | public class ReverseAuthorizationCommand implements Command { 8 | private long consumerId; 9 | private Long orderId; 10 | private Money orderTotal; 11 | 12 | private ReverseAuthorizationCommand() { 13 | } 14 | 15 | public ReverseAuthorizationCommand(long consumerId, Long orderId, Money orderTotal) { 16 | this.consumerId = consumerId; 17 | this.orderId = orderId; 18 | this.orderTotal = orderTotal; 19 | } 20 | 21 | public long getConsumerId() { 22 | return consumerId; 23 | } 24 | 25 | public void setConsumerId(long consumerId) { 26 | this.consumerId = consumerId; 27 | } 28 | 29 | public Money getOrderTotal() { 30 | return orderTotal; 31 | } 32 | 33 | public void setOrderTotal(Money orderTotal) { 34 | this.orderTotal = orderTotal; 35 | } 36 | 37 | public Long getOrderId() { 38 | 39 | return orderId; 40 | 41 | } 42 | 43 | public void setOrderId(Long orderId) { 44 | this.orderId = orderId; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ftgo-accounting-service-api/src/main/java/net/chrisrichardson/ftgo/accountservice/api/ReviseAuthorization.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | public class ReviseAuthorization implements Command { 7 | private long consumerId; 8 | private Long orderId; 9 | private Money orderTotal; 10 | 11 | private ReviseAuthorization() { 12 | } 13 | 14 | public ReviseAuthorization(long consumerId, Long orderId, Money orderTotal) { 15 | this.consumerId = consumerId; 16 | this.orderId = orderId; 17 | this.orderTotal = orderTotal; 18 | } 19 | 20 | public long getConsumerId() { 21 | return consumerId; 22 | } 23 | 24 | public void setConsumerId(long consumerId) { 25 | this.consumerId = consumerId; 26 | } 27 | 28 | public Money getOrderTotal() { 29 | return orderTotal; 30 | } 31 | 32 | public void setOrderTotal(Money orderTotal) { 33 | this.orderTotal = orderTotal; 34 | } 35 | 36 | public Long getOrderId() { 37 | 38 | return orderId; 39 | 40 | } 41 | 42 | public void setOrderId(Long orderId) { 43 | this.orderId = orderId; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ftgo-accounting-service-contracts/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'spring-cloud-contract' 3 | apply plugin: 'maven-publish' 4 | 5 | 6 | publishing { 7 | repositories { 8 | maven { 9 | url "${project.rootDir}/build/repo" 10 | } 11 | } 12 | } 13 | 14 | contracts { 15 | contractsDslDir = file("${projectDir}/src/main/resources/contracts") 16 | } 17 | 18 | generateContractTests.enabled = false 19 | 20 | 21 | build.finalizedBy(publish) 22 | 23 | dependencies { 24 | compile 'org.codehaus.groovy:groovy-all:2.4.6' 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-accounting-service-contracts/src/main/resources/contracts/Authorize.groovy: -------------------------------------------------------------------------------- 1 | package contracts; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'authorize' 5 | input { 6 | messageFrom('accountingService') 7 | messageBody('''{"consumerId":1511300065921,"orderId":1,"orderTotal":"61.70"}''') 8 | messageHeaders { 9 | } 10 | } 11 | outputMessage { 12 | sentTo('net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 13 | body('''{}''') 14 | headers { 15 | header('reply_type', 'io.eventuate.tram.commands.common.Success') 16 | header('reply_outcome-type', 'SUCCESS') 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /ftgo-accounting-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-accounting-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizationFailed.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.Event; 4 | 5 | public class AccountAuthorizationFailed implements Event { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountAuthorizedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.Event; 4 | 5 | public class AccountAuthorizedEvent implements Event { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.Command; 4 | 5 | public interface AccountCommand extends Command { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.Event; 4 | 5 | public class AccountCreatedEvent implements Event { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountDisabledException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | public class AccountDisabledException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountServiceConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.sync.AggregateRepository; 4 | import io.eventuate.sync.EventuateAggregateStore; 5 | import io.eventuate.tram.spring.commands.producer.TramCommandProducerConfiguration; 6 | import net.chrisrichardson.ftgo.common.CommonConfiguration; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Import; 10 | 11 | @Configuration 12 | @Import({TramCommandProducerConfiguration.class, CommonConfiguration.class}) 13 | public class AccountServiceConfiguration { 14 | 15 | 16 | @Bean 17 | public AggregateRepository accountRepositorySync(EventuateAggregateStore aggregateStore) { 18 | return new AggregateRepository<>(Account.class, aggregateStore); 19 | } 20 | 21 | @Bean 22 | public AccountingService accountingService() { 23 | return new AccountingService(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AccountingService.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.sync.AggregateRepository; 4 | import io.eventuate.EntityWithIdAndVersion; 5 | import io.eventuate.SaveOptions; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import java.util.Optional; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.concurrent.TimeoutException; 12 | 13 | public class AccountingService { 14 | @Autowired 15 | private AggregateRepository accountRepository; 16 | 17 | public void create(String aggregateId) { 18 | EntityWithIdAndVersion account = accountRepository.save(new CreateAccountCommand(), 19 | Optional.of(new SaveOptions().withId(aggregateId))); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/AuthorizeCommandInternal.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | public class AuthorizeCommandInternal implements AccountCommand, Command { 7 | private String consumerId; 8 | private String orderId; 9 | private Money orderTotal; 10 | 11 | public String getOrderId() { 12 | return orderId; 13 | } 14 | 15 | public void setOrderId(String orderId) { 16 | this.orderId = orderId; 17 | } 18 | 19 | public AuthorizeCommandInternal(String consumerId, String orderId, Money orderTotal) { 20 | this.consumerId = consumerId; 21 | this.orderId = orderId; 22 | this.orderTotal = orderTotal; 23 | } 24 | 25 | private AuthorizeCommandInternal() { 26 | } 27 | 28 | public String getConsumerId() { 29 | return consumerId; 30 | } 31 | 32 | public void setConsumerId(String consumerId) { 33 | this.consumerId = consumerId; 34 | } 35 | 36 | public Money getOrderTotal() { 37 | return orderTotal; 38 | } 39 | 40 | public void setOrderTotal(Money orderTotal) { 41 | this.orderTotal = orderTotal; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/CreateAccountCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | public class CreateAccountCommand implements AccountCommand { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/ReverseAuthorizationCommandInternal.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | 7 | public class ReverseAuthorizationCommandInternal implements AccountCommand, Command { 8 | private String consumerId; 9 | private String orderId; 10 | private Money orderTotal; 11 | 12 | public String getOrderId() { 13 | return orderId; 14 | } 15 | 16 | public void setOrderId(String orderId) { 17 | this.orderId = orderId; 18 | } 19 | 20 | public ReverseAuthorizationCommandInternal(String consumerId, String orderId, Money orderTotal) { 21 | this.consumerId = consumerId; 22 | this.orderId = orderId; 23 | this.orderTotal = orderTotal; 24 | } 25 | 26 | private ReverseAuthorizationCommandInternal() { 27 | } 28 | 29 | public String getConsumerId() { 30 | return consumerId; 31 | } 32 | 33 | public void setConsumerId(String consumerId) { 34 | this.consumerId = consumerId; 35 | } 36 | 37 | public Money getOrderTotal() { 38 | return orderTotal; 39 | } 40 | 41 | public void setOrderTotal(Money orderTotal) { 42 | this.orderTotal = orderTotal; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/domain/ReviseAuthorizationCommandInternal.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.domain; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | 7 | public class ReviseAuthorizationCommandInternal implements AccountCommand, Command { 8 | private String consumerId; 9 | private String orderId; 10 | private Money orderTotal; 11 | 12 | public String getOrderId() { 13 | return orderId; 14 | } 15 | 16 | public void setOrderId(String orderId) { 17 | this.orderId = orderId; 18 | } 19 | 20 | public ReviseAuthorizationCommandInternal(String consumerId, String orderId, Money orderTotal) { 21 | this.consumerId = consumerId; 22 | this.orderId = orderId; 23 | this.orderTotal = orderTotal; 24 | } 25 | 26 | private ReviseAuthorizationCommandInternal() { 27 | } 28 | 29 | public String getConsumerId() { 30 | return consumerId; 31 | } 32 | 33 | public void setConsumerId(String consumerId) { 34 | this.consumerId = consumerId; 35 | } 36 | 37 | public Money getOrderTotal() { 38 | return orderTotal; 39 | } 40 | 41 | public void setOrderTotal(Money orderTotal) { 42 | this.orderTotal = orderTotal; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountServiceChannelConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.messaging; 2 | 3 | public class AccountServiceChannelConfiguration { 4 | private String commandDispatcherId; 5 | private String commandChannel; 6 | 7 | public AccountServiceChannelConfiguration(String commandDispatcherId, String commandChannel) { 8 | this.commandDispatcherId = commandDispatcherId; 9 | this.commandChannel = commandChannel; 10 | } 11 | 12 | public String getCommandDispatcherId() { 13 | return commandDispatcherId; 14 | } 15 | 16 | public String getCommandChannel() { 17 | return commandChannel; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/messaging/AccountingEventConsumer.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.messaging; 2 | 3 | import io.eventuate.tram.events.subscriber.DomainEventEnvelope; 4 | import io.eventuate.tram.events.subscriber.DomainEventHandlers; 5 | import io.eventuate.tram.events.subscriber.DomainEventHandlersBuilder; 6 | import net.chrisrichardson.ftgo.accountingservice.domain.AccountingService; 7 | import net.chrisrichardson.ftgo.consumerservice.domain.ConsumerCreated; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | 10 | 11 | public class AccountingEventConsumer { 12 | 13 | @Autowired 14 | private AccountingService accountingService; 15 | 16 | public DomainEventHandlers domainEventHandlers() { 17 | return DomainEventHandlersBuilder 18 | .forAggregateType("net.chrisrichardson.ftgo.consumerservice.domain.Consumer") 19 | .onEvent(ConsumerCreated.class, this::createAccount) // TODO this is hack to get the correct package 20 | .build(); 21 | } 22 | 23 | private void createAccount(DomainEventEnvelope dee) { 24 | accountingService.create(dee.getAggregateId()); 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/AccountingWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.web; 2 | 3 | import net.chrisrichardson.ftgo.accountingservice.domain.AccountServiceConfiguration; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | @Configuration 9 | @Import(AccountServiceConfiguration.class) 10 | @ComponentScan 11 | public class AccountingWebConfiguration { 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountingservice/web/GetAccountResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountingservice.web; 2 | 3 | public class GetAccountResponse { 4 | private String accountId; 5 | 6 | public String getAccountId() { 7 | return accountId; 8 | } 9 | 10 | public void setAccountId(String accountId) { 11 | this.accountId = accountId; 12 | } 13 | 14 | public GetAccountResponse() { 15 | 16 | } 17 | 18 | public GetAccountResponse(String accountId) { 19 | this.accountId = accountId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/accountservice/api/AuthorizeCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.accountservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | public class AuthorizeCommand implements Command { 7 | private long consumerId; 8 | private Long orderId; 9 | private Money orderTotal; 10 | 11 | private AuthorizeCommand() { 12 | } 13 | 14 | public AuthorizeCommand(long consumerId, Long orderId, Money orderTotal) { 15 | this.consumerId = consumerId; 16 | this.orderId = orderId; 17 | this.orderTotal = orderTotal; 18 | } 19 | 20 | public long getConsumerId() { 21 | return consumerId; 22 | } 23 | 24 | public void setConsumerId(long consumerId) { 25 | this.consumerId = consumerId; 26 | } 27 | 28 | public Money getOrderTotal() { 29 | return orderTotal; 30 | } 31 | 32 | public void setOrderTotal(Money orderTotal) { 33 | this.orderTotal = orderTotal; 34 | } 35 | 36 | public Long getOrderId() { 37 | 38 | return orderId; 39 | 40 | } 41 | 42 | public void setOrderId(Long orderId) { 43 | this.orderId = orderId; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.domain; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public class ConsumerCreated implements DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-accounting-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-accounting-service 2 | 3 | management.endpoint.health.show-details=always 4 | 5 | spring.jpa.generate-ddl=true 6 | logging.level.org.springframework.orm.jpa=INFO 7 | logging.level.org.hibernate.SQL=DEBUG 8 | logging.level.io.eventuate=DEBUG 9 | logging.level.net.chrisrichardson.ftgo=DEBUG 10 | logging.level.io.eventuate.tram=DEBUG 11 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_accounting_service 12 | spring.datasource.username=ftgo_accounting_service_user 13 | spring.datasource.password=ftgo_accounting_service_password 14 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 15 | 16 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 17 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 18 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:9.11.2-alpine 2 | COPY package.json . 3 | COPY package-lock.json . 4 | RUN npm install 5 | RUN npm config set unsafe-perm true && npm install -g typescript 6 | COPY tsconfig.json . 7 | ADD src ./src 8 | RUN npm run build 9 | CMD npm run start 10 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | 'ts-jest': { 4 | tsConfigFile: 'tsconfig.json' 5 | } 6 | }, 7 | moduleFileExtensions: [ 8 | 'ts', 9 | 'js' 10 | ], 11 | transform: { 12 | '^.+\\.(ts|tsx)$': './node_modules/ts-jest/preprocessor.js' 13 | }, 14 | testMatch: [ 15 | '**/tests/**/*.test.(ts|js)' 16 | ], 17 | testEnvironment: 'node' 18 | }; -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "main": "./src/index.js", 4 | "scripts": { 5 | "start": "node ./dist/index.js", 6 | "build": "tsc", 7 | "dev": "tsc --watch & nodemon dist/server.js", 8 | "unit-test": "tsc && jest --config jest.config.js tests/unit", 9 | "end-to-end-test": "tsc && jest --config jest.config.js tests/end-to-end", 10 | "lint": "eslint src --ext ts", 11 | "tsc": "tsc", 12 | "clean": "rm -fr dist" 13 | }, 14 | "dependencies": { 15 | "@types/graphql": "^14.5.0", 16 | "apollo-cache-inmemory": "^1.6.3", 17 | "apollo-client": "^2.6.4", 18 | "apollo-engine": "^1.1.2", 19 | "apollo-link-http": "^1.5.6", 20 | "apollo-server-express": "1.3.2", 21 | "body-parser": "^1.19.0", 22 | "dataloader": "^1.4.0", 23 | "express": "^4.17.1", 24 | "graphql": "^0.13.2", 25 | "graphql-tools": "4.0.5", 26 | "node-fetch": "^2.6.0" 27 | }, 28 | "devDependencies": { 29 | "@types/mocha": "^5.2.7", 30 | "@types/node": "^12.7.11", 31 | "apollo-boost": "^0.1.6", 32 | "apollo-link-persisted-queries": "^0.2.0", 33 | "apollo-link-schema": "^1.1.0", 34 | "graphql-tag": "^2.9.2", 35 | "jest": "^24.9.0", 36 | "ts-jest": "^24.1.0", 37 | "typescript": "^3.6.3" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/src/OrderServiceProxy.js: -------------------------------------------------------------------------------- 1 | const fetch = require("node-fetch"); 2 | 3 | class OrderServiceProxy { 4 | 5 | constructor(options) { 6 | this.orderService = `${options.baseUrl}/orders`; 7 | } 8 | 9 | findOrders(consumerId) { 10 | return fetch(`${this.orderService}?consumerId=${consumerId}`) 11 | .then(res => res.json()) 12 | .then(data => { 13 | // Sometimes, there are no upcoming events 14 | console.log("orders=", data); 15 | const x = data.orders.map((order) => Object.assign({consumerId}, order)); 16 | console.log("orders=", x); 17 | return x; 18 | }); 19 | } 20 | 21 | } 22 | 23 | module.exports = {OrderServiceProxy}; 24 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/src/index.js: -------------------------------------------------------------------------------- 1 | 2 | const {app} = require("./server"); 3 | 4 | const PORT = 3000; 5 | 6 | app.listen(PORT); 7 | 8 | console.log("Server listing on port: ", PORT); 9 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/tests/end-to-end/client.end2end.test.js: -------------------------------------------------------------------------------- 1 | const {app} = require("../../src/server.ts"); 2 | const {FtgoGraphQLClient} = require("../common/ftgo-graphql-client.js"); 3 | 4 | 5 | /* 6 | var server; 7 | 8 | beforeAll(() => { 9 | 10 | const PORT = 3000; 11 | server = app.listen(PORT); 12 | console.log("Server listing on port: ", PORT); 13 | 14 | }); 15 | 16 | afterAll(() => { 17 | server.close(); 18 | }); 19 | */ 20 | 21 | test('findConsumerWithOrders', () => { 22 | const client = new FtgoGraphQLClient({baseUrl: `http://${process.env.DOCKER_HOST_IP || "localhost"}:8088`}); 23 | 24 | return client.findConsumerWithOrders("1") 25 | .then(result => { 26 | expect(result.errors).toBe(undefined); 27 | expect(result.data.consumer.id).toBe('1'); 28 | expect(result.data.consumer.orders[0].restaurant.name).toBe('My Restaurant'); 29 | console.log("result.data", JSON.stringify(result.data)); 30 | }); 31 | 32 | }); 33 | -------------------------------------------------------------------------------- /ftgo-api-gateway-graphql/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "sourceMap": true, 7 | "moduleResolution": "node", 8 | "noImplicitAny": true, 9 | "allowJs": true, 10 | "noImplicitAny": false, 11 | "lib": ["esnext.asynciterable", "es2015"], 12 | "baseUrl" : "./src", 13 | "paths": { 14 | "*": [ 15 | "src/types/*" 16 | ] 17 | } 18 | }, 19 | "include": [ 20 | "src/**/*" 21 | ], 22 | "exclude": [ 23 | "node_modules" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-api-gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-api-gateway.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/deployment/kubernetes-node-port/ftgo-api-gateway-NodePort.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: ftgo-api-gateway 5 | spec: 6 | type: NodePort 7 | ports: 8 | - nodePort: 30000 9 | port: 80 10 | targetPort: 8080 11 | selector: 12 | svc: ftgo-api-gateway 13 | --- 14 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayApplication.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway; 2 | 3 | 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.context.annotation.ComponentScan; 7 | 8 | @SpringBootApplication 9 | @ComponentScan 10 | public class ApiGatewayApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(ApiGatewayApplication.class, args); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/consumers/ConsumerConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.consumers; 2 | 3 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 4 | import org.springframework.cloud.gateway.route.RouteLocator; 5 | import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | 10 | @Configuration 11 | @EnableConfigurationProperties(ConsumerDestinations.class) 12 | public class ConsumerConfiguration { 13 | 14 | @Bean 15 | public RouteLocator consumerProxyRouting(RouteLocatorBuilder builder, ConsumerDestinations consumerDestinations) { 16 | return builder.routes() 17 | .route(r -> r.path("/consumers").and().method("POST").uri(consumerDestinations.getConsumerServiceUrl())) 18 | .route(r -> r.path("/consumers").and().method("PUT").uri(consumerDestinations.getConsumerServiceUrl())) 19 | .build(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/consumers/ConsumerDestinations.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.consumers; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | @ConfigurationProperties(prefix = "consumer.destinations") 8 | public class ConsumerDestinations { 9 | 10 | @NotNull 11 | private String consumerServiceUrl; 12 | 13 | public String getConsumerServiceUrl() { 14 | return consumerServiceUrl; 15 | } 16 | 17 | public void setConsumerServiceUrl(String consumerServiceUrl) { 18 | this.consumerServiceUrl = consumerServiceUrl; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/orders/OrderDestinations.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.orders; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | import javax.validation.constraints.NotNull; 6 | 7 | @ConfigurationProperties(prefix = "order.destinations") 8 | public class OrderDestinations { 9 | 10 | @NotNull 11 | private String orderServiceUrl; 12 | 13 | @NotNull 14 | private String orderHistoryServiceUrl; 15 | 16 | public String getOrderHistoryServiceUrl() { 17 | return orderHistoryServiceUrl; 18 | } 19 | 20 | public void setOrderHistoryServiceUrl(String orderHistoryServiceUrl) { 21 | this.orderHistoryServiceUrl = orderHistoryServiceUrl; 22 | } 23 | 24 | 25 | public String getOrderServiceUrl() { 26 | return orderServiceUrl; 27 | } 28 | 29 | public void setOrderServiceUrl(String orderServiceUrl) { 30 | this.orderServiceUrl = orderServiceUrl; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/AccountingService.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | import org.springframework.stereotype.Service; 4 | import reactor.core.publisher.Mono; 5 | 6 | 7 | @Service 8 | public class AccountingService { 9 | public Mono findBillByOrderId(String orderId) { 10 | return Mono.error(new UnsupportedOperationException()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/BillInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | public class BillInfo { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/DeliveryInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | public class DeliveryInfo { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/DeliveryService.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import reactor.core.publisher.Mono; 6 | 7 | @Service 8 | public class DeliveryService { 9 | public Mono findDeliveryByOrderId(String orderId) { 10 | return Mono.error(new UnsupportedOperationException()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/KitchenService.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | import reactor.core.publisher.Mono; 6 | 7 | @Service 8 | public class KitchenService { 9 | public Mono findTicketById(String ticketId) { 10 | return Mono.error(new UnsupportedOperationException()); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/OrderInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | import org.apache.commons.lang3.builder.EqualsBuilder; 4 | import org.apache.commons.lang3.builder.HashCodeBuilder; 5 | import org.apache.commons.lang3.builder.ToStringBuilder; 6 | 7 | public class OrderInfo { 8 | 9 | private String orderId; 10 | private String state; 11 | 12 | public String getState() { 13 | return state; 14 | } 15 | 16 | public void setState(String state) { 17 | this.state = state; 18 | } 19 | 20 | public OrderInfo(String orderId, String state) { 21 | this.orderId = orderId; 22 | this.state = state; 23 | 24 | } 25 | 26 | private OrderInfo() { 27 | } 28 | 29 | public String getOrderId() { 30 | return orderId; 31 | } 32 | 33 | public void setOrderId(String orderId) { 34 | this.orderId = orderId; 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return ToStringBuilder.reflectionToString(this); 40 | } 41 | 42 | @Override 43 | public boolean equals(Object o) { 44 | return EqualsBuilder.reflectionEquals(this, o); 45 | } 46 | 47 | @Override 48 | public int hashCode() { 49 | return HashCodeBuilder.reflectionHashCode(this); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/OrderNotFoundException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | public class OrderNotFoundException extends RuntimeException { 4 | public OrderNotFoundException() { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/java/net/chrisrichardson/ftgo/apiagateway/proxies/TicketInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.proxies; 2 | 3 | public class TicketInfo { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-api-gateway 2 | 3 | logging.level.org.springframework.web=DEBUG 4 | logging.level.org.springframework.cloud=DEBUG 5 | logging.level.com.github.tomakehurst.wiremock=TRACE 6 | 7 | management.endpoints.web.exposure.include=health,prometheus 8 | 9 | spring.sleuth.sampler.probability=1.0 10 | 11 | # routes 12 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/ApiGatewayIntegrationTestConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.ComponentScan; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | @EnableAutoConfiguration 11 | @ComponentScan 12 | public class ApiGatewayIntegrationTestConfiguration { 13 | 14 | // Force it to be Netty to avoid casting exception in NettyWriteResponseFilter 15 | // Wiremock adds dependency on Jetty 16 | 17 | @Bean 18 | public NettyReactiveWebServerFactory NettyReactiveWebServerFactory() { 19 | return new NettyReactiveWebServerFactory(); 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/test/java/net/chrisrichardson/ftgo/apiagateway/contract/TestConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.apiagateway.contract; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | 5 | @Configuration 6 | public class TestConfiguration { 7 | 8 | } 9 | -------------------------------------------------------------------------------- /ftgo-api-gateway/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.hibernate.SQL=DEBUG 2 | logging.level.org.springframework.cloud=DEBUG 3 | logging.level.org.springframework.web=DEBUG 4 | logging.level.io.eventuate=DEBUG 5 | spring.jpa.generate-ddl=true 6 | stubrunner.stream.enabled=false 7 | stubrunner.integration.enabled=false -------------------------------------------------------------------------------- /ftgo-common-jpa/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | 3 | compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-common/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | // TODO eliminate this - problem is value objects like Money need to be embeddable. 3 | // TODO https://en.wikibooks.org/wiki/Java_Persistence/Embeddables#Example_of_an_Embeddable_object_XML 4 | 5 | // compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" 6 | compile "org.springframework.boot:spring-boot-starter:$springBootVersion" 7 | 8 | // compile "org.springframework.boot:spring-boot-starter:$springBootVersion" 9 | 10 | compile "io.eventuate.common:eventuate-common-json-mapper:$eventuateCommonVersion" 11 | 12 | testCompile "org.springframework.boot:spring-boot-starter-test:$springBootVersion" 13 | 14 | compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.7" 15 | 16 | runtime "javax.xml.bind:jaxb-api:2.2.11" 17 | runtime "com.sun.xml.bind:jaxb-core:2.2.11" 18 | runtime "com.sun.xml.bind:jaxb-impl:2.2.11" 19 | runtime "javax.activation:activation:1.1.1" 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/CommonConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | @Configuration 7 | public class CommonConfiguration { 8 | 9 | @Bean 10 | public CommonJsonMapperInitializer commonJsonMapperInitializer() { 11 | return new CommonJsonMapperInitializer(); 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/CommonJsonMapperInitializer.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | import com.fasterxml.jackson.databind.SerializationFeature; 4 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 5 | import io.eventuate.common.json.mapper.JSonMapper; 6 | 7 | import javax.annotation.PostConstruct; 8 | 9 | public class CommonJsonMapperInitializer { 10 | 11 | @PostConstruct 12 | public void initialize() { 13 | registerMoneyModule(); 14 | } 15 | 16 | public static void registerMoneyModule() { 17 | JSonMapper.objectMapper.registerModule(new MoneyModule()); 18 | JSonMapper.objectMapper.registerModule(new JavaTimeModule()); 19 | JSonMapper.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/NotYetImplementedException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | public class NotYetImplementedException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/PersonName.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | public class PersonName { 4 | private String firstName; 5 | private String lastName; 6 | 7 | private PersonName() { 8 | } 9 | 10 | public PersonName(String firstName, String lastName) { 11 | this.firstName = firstName; 12 | this.lastName = lastName; 13 | } 14 | 15 | public String getFirstName() { 16 | return firstName; 17 | } 18 | 19 | public String getLastName() { 20 | return lastName; 21 | } 22 | } -------------------------------------------------------------------------------- /ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/UnsupportedStateTransitionException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | public class UnsupportedStateTransitionException extends RuntimeException { 4 | public UnsupportedStateTransitionException(Enum state) { 5 | super("current state: " + state); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-common/src/test/java/net/chrisrichardson/ftgo/common/MoneyTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.common; 2 | 3 | 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.assertEquals; 7 | import static org.junit.Assert.assertFalse; 8 | import static org.junit.Assert.assertTrue; 9 | 10 | public class MoneyTest { 11 | 12 | private final int M1_AMOUNT = 10; 13 | private final int M2_AMOUNT = 15; 14 | 15 | private Money m1 = new Money(M1_AMOUNT); 16 | private Money m2 = new Money(M2_AMOUNT); 17 | 18 | @Test 19 | public void shouldReturnAsString() { 20 | assertEquals(Integer.toString(M1_AMOUNT), new Money(M1_AMOUNT).asString()); 21 | } 22 | 23 | @Test 24 | public void shouldCompare() { 25 | assertTrue(m2.isGreaterThanOrEqual(m2)); 26 | assertTrue(m2.isGreaterThanOrEqual(m1)); 27 | assertFalse(m1.isGreaterThanOrEqual(m2)); 28 | } 29 | 30 | @Test 31 | public void shouldAdd() { 32 | assertEquals(new Money(M1_AMOUNT + M2_AMOUNT), m1.add(m2)); 33 | } 34 | 35 | @Test 36 | public void shouldMultiply() { 37 | int multiplier = 12; 38 | assertEquals(new Money(M2_AMOUNT * multiplier), m2.multiply(multiplier)); 39 | } 40 | 41 | 42 | 43 | } -------------------------------------------------------------------------------- /ftgo-consumer-service-api-spec/src/main/resources/ValidateOrderByConsumer.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "consumerId": { 5 | "type": "integer", 6 | "format": "int64" 7 | }, 8 | "orderId": { 9 | "type": "integer", 10 | "format": "int64" 11 | }, 12 | "orderTotal": { 13 | "type": "string" 14 | } 15 | }, 16 | "required": [ 17 | "consumerId", 18 | "orderId", 19 | "orderTotal" 20 | ], 21 | "javaInterfaces": ["io.eventuate.tram.commands.common.Command"] 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-consumer-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | 3 | compile "io.eventuate.tram.sagas:eventuate-tram-sagas-spring-participant" 4 | compile project(":ftgo-common") 5 | 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-consumer-service-api/src/main/java/net/chrisrichardson/ftgo/consumerservice/api/ConsumerServiceChannels.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.api; 2 | 3 | public class ConsumerServiceChannels { 4 | public static final String consumerServiceChannel = "consumerService"; 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-consumer-service-contracts/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'spring-cloud-contract' 3 | apply plugin: 'maven-publish' 4 | 5 | 6 | publishing { 7 | repositories { 8 | maven { 9 | url "${project.rootDir}/build/repo" 10 | } 11 | } 12 | } 13 | 14 | contracts { 15 | contractsDslDir = file("${projectDir}/src/main/resources/contracts") 16 | } 17 | 18 | generateContractTests.enabled = false 19 | 20 | 21 | build.finalizedBy(publish) 22 | 23 | dependencies { 24 | compile 'org.codehaus.groovy:groovy-all:2.4.6' 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-consumer-service-contracts/src/main/resources/contracts/VerifyConsumer.groovy: -------------------------------------------------------------------------------- 1 | package contracts; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'verifyConsumer' 5 | input { 6 | messageFrom('consumerService') 7 | messageBody([ 8 | consumerId: 1511300065921L, 9 | orderId: 1, 10 | orderTotal: "61.70" 11 | ]) 12 | messageHeaders { 13 | } 14 | } 15 | outputMessage { 16 | sentTo('net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 17 | body('''{}''') 18 | headers { 19 | header('reply_type', 'io.eventuate.tram.commands.common.Success') 20 | header('reply_outcome-type', 'SUCCESS') 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /ftgo-consumer-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-consumer-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerCreated.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.domain; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public class ConsumerCreated implements DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerNotFoundException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.domain; 2 | 3 | public class ConsumerNotFoundException extends ConsumerVerificationFailedException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface ConsumerRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/domain/ConsumerVerificationFailedException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.domain; 2 | 3 | public class ConsumerVerificationFailedException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/main/ConsumerServiceMain.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.main; 2 | 3 | import io.eventuate.tram.spring.jdbckafka.TramJdbcKafkaConfiguration; 4 | import net.chrisrichardson.eventstore.examples.customersandorders.commonswagger.CommonSwaggerConfiguration; 5 | import net.chrisrichardson.ftgo.consumerservice.web.ConsumerWebConfiguration; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Import; 9 | 10 | @SpringBootApplication 11 | @Import({ConsumerWebConfiguration.class, TramJdbcKafkaConfiguration.class, CommonSwaggerConfiguration.class}) 12 | public class ConsumerServiceMain { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(ConsumerServiceMain.class, args); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/ConsumerWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.web; 2 | 3 | import net.chrisrichardson.ftgo.consumerservice.domain.ConsumerServiceConfiguration; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | @Configuration 9 | @ComponentScan 10 | @Import(ConsumerServiceConfiguration.class) 11 | public class ConsumerWebConfiguration { 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/CreateConsumerRequest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.web; 2 | 3 | import net.chrisrichardson.ftgo.common.PersonName; 4 | 5 | public class CreateConsumerRequest { 6 | private PersonName name; 7 | 8 | public PersonName getName() { 9 | return name; 10 | } 11 | 12 | public void setName(PersonName name) { 13 | this.name = name; 14 | } 15 | 16 | public CreateConsumerRequest(PersonName name) { 17 | 18 | this.name = name; 19 | } 20 | 21 | private CreateConsumerRequest() { 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/CreateConsumerResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.web; 2 | 3 | public class CreateConsumerResponse { 4 | private long consumerId; 5 | 6 | public long getConsumerId() { 7 | return consumerId; 8 | } 9 | 10 | public void setConsumerId(long consumerId) { 11 | this.consumerId = consumerId; 12 | } 13 | 14 | public CreateConsumerResponse() { 15 | 16 | } 17 | 18 | public CreateConsumerResponse(long consumerId) { 19 | this.consumerId = consumerId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/java/net/chrisrichardson/ftgo/consumerservice/web/GetConsumerResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.web; 2 | 3 | import net.chrisrichardson.ftgo.common.PersonName; 4 | 5 | public class GetConsumerResponse extends CreateConsumerResponse { 6 | private PersonName name; 7 | 8 | public PersonName getName() { 9 | return name; 10 | } 11 | 12 | public GetConsumerResponse(PersonName name) { 13 | 14 | this.name = name; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-consumer-service 2 | 3 | management.endpoint.health.show-details=always 4 | 5 | spring.jpa.generate-ddl=true 6 | logging.level.org.springframework.orm.jpa=INFO 7 | logging.level.org.hibernate.SQL=DEBUG 8 | logging.level.io.eventuate=DEBUG 9 | logging.level.net.chrisrichardson.ftgo=DEBUG 10 | logging.level.io.eventuate.tram=DEBUG 11 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_consumer_service 12 | spring.datasource.username=ftgo_consumer_service_user 13 | spring.datasource.password=ftgo_consumer_service_password 14 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 15 | 16 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 17 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 18 | -------------------------------------------------------------------------------- /ftgo-consumer-service/src/test/java/net/chrisrichardson/ftgo/consumerservice/api/ValidateOrderByConsumerTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.consumerservice.api; 2 | 3 | import net.chrisrichardson.ftgo.common.CommonJsonMapperInitializer; 4 | import net.chrisrichardson.ftgo.common.Money; 5 | import net.chrisrichardson.ftgo.testutil.jsonschema.ValidatingJSONMapper; 6 | import org.json.JSONObject; 7 | import org.junit.Test; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | 11 | public class ValidateOrderByConsumerTest { 12 | 13 | static { 14 | CommonJsonMapperInitializer.registerMoneyModule(); 15 | } 16 | 17 | @Test 18 | public void shouldDeserialize() { 19 | 20 | ValidatingJSONMapper mapper = ValidatingJSONMapper.forSchema("/ValidateOrderByConsumer.json"); 21 | 22 | JSONObject jsonObject = new JSONObject().put("consumerId", 1).put("orderId", 2).put("orderTotal", "12.34"); 23 | 24 | ValidateOrderByConsumer cmd = mapper.fromJSON(jsonObject, ValidateOrderByConsumer.class); 25 | 26 | assertEquals(1, cmd.getConsumerId()); 27 | assertEquals(2, cmd.getOrderId()); 28 | assertEquals(new Money("12.34"), cmd.getOrderTotal()); 29 | } 30 | 31 | 32 | } -------------------------------------------------------------------------------- /ftgo-delivery-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile project(":ftgo-common") 3 | } 4 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/ActionInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | public class ActionInfo { 4 | private DeliveryActionType type; 5 | 6 | public ActionInfo() { 7 | } 8 | 9 | public ActionInfo(DeliveryActionType type) { 10 | this.type = type; 11 | } 12 | 13 | public DeliveryActionType getType() { 14 | return type; 15 | } 16 | 17 | public void setType(DeliveryActionType type) { 18 | this.type = type; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/CourierAvailability.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | public class CourierAvailability { 4 | 5 | private boolean available; 6 | 7 | public CourierAvailability() { 8 | } 9 | 10 | public CourierAvailability(boolean available) { 11 | this.available = available; 12 | } 13 | 14 | public boolean isAvailable() { 15 | return available; 16 | } 17 | 18 | public void setAvailable(boolean available) { 19 | this.available = available; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/DeliveryActionType.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | public enum DeliveryActionType { PICKUP, DROPOFF 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/DeliveryInfo.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | public class DeliveryInfo { 4 | 5 | private long id; 6 | private DeliveryState state; 7 | 8 | public DeliveryInfo() { 9 | } 10 | 11 | public DeliveryInfo(long id, DeliveryState state) { 12 | 13 | this.id = id; 14 | this.state = state; 15 | } 16 | 17 | public long getId() { 18 | return id; 19 | } 20 | 21 | public void setId(long id) { 22 | this.id = id; 23 | } 24 | 25 | public DeliveryState getState() { 26 | return state; 27 | } 28 | 29 | public void setState(DeliveryState state) { 30 | this.state = state; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/DeliveryState.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | public enum DeliveryState { 4 | CANCELLED, SCHEDULED, PENDING 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-delivery-service-api/src/main/java/net/chrisrichardson/ftgo/deliveryservice/api/web/DeliveryStatus.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.api.web; 2 | 3 | import java.util.List; 4 | 5 | public class DeliveryStatus { 6 | private DeliveryInfo deliveryInfo; 7 | private Long assignedCourier; 8 | private List courierActions; 9 | 10 | public DeliveryStatus() { 11 | } 12 | 13 | public DeliveryInfo getDeliveryInfo() { 14 | return deliveryInfo; 15 | } 16 | 17 | public void setDeliveryInfo(DeliveryInfo deliveryInfo) { 18 | this.deliveryInfo = deliveryInfo; 19 | } 20 | 21 | public Long getAssignedCourier() { 22 | return assignedCourier; 23 | } 24 | 25 | public void setAssignedCourier(Long assignedCourier) { 26 | this.assignedCourier = assignedCourier; 27 | } 28 | 29 | public List getCourierActions() { 30 | return courierActions; 31 | } 32 | 33 | public void setCourierActions(List courierActions) { 34 | this.courierActions = courierActions; 35 | } 36 | 37 | public DeliveryStatus(DeliveryInfo deliveryInfo, Long assignedCourier, List courierActions) { 38 | this.deliveryInfo = deliveryInfo; 39 | this.assignedCourier = assignedCourier; 40 | this.courierActions = courierActions; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ftgo-delivery-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-delivery-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/CourierRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.data.jpa.repository.Query; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | import java.util.List; 7 | 8 | public interface CourierRepository extends CrudRepository, CustomCourierRepository { 9 | 10 | @Query("SELECT c FROM Courier c WHERE c.available = true") 11 | List findAllAvailable(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/CustomCourierRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.data.jpa.repository.Query; 4 | 5 | import java.util.List; 6 | 7 | public interface CustomCourierRepository { 8 | 9 | Courier findOrCreateCourier(long courierId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/CustomCourierRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | 5 | import javax.persistence.EntityManager; 6 | import java.util.List; 7 | 8 | public class CustomCourierRepositoryImpl implements CustomCourierRepository { 9 | 10 | @Autowired 11 | private EntityManager entityManager; 12 | 13 | // @Override 14 | // public List findAllAvailable() { 15 | // return entityManager.createQuery("").getResultList(); 16 | // } 17 | 18 | @Override 19 | public Courier findOrCreateCourier(long courierId) { 20 | Courier courier = entityManager.find(Courier.class, courierId); 21 | if (courier == null) { 22 | courier = Courier.create(courierId); 23 | entityManager.persist(courier); 24 | } 25 | return courier; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/DeliveryRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface DeliveryRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/DeliveryServiceDomainConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.boot.autoconfigure.domain.EntityScan; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | import org.springframework.transaction.annotation.EnableTransactionManagement; 8 | 9 | @Configuration 10 | @EntityScan 11 | @EnableJpaRepositories 12 | @EnableTransactionManagement 13 | public class DeliveryServiceDomainConfiguration { 14 | 15 | @Bean 16 | public DeliveryService deliveryService(RestaurantRepository restaurantRepository, DeliveryRepository deliveryRepository, CourierRepository courierRepository) { 17 | return new DeliveryService(restaurantRepository, deliveryRepository, courierRepository); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/Plan.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import javax.persistence.ElementCollection; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.stream.Collectors; 7 | 8 | public class Plan { 9 | 10 | @ElementCollection 11 | private List actions = new LinkedList<>(); 12 | 13 | public void add(Action action) { 14 | actions.add(action); 15 | } 16 | 17 | public void removeDelivery(long deliveryId) { 18 | actions = actions.stream().filter(action -> !action.actionFor(deliveryId)).collect(Collectors.toList()); 19 | } 20 | 21 | public List getActions() { 22 | return actions; 23 | } 24 | 25 | public List actionsForDelivery(long deliveryId) { 26 | return actions.stream().filter(action -> action.actionFor(deliveryId)).collect(Collectors.toList()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/Restaurant.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.common.Address; 4 | 5 | import javax.persistence.*; 6 | 7 | @Entity 8 | @Access(AccessType.FIELD) 9 | public class Restaurant { 10 | 11 | @Id 12 | private Long id; 13 | 14 | private String restaurantName; 15 | private Address address; 16 | 17 | private Restaurant() { 18 | } 19 | 20 | public Restaurant(long restaurantId, String restaurantName, Address address) { 21 | this.id = restaurantId; 22 | this.restaurantName = restaurantName; 23 | this.address = address; 24 | } 25 | 26 | public static Restaurant create(long restaurantId, String restaurantName, Address address) { 27 | return new Restaurant(restaurantId, restaurantName, address); 28 | } 29 | 30 | public Address getAddress() { 31 | return address; 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/domain/RestaurantRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface RestaurantRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/main/DeliveryServiceMain.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.main; 2 | 3 | import io.eventuate.tram.spring.jdbckafka.TramJdbcKafkaConfiguration; 4 | import net.chrisrichardson.eventstore.examples.customersandorders.commonswagger.CommonSwaggerConfiguration; 5 | import net.chrisrichardson.ftgo.deliveryservice.messaging.DeliveryServiceMessagingConfiguration; 6 | import net.chrisrichardson.ftgo.deliveryservice.web.DeliveryServiceWebConfiguration; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Import; 11 | 12 | @Configuration 13 | @EnableAutoConfiguration 14 | @Import({DeliveryServiceMessagingConfiguration.class, DeliveryServiceWebConfiguration.class, 15 | TramJdbcKafkaConfiguration.class, CommonSwaggerConfiguration.class 16 | }) 17 | public class DeliveryServiceMain { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication.run(DeliveryServiceMain.class, args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/messaging/RestaurantEventMapper.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.messaging; 2 | 3 | import net.chrisrichardson.ftgo.common.Address; 4 | 5 | public class RestaurantEventMapper { 6 | 7 | public static Address toAddress(net.chrisrichardson.ftgo.restaurantservice.events.Address address) { 8 | return new Address(address.getStreet1(), address.getStreet2(), address.getCity(), address.getState(), address.getZip()); 9 | } 10 | 11 | public static net.chrisrichardson.ftgo.restaurantservice.events.Address fromAddress(net.chrisrichardson.ftgo.common.Address a) { 12 | return new net.chrisrichardson.ftgo.restaurantservice.events.Address().withStreet1(a.getStreet1()).withStreet2(a.getStreet2()).withCity(a.getCity()).withZip(a.getZip()); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/java/net/chrisrichardson/ftgo/deliveryservice/web/DeliveryServiceWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.web; 2 | 3 | import net.chrisrichardson.ftgo.common.CommonConfiguration; 4 | import net.chrisrichardson.ftgo.deliveryservice.domain.DeliveryServiceDomainConfiguration; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Import; 8 | 9 | @Configuration 10 | @ComponentScan 11 | @Import({DeliveryServiceDomainConfiguration.class, CommonConfiguration.class}) 12 | public class DeliveryServiceWebConfiguration { 13 | } 14 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-order-service 2 | management.endpoint.health.show-details=always 3 | spring.sleuth.sampler.probability=1.0 4 | 5 | management.endpoints.web.exposure.include=health,prometheus,beans,endpoints 6 | 7 | logging.level.org.springframework.cloud=INFO 8 | 9 | spring.jpa.generate-ddl=true 10 | logging.level.org.springframework.orm.jpa=INFO 11 | logging.level.org.hibernate.SQL=DEBUG 12 | logging.level.io.eventuate=DEBUG 13 | logging.level.net.chrisrichardson.ftgo=DEBUG 14 | logging.level.io.eventuate.tram=DEBUG 15 | 16 | eventuate.database.schema=none 17 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_delivery_service 18 | spring.datasource.username=ftgo_delivery_service_user 19 | spring.datasource.password=ftgo_delivery_service_password 20 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 21 | 22 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 23 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 24 | -------------------------------------------------------------------------------- /ftgo-delivery-service/src/test/java/net/chrisrichardson/ftgo/deliveryservice/domain/DeliveryServiceTestData.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.deliveryservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.common.Address; 4 | 5 | public class DeliveryServiceTestData { 6 | public static final Address PICKUP_ADDRESS = 7 | new Address("1 Main Street", "Suite 501", "Oakland", "CA", "94612"); 8 | public static final Address DELIVERY_ADDRESS = 9 | new Address("1 Quiet Street", "Apartment 101", "Oakland", "CA", "94612"); 10 | } 11 | -------------------------------------------------------------------------------- /ftgo-end-to-end-tests/src/test/resources/contracts/create-revise-cancel.feature: -------------------------------------------------------------------------------- 1 | Feature: Create revise and cancel 2 | 3 | As a consumer of the Order Service 4 | I should be able to create, revise and cancel an order 5 | 6 | Scenario: Order authorized 7 | Given A valid consumer 8 | Given using a valid credit card 9 | Given the restaurant is accepting orders 10 | When I place an order for Chicken Vindaloo at Ajanta 11 | Then the order should be APPROVED 12 | And when I revise the order 13 | Then it should be revised 14 | And when I cancel the order 15 | Then the order should be CANCELED 16 | -------------------------------------------------------------------------------- /ftgo-end-to-end-tests/swagger-codegen-config/consumer-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "modelPackage": "net.chrisrichardson.ftgo.apis.model.consumerservice", 3 | "library" : "jersey2" 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-end-to-end-tests/swagger-codegen-config/restaurant-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "modelPackage": "net.chrisrichardson.ftgo.apis.model.restaurantservice", 3 | "library" : "jersey2" 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" 3 | compile "io.eventuate.tram.sagas:eventuate-tram-sagas-spring-participant" 4 | compile "io.eventuate.tram.core:eventuate-tram-spring-events" 5 | compile project(":ftgo-common") 6 | 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/BeginCancelTicketCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class BeginCancelTicketCommand implements Command { 6 | private long restaurantId; 7 | private long orderId; 8 | 9 | private BeginCancelTicketCommand() { 10 | } 11 | 12 | public BeginCancelTicketCommand(long restaurantId, long orderId) { 13 | 14 | this.restaurantId = restaurantId; 15 | this.orderId = orderId; 16 | } 17 | 18 | public long getRestaurantId() { 19 | return restaurantId; 20 | } 21 | 22 | public void setRestaurantId(long restaurantId) { 23 | this.restaurantId = restaurantId; 24 | } 25 | 26 | public long getOrderId() { 27 | return orderId; 28 | } 29 | 30 | public void setOrderId(long orderId) { 31 | this.orderId = orderId; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/CancelCreateTicket.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class CancelCreateTicket implements Command { 6 | private Long ticketId; 7 | 8 | private CancelCreateTicket() { 9 | } 10 | 11 | public CancelCreateTicket(long ticketId) { 12 | this.ticketId = ticketId; 13 | } 14 | 15 | public Long getTicketId() { 16 | return ticketId; 17 | } 18 | 19 | public void setTicketId(Long ticketId) { 20 | this.ticketId = ticketId; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/ChangeTicketLineItemQuantity.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | 4 | import io.eventuate.tram.commands.common.Command; 5 | 6 | public class ChangeTicketLineItemQuantity implements Command { 7 | public ChangeTicketLineItemQuantity(Long orderId) { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/ConfirmCancelTicketCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class ConfirmCancelTicketCommand implements Command { 6 | 7 | private long restaurantId; 8 | private long orderId; 9 | 10 | private ConfirmCancelTicketCommand() { 11 | } 12 | 13 | public ConfirmCancelTicketCommand(long restaurantId, long orderId) { 14 | 15 | this.restaurantId = restaurantId; 16 | this.orderId = orderId; 17 | } 18 | 19 | public long getRestaurantId() { 20 | return restaurantId; 21 | } 22 | 23 | public void setRestaurantId(long restaurantId) { 24 | this.restaurantId = restaurantId; 25 | } 26 | 27 | public long getOrderId() { 28 | return orderId; 29 | } 30 | 31 | public void setOrderId(long orderId) { 32 | this.orderId = orderId; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/ConfirmCreateTicket.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class ConfirmCreateTicket implements Command { 6 | private Long ticketId; 7 | 8 | private ConfirmCreateTicket() { 9 | } 10 | 11 | 12 | public ConfirmCreateTicket(Long ticketId) { 13 | this.ticketId = ticketId; 14 | } 15 | 16 | public Long getTicketId() { 17 | return ticketId; 18 | } 19 | 20 | public void setTicketId(Long ticketId) { 21 | this.ticketId = ticketId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/CreateTicketReply.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import org.apache.commons.lang.builder.EqualsBuilder; 4 | import org.apache.commons.lang.builder.HashCodeBuilder; 5 | import org.apache.commons.lang.builder.ToStringBuilder; 6 | 7 | public class CreateTicketReply { 8 | private long ticketId; 9 | 10 | private CreateTicketReply() { 11 | } 12 | 13 | public CreateTicketReply(long ticketId) { 14 | 15 | this.ticketId = ticketId; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return ToStringBuilder.reflectionToString(this); 21 | } 22 | 23 | @Override 24 | public boolean equals(Object o) { 25 | return EqualsBuilder.reflectionEquals(this, o); 26 | } 27 | 28 | @Override 29 | public int hashCode() { 30 | return HashCodeBuilder.reflectionHashCode(this); 31 | } 32 | 33 | public void setTicketId(long ticketId) { 34 | this.ticketId = ticketId; 35 | } 36 | 37 | public long getTicketId() { 38 | return ticketId; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/KitchenServiceChannels.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | public class KitchenServiceChannels { 4 | public static final String COMMAND_CHANNEL = "kitchenService"; 5 | public static final String TICKET_EVENT_CHANNEL = "net.chrisrichardson.ftgo.kitchenservice.domain.Ticket"; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/TicketDetails.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import org.apache.commons.lang.builder.ToStringBuilder; 4 | 5 | import java.util.List; 6 | 7 | public class TicketDetails { 8 | private List lineItems; 9 | 10 | public TicketDetails() { 11 | } 12 | 13 | public TicketDetails(List lineItems) { 14 | this.lineItems = lineItems; 15 | } 16 | 17 | public List getLineItems() { 18 | return lineItems; 19 | } 20 | 21 | public void setLineItems(List lineItems) { 22 | this.lineItems = lineItems; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | return ToStringBuilder.reflectionToString(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/TicketLineItem.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import javax.persistence.Access; 4 | import javax.persistence.AccessType; 5 | import javax.persistence.Embeddable; 6 | 7 | @Embeddable 8 | @Access(AccessType.FIELD) 9 | public class TicketLineItem { 10 | 11 | private int quantity; 12 | private String menuItemId; 13 | private String name; 14 | 15 | 16 | public int getQuantity() { 17 | return quantity; 18 | } 19 | 20 | public void setQuantity(int quantity) { 21 | this.quantity = quantity; 22 | } 23 | 24 | public String getMenuItemId() { 25 | return menuItemId; 26 | } 27 | 28 | public void setMenuItemId(String menuItemId) { 29 | this.menuItemId = menuItemId; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public void setName(String name) { 37 | this.name = name; 38 | } 39 | 40 | private TicketLineItem() { 41 | 42 | } 43 | 44 | public TicketLineItem(String menuItemId, String name, int quantity) { 45 | this.menuItemId = menuItemId; 46 | this.name = name; 47 | this.quantity = quantity; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/UndoBeginCancelTicketCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class UndoBeginCancelTicketCommand implements Command { 6 | 7 | private long restaurantId; 8 | private long orderId; 9 | 10 | private UndoBeginCancelTicketCommand() { 11 | } 12 | 13 | public UndoBeginCancelTicketCommand(long restaurantId, long orderId) { 14 | 15 | this.restaurantId = restaurantId; 16 | this.orderId = orderId; 17 | } 18 | 19 | public long getOrderId() { 20 | return orderId; 21 | } 22 | 23 | public void setOrderId(long orderId) { 24 | this.orderId = orderId; 25 | } 26 | 27 | public long getRestaurantId() { 28 | return restaurantId; 29 | } 30 | 31 | public void setRestaurantId(long restaurantId) { 32 | this.restaurantId = restaurantId; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/UndoBeginReviseTicketCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public class UndoBeginReviseTicketCommand implements Command { 6 | private long restaurantId; 7 | private Long orderId; 8 | 9 | public UndoBeginReviseTicketCommand() { 10 | } 11 | 12 | public UndoBeginReviseTicketCommand(long restaurantId, Long orderId) { 13 | 14 | this.restaurantId = restaurantId; 15 | this.orderId = orderId; 16 | } 17 | 18 | public long getRestaurantId() { 19 | return restaurantId; 20 | } 21 | 22 | public void setRestaurantId(long restaurantId) { 23 | this.restaurantId = restaurantId; 24 | } 25 | 26 | public Long getOrderId() { 27 | return orderId; 28 | } 29 | 30 | public void setOrderId(Long orderId) { 31 | this.orderId = orderId; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/events/TicketAcceptedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api.events; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public class TicketAcceptedEvent implements TicketDomainEvent { 6 | private LocalDateTime readyBy; 7 | 8 | public TicketAcceptedEvent() { 9 | } 10 | 11 | public TicketAcceptedEvent(LocalDateTime readyBy) { 12 | this.readyBy = readyBy; 13 | } 14 | 15 | public LocalDateTime getReadyBy() { 16 | return readyBy; 17 | } 18 | 19 | public void setReadyBy(LocalDateTime readyBy) { 20 | this.readyBy = readyBy; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/events/TicketCancelled.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api.events; 2 | 3 | public class TicketCancelled implements TicketDomainEvent { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/events/TicketDomainEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api.events; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public interface TicketDomainEvent extends DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-api/src/main/java/net/chrisrichardson/ftgo/kitchenservice/api/web/TicketAcceptance.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.api.web; 2 | 3 | import java.time.LocalDateTime; 4 | 5 | public class TicketAcceptance { 6 | private LocalDateTime readyBy; 7 | 8 | public TicketAcceptance() { 9 | } 10 | 11 | public TicketAcceptance(LocalDateTime readyBy) { 12 | this.readyBy = readyBy; 13 | } 14 | 15 | public LocalDateTime getReadyBy() { 16 | return readyBy; 17 | } 18 | 19 | public void setReadyBy(LocalDateTime readyBy) { 20 | this.readyBy = readyBy; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-contracts/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'spring-cloud-contract' 3 | apply plugin: 'maven-publish' 4 | 5 | 6 | publishing { 7 | repositories { 8 | maven { 9 | url "${project.rootDir}/build/repo" 10 | } 11 | } 12 | } 13 | 14 | contracts { 15 | contractsDslDir = file("${projectDir}/src/main/resources/contracts") 16 | } 17 | 18 | generateContractTests.enabled = false 19 | 20 | build.finalizedBy(publish) 21 | 22 | dependencies { 23 | compile 'org.codehaus.groovy:groovy-all:2.4.6' 24 | } 25 | -------------------------------------------------------------------------------- /ftgo-kitchen-service-contracts/src/main/resources/contracts/deliveryservice/messaging/TicketAcceptedEvent.groovy: -------------------------------------------------------------------------------- 1 | package contracts.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'ticketAcceptedEvent' 5 | input { 6 | triggeredBy('ticketAcceptedEvent()') 7 | } 8 | 9 | outputMessage { 10 | sentTo('net.chrisrichardson.ftgo.kitchenservice.domain.Ticket') 11 | body( 12 | readyBy: $(consumer('2019-08-20T14:20:00.979'), producer(regex('20[0-9]{2}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]+'))) 13 | ) 14 | headers { 15 | header('event-aggregate-type', 'net.chrisrichardson.ftgo.kitchenservice.domain.Ticket') 16 | header('event-type', 'net.chrisrichardson.ftgo.kitchenservice.api.events.TicketAcceptedEvent') 17 | header('event-aggregate-id', '99') 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /ftgo-kitchen-service-contracts/src/main/resources/contracts/messaging/ConfirmCreateTicket.groovy: -------------------------------------------------------------------------------- 1 | package contracts.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'confirmCreateTicket' 5 | input { 6 | messageFrom('kitchenService') 7 | messageBody('''{"ticketId":1}''') 8 | messageHeaders { 9 | header('command_type','net.chrisrichardson.ftgo.kitchenservice.api.ConfirmCreateTicket') 10 | header('command_saga_type','net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga') 11 | header('command_saga_id',$(consumer(regex('[0-9a-f]{16}-[0-9a-f]{16}')))) 12 | header('command_reply_to', 'net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 13 | } 14 | } 15 | outputMessage { 16 | sentTo('net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 17 | headers { 18 | header('reply_type', 'io.eventuate.tram.commands.common.Success') 19 | header('reply_outcome-type', 'SUCCESS') 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ftgo-kitchen-service-contracts/src/main/resources/contracts/messaging/CreateTicket.groovy: -------------------------------------------------------------------------------- 1 | package contracts.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'createTicket' 5 | input { 6 | messageFrom('kitchenService') 7 | messageBody('''{"orderId":99,"restaurantId":1,"ticketDetails":{"lineItems":[{"quantity":5,"menuItemId":"1","name":"Chicken Vindaloo"}]}}''') 8 | messageHeaders { 9 | header('command_type','net.chrisrichardson.ftgo.kitchenservice.api.CreateTicket') 10 | header('command_saga_type','net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga') 11 | header('command_saga_id',$(consumer(regex('[0-9a-f]{16}-[0-9a-f]{16}')))) 12 | header('command_reply_to', 'net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 13 | } 14 | } 15 | outputMessage { 16 | sentTo('net.chrisrichardson.ftgo.orderservice.sagas.createorder.CreateOrderSaga-reply') 17 | body([ 18 | ticketId: 99 19 | ]) 20 | headers { 21 | header('reply_type', 'net.chrisrichardson.ftgo.kitchenservice.api.CreateTicketReply') 22 | header('reply_outcome-type', 'SUCCESS') 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /ftgo-kitchen-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-kitchen-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/CancelCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | public class CancelCommand { 4 | private long orderId; 5 | private boolean force; 6 | 7 | public long getOrderId() { 8 | return orderId; 9 | } 10 | 11 | public boolean isForce() { 12 | return force; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/ChangeLineItemQuantityCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | public class ChangeLineItemQuantityCommand { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantDetailsVerificationException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | public class RestaurantDetailsVerificationException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantMenu.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import java.util.List; 4 | 5 | public class RestaurantMenu { 6 | private List menuItems; 7 | 8 | public RestaurantMenu(List menuItems) { 9 | this.menuItems = menuItems; 10 | } 11 | 12 | public List getMenuItems() { 13 | return menuItems; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/RestaurantRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface RestaurantRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | 4 | import net.chrisrichardson.ftgo.kitchenservice.api.TicketDetails; 5 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 6 | 7 | public class TicketCreatedEvent implements TicketDomainEvent { 8 | public TicketCreatedEvent(Long id, TicketDetails details) { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketDomainEventPublisher.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import io.eventuate.tram.events.aggregates.AbstractAggregateDomainEventPublisher; 4 | import io.eventuate.tram.events.publisher.DomainEventPublisher; 5 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 6 | 7 | public class TicketDomainEventPublisher extends AbstractAggregateDomainEventPublisher { 8 | 9 | public TicketDomainEventPublisher(DomainEventPublisher eventPublisher) { 10 | super(eventPublisher, Ticket.class, Ticket::getId); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketNotFoundException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | public class TicketNotFoundException extends RuntimeException { 4 | public TicketNotFoundException(long orderId) { 5 | super("Ticket not found: " + orderId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketPickedUpEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 4 | 5 | public class TicketPickedUpEvent implements TicketDomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketPreparationCompletedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 4 | 5 | public class TicketPreparationCompletedEvent implements TicketDomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketPreparationStartedEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 4 | 5 | public class TicketPreparationStartedEvent implements TicketDomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface TicketRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketRevised.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | 4 | import net.chrisrichardson.ftgo.kitchenservice.api.events.TicketDomainEvent; 5 | 6 | public class TicketRevised implements TicketDomainEvent { 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketState.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | public enum TicketState { 4 | CREATE_PENDING, AWAITING_ACCEPTANCE, ACCEPTED, PREPARING, READY_FOR_PICKUP, PICKED_UP, CANCEL_PENDING, CANCELLED, REVISION_PENDING, 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/main/KitchenServiceMain.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.main; 2 | 3 | import io.eventuate.tram.spring.jdbckafka.TramJdbcKafkaConfiguration; 4 | import net.chrisrichardson.eventstore.examples.customersandorders.commonswagger.CommonSwaggerConfiguration; 5 | import net.chrisrichardson.ftgo.kitchenservice.messagehandlers.KitchenServiceMessageHandlersConfiguration; 6 | import net.chrisrichardson.ftgo.kitchenservice.web.KitchenServiceWebConfiguration; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.annotation.Import; 10 | 11 | @SpringBootApplication 12 | @Import({KitchenServiceWebConfiguration.class, 13 | KitchenServiceMessageHandlersConfiguration.class, 14 | TramJdbcKafkaConfiguration.class, 15 | CommonSwaggerConfiguration.class}) 16 | public class KitchenServiceMain { 17 | 18 | public static void main(String[] args) { 19 | SpringApplication.run(KitchenServiceMain.class, args); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/messagehandlers/RestaurantEventMapper.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.messagehandlers; 2 | 3 | import net.chrisrichardson.ftgo.common.Money; 4 | import net.chrisrichardson.ftgo.restaurantservice.events.MenuItem; 5 | 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | 9 | public class RestaurantEventMapper { 10 | 11 | public static List toMenuItems(List menuItems) { 12 | return menuItems.stream().map(mi -> new net.chrisrichardson.ftgo.kitchenservice.domain.MenuItem(mi.getId(), mi.getName(), new Money(mi.getPrice()))).collect(Collectors.toList()); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/web/GetRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.web; 2 | 3 | public class GetRestaurantResponse { 4 | private long restaurantId; 5 | 6 | public long getRestaurantId() { 7 | return restaurantId; 8 | } 9 | 10 | public void setRestaurantId(long restaurantId) { 11 | this.restaurantId = restaurantId; 12 | } 13 | 14 | public GetRestaurantResponse() { 15 | 16 | } 17 | 18 | public GetRestaurantResponse(long restaurantId) { 19 | this.restaurantId = restaurantId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/web/KitchenController.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.web; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.api.web.TicketAcceptance; 4 | import net.chrisrichardson.ftgo.kitchenservice.domain.KitchenService; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | @RestController 10 | public class KitchenController { 11 | 12 | private KitchenService kitchenService; 13 | 14 | public KitchenController(KitchenService kitchenService) { 15 | this.kitchenService = kitchenService; 16 | } 17 | 18 | @RequestMapping(path="/tickets/{ticketId}/accept", method= RequestMethod.POST) 19 | public void acceptTicket(@PathVariable long ticketId, @RequestBody TicketAcceptance ticketAcceptance) { 20 | kitchenService.accept(ticketId, ticketAcceptance.getReadyBy()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/java/net/chrisrichardson/ftgo/kitchenservice/web/KitchenServiceWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.web; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.domain.KitchenDomainConfiguration; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | @Configuration 9 | @Import(KitchenDomainConfiguration.class) 10 | @ComponentScan 11 | public class KitchenServiceWebConfiguration { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-kitchen-service 2 | 3 | management.endpoint.health.show-details=always 4 | 5 | spring.jpa.generate-ddl=true 6 | logging.level.org.springframework.orm.jpa=INFO 7 | logging.level.org.hibernate.SQL=DEBUG 8 | logging.level.io.eventuate=DEBUG 9 | logging.level.net.chrisrichardson.ftgo=DEBUG 10 | logging.level.io.eventuate.tram=DEBUG 11 | 12 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_kitchen_service 13 | spring.datasource.username=ftgo_kitchen_service_user 14 | spring.datasource.password=ftgo_kitchen_service_password 15 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 16 | 17 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 18 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 19 | -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/test/java/net/chrisrichardson/ftgo/kitchenservice/domain/TicketDomainEventPublisherTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.kitchenservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.kitchenservice.api.KitchenServiceChannels; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.*; 7 | 8 | public class TicketDomainEventPublisherTest { 9 | 10 | @Test 11 | public void verifyTicketEventChannel() { 12 | assertEquals(KitchenServiceChannels.TICKET_EVENT_CHANNEL, new TicketDomainEventPublisher(null).getAggregateType().getName()); 13 | } 14 | 15 | 16 | } -------------------------------------------------------------------------------- /ftgo-kitchen-service/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.hibernate.SQL=DEBUG 2 | logging.level.org.springframework.cloud.contract=DEBUG 3 | logging.level.io.eventuate=DEBUG 4 | spring.jpa.generate-ddl=true 5 | stubrunner.stream.enabled=false 6 | stubrunner.integration.enabled=false 7 | 8 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/eventuate 9 | spring.datasource.username=mysqluser 10 | spring.datasource.password=mysqlpw 11 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 12 | spring.data.mongodb.uri=mongodb://${DOCKER_HOST_IP:localhost}/bankingexampledb 13 | 14 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 15 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 16 | 17 | aws.access.key_id=id_key 18 | aws.secret.access.key=access_key 19 | aws.dynamodb.endpoint.url=http://${DOCKER_HOST_IP:localhost}:8000 20 | aws.region=us-west-2 21 | -------------------------------------------------------------------------------- /ftgo-order-history-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-order-history-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/DeliveryPickedUp.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public class DeliveryPickedUp implements DomainEvent { 6 | private String orderId; 7 | 8 | public String getOrderId() { 9 | return orderId; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/Location.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory; 2 | 3 | public class Location { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/OrderHistory.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory; 2 | 3 | import net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb.Order; 4 | 5 | import java.util.List; 6 | import java.util.Optional; 7 | import java.util.stream.Stream; 8 | 9 | public class OrderHistory { 10 | private List orders; 11 | private Optional startKey; 12 | 13 | public OrderHistory(List orders, Optional startKey) { 14 | this.orders = orders; 15 | this.startKey = startKey; 16 | } 17 | 18 | public List getOrders() { 19 | return orders; 20 | } 21 | 22 | public Optional getStartKey() { 23 | return startKey; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/OrderHistoryDao.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory; 2 | 3 | 4 | import net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb.SourceEvent; 5 | import net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb.Order; 6 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderState; 7 | 8 | import java.util.Optional; 9 | 10 | public interface OrderHistoryDao { 11 | 12 | boolean addOrder(Order order, Optional eventSource); 13 | 14 | OrderHistory findOrderHistory(String consumerId, OrderHistoryFilter filter); 15 | 16 | boolean updateOrderState(String orderId, OrderState newState, Optional eventSource); 17 | 18 | void noteTicketPreparationStarted(String orderId); 19 | 20 | void noteTicketPreparationCompleted(String orderId); 21 | 22 | void notePickedUp(String orderId, Optional eventSource); 23 | 24 | void updateLocation(String orderId, Location location); 25 | 26 | void noteDelivered(String orderId); 27 | 28 | Optional findOrder(String orderId); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/AvMapBuilder.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb; 2 | 3 | import com.amazonaws.services.dynamodbv2.model.AttributeValue; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class AvMapBuilder { 9 | 10 | private Map eav = new HashMap<>(); 11 | 12 | public AvMapBuilder(String key, AttributeValue value) { 13 | eav.put(key, value); 14 | } 15 | 16 | public AvMapBuilder add(String key, String value) { 17 | eav.put(key, new AttributeValue(value)); 18 | return this; 19 | } 20 | 21 | public AvMapBuilder add(String key, AttributeValue value) { 22 | eav.put(key, value); 23 | return this; 24 | } 25 | 26 | public Map map() { 27 | return eav; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/DeliveryStatus.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb; 2 | 3 | public enum DeliveryStatus { 4 | PICKED_UP 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/DynamoDBHealthIndicator.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb; 2 | 3 | import com.amazonaws.services.dynamodbv2.document.DynamoDB; 4 | import com.amazonaws.services.dynamodbv2.document.Table; 5 | import org.springframework.boot.actuate.health.Health; 6 | import org.springframework.boot.actuate.health.HealthIndicator; 7 | 8 | public class DynamoDBHealthIndicator implements HealthIndicator { 9 | private final Table table; 10 | private DynamoDB dynamoDB; 11 | 12 | public DynamoDBHealthIndicator(DynamoDB dynamoDB) { 13 | this.dynamoDB = dynamoDB; 14 | this.table = this.dynamoDB.getTable(OrderHistoryDaoDynamoDb.FTGO_ORDER_HISTORY_BY_ID); 15 | } 16 | 17 | @Override 18 | public Health health() { 19 | try { 20 | table.getItem(OrderHistoryDaoDynamoDb.makePrimaryKey("999")); 21 | return Health.up().build(); 22 | } catch (Exception e) { 23 | return Health.down(e).build(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/Expressions.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import java.util.Optional; 6 | 7 | public class Expressions { 8 | 9 | static String and(String s1, Optional s2) { 10 | return s2.map(x -> and(s1, x)).orElse(s1); 11 | } 12 | 13 | static String and(String s1, String s2) { 14 | if (StringUtils.isBlank(s1)) 15 | return s2; 16 | if (StringUtils.isBlank(s2)) 17 | return s1; 18 | return String.format("(%s) AND (%s)", s1, s2); 19 | } 20 | 21 | static String or(String s1, String s2) { 22 | if (StringUtils.isBlank(s1)) 23 | return s2; 24 | if (StringUtils.isBlank(s2)) 25 | return s1; 26 | return String.format("(%s) AND (%s)", s1, s2); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/dynamodb/Maps.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb; 2 | 3 | import org.joda.time.DurationField; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | public class Maps { 9 | 10 | private final Map map; 11 | 12 | public Maps() { 13 | this.map = new HashMap<>(); 14 | } 15 | 16 | public Maps add(String key, Object value) { 17 | map.put(key, value); 18 | return this; 19 | } 20 | 21 | public Map map() { 22 | return map; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/main/OrderHistoryServiceMain.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.main; 2 | 3 | import io.eventuate.tram.spring.consumer.common.TramConsumerCommonConfiguration; 4 | import io.eventuate.tram.spring.consumer.kafka.EventuateTramKafkaMessageConsumerConfiguration; 5 | import net.chrisrichardson.eventstore.examples.customersandorders.commonswagger.CommonSwaggerConfiguration; 6 | import net.chrisrichardson.ftgo.cqrs.orderhistory.messaging.OrderHistoryServiceMessagingConfiguration; 7 | import net.chrisrichardson.ftgo.cqrs.orderhistory.web.OrderHistoryWebConfiguration; 8 | import org.springframework.boot.SpringApplication; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.context.annotation.Import; 11 | 12 | @SpringBootApplication 13 | @Import({OrderHistoryWebConfiguration.class, 14 | OrderHistoryServiceMessagingConfiguration.class, 15 | CommonSwaggerConfiguration.class, 16 | TramConsumerCommonConfiguration.class, 17 | EventuateTramKafkaMessageConsumerConfiguration.class}) 18 | public class OrderHistoryServiceMain { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(OrderHistoryServiceMain.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/web/GetOrdersResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.web; 2 | 3 | import java.util.List; 4 | 5 | public class GetOrdersResponse { 6 | private List orders; 7 | private String startKey; 8 | 9 | private GetOrdersResponse() { 10 | } 11 | 12 | public List getOrders() { 13 | return orders; 14 | } 15 | 16 | public void setOrders(List orders) { 17 | this.orders = orders; 18 | } 19 | 20 | public String getStartKey() { 21 | return startKey; 22 | } 23 | 24 | public void setStartKey(String startKey) { 25 | this.startKey = startKey; 26 | } 27 | 28 | public GetOrdersResponse(List orders, String startKey) { 29 | this.orders = orders; 30 | this.startKey = startKey; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/java/net/chrisrichardson/ftgo/cqrs/orderhistory/web/OrderHistoryWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.cqrs.orderhistory.web; 2 | 3 | import net.chrisrichardson.ftgo.cqrs.orderhistory.dynamodb.OrderHistoryDynamoDBConfiguration; 4 | import org.springframework.context.annotation.ComponentScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | @Configuration 9 | @ComponentScan 10 | @Import(OrderHistoryDynamoDBConfiguration.class) 11 | public class OrderHistoryWebConfiguration { 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-order-history-service 2 | 3 | management.endpoint.health.show-details=always 4 | 5 | logging.level.io.eventuate=DEBUG 6 | logging.level.net.chrisrichardson.ftgo=DEBUG 7 | logging.level.io.eventuate.tram=DEBUG 8 | logging.level.root=INFO 9 | 10 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 11 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 12 | 13 | aws.access.key_id=id_key 14 | aws.secret.access.key=access_key 15 | aws.dynamodb.endpoint.url=http://${DOCKER_HOST_IP:localhost}:8000 16 | aws.region=us-west-2 17 | -------------------------------------------------------------------------------- /ftgo-order-history-service/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.hibernate.SQL=DEBUG 2 | logging.level.org.springframework.cloud.contract=DEBUG 3 | logging.level.io.eventuate=DEBUG 4 | spring.jpa.generate-ddl=true 5 | stubrunner.stream.enabled=false 6 | stubrunner.integration.enabled=false 7 | 8 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/eventuate 9 | spring.datasource.username=mysqluser 10 | spring.datasource.password=mysqlpw 11 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 12 | spring.data.mongodb.uri=mongodb://${DOCKER_HOST_IP:localhost}/bankingexampledb 13 | 14 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 15 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 16 | 17 | aws.access.key_id=id_key 18 | aws.secret.access.key=access_key 19 | aws.dynamodb.endpoint.url=http://${DOCKER_HOST_IP:localhost}:8000 20 | aws.region=us-west-2 21 | -------------------------------------------------------------------------------- /ftgo-order-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion" 3 | compile "io.eventuate.tram.core:eventuate-tram-spring-events" 4 | compile project(":ftgo-common") 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/OrderServiceChannels.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api; 2 | 3 | public class OrderServiceChannels { 4 | public static final String COMMAND_CHANNEL = "orderService"; 5 | public static final String ORDER_EVENT_CHANNEL = "net.chrisrichardson.ftgo.orderservice.domain.Order"; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderAuthorized.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.events; 2 | 3 | import org.apache.commons.lang.builder.EqualsBuilder; 4 | import org.apache.commons.lang.builder.HashCodeBuilder; 5 | 6 | public class OrderAuthorized implements OrderDomainEvent { 7 | 8 | @Override 9 | public boolean equals(Object o) { 10 | return EqualsBuilder.reflectionEquals(this, o); 11 | } 12 | 13 | @Override 14 | public int hashCode() { 15 | return HashCodeBuilder.reflectionHashCode(this); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderCancelled.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.events; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderDomainEvent; 5 | 6 | public class OrderCancelled implements OrderDomainEvent { 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderDomainEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.events; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public interface OrderDomainEvent extends DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderRejected.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.events; 2 | 3 | public class OrderRejected implements OrderDomainEvent { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/events/OrderState.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.events; 2 | 3 | public enum OrderState { 4 | APPROVAL_PENDING, 5 | APPROVED, 6 | REJECTED, 7 | CANCEL_PENDING, 8 | CANCELLED, 9 | REVISION_PENDING, 10 | } 11 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/web/CreateOrderResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.web; 2 | 3 | public class CreateOrderResponse { 4 | private long orderId; 5 | 6 | public long getOrderId() { 7 | return orderId; 8 | } 9 | 10 | public void setOrderId(long orderId) { 11 | this.orderId = orderId; 12 | } 13 | 14 | private CreateOrderResponse() { 15 | } 16 | 17 | public CreateOrderResponse(long orderId) { 18 | this.orderId = orderId; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-order-service-api/src/main/java/net/chrisrichardson/ftgo/orderservice/api/web/ReviseOrderRequest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.api.web; 2 | 3 | import net.chrisrichardson.ftgo.common.RevisedOrderLineItem; 4 | 5 | import java.util.List; 6 | 7 | public class ReviseOrderRequest { 8 | private List revisedOrderLineItems; 9 | 10 | private ReviseOrderRequest() { 11 | } 12 | 13 | public ReviseOrderRequest(List revisedOrderLineItems) { 14 | this.revisedOrderLineItems = revisedOrderLineItems; 15 | } 16 | 17 | public List getRevisedOrderLineItems() { 18 | return revisedOrderLineItems; 19 | } 20 | 21 | public void setRevisedOrderLineItems(List revisedOrderLineItems) { 22 | this.revisedOrderLineItems = revisedOrderLineItems; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ftgo-order-service-contracts/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'spring-cloud-contract' 3 | apply plugin: 'maven-publish' 4 | 5 | 6 | publishing { 7 | repositories { 8 | maven { 9 | url "${project.rootDir}/build/repo" 10 | } 11 | } 12 | } 13 | 14 | contracts { 15 | contractsDslDir = file("${projectDir}/src/main/resources/contracts") 16 | } 17 | 18 | generateContractTests.enabled = false 19 | 20 | 21 | build.finalizedBy(publish) 22 | 23 | dependencies { 24 | compile 'org.codehaus.groovy:groovy-all:2.4.6' 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-order-service-contracts/src/main/resources/contracts/deliveryservice/messaging/OrderCreatedEvent.groovy: -------------------------------------------------------------------------------- 1 | package deliveryservice.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'orderCreatedForDeliveryService' 5 | input { 6 | triggeredBy('orderCreatedEvent()') 7 | } 8 | 9 | outputMessage { 10 | sentTo('net.chrisrichardson.ftgo.orderservice.domain.Order') 11 | body('''{"orderDetails":{"lineItems":[{"quantity":5,"menuItemId":"1","name":"Chicken Vindaloo","price":"12.34","total":"61.70"}],"orderTotal":"61.70","restaurantId":1, "consumerId":1511300065921}, "deliveryAddress":{ "street1" : "9 Amazing View", "city" : "Oakland", "state" : "CA", "zip" : "94612", }, "restaurantName" : "Ajanta"}''') 12 | headers { 13 | header('event-aggregate-type', 'net.chrisrichardson.ftgo.orderservice.domain.Order') 14 | header('event-type', 'net.chrisrichardson.ftgo.orderservice.api.events.OrderCreatedEvent') 15 | header('event-aggregate-id', '99') // Matches OrderDetailsMother.ORDER_ID 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ftgo-order-service-contracts/src/main/resources/contracts/http/GetNonExistentOrder.groovy: -------------------------------------------------------------------------------- 1 | package contracts.http; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | request { 5 | method 'GET' 6 | url '/orders/555' 7 | } 8 | response { 9 | status 404 10 | } 11 | } -------------------------------------------------------------------------------- /ftgo-order-service-contracts/src/main/resources/contracts/http/GetOrder.groovy: -------------------------------------------------------------------------------- 1 | package contracts.http; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | request { 5 | method 'GET' 6 | url '/orders/99' 7 | } 8 | response { 9 | status 200 10 | headers { 11 | header('Content-Type': 'application/json') 12 | } 13 | body('''{"orderId" : "99", "state" : "APPROVAL_PENDING"}''') 14 | } 15 | } -------------------------------------------------------------------------------- /ftgo-order-service-contracts/src/main/resources/contracts/messaging/OrderCreatedEvent.groovy: -------------------------------------------------------------------------------- 1 | package contracts.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'orderCreatedEvent' 5 | input { 6 | triggeredBy('orderCreated()') 7 | } 8 | 9 | outputMessage { 10 | sentTo('net.chrisrichardson.ftgo.orderservice.domain.Order') 11 | body('''{"orderDetails":{"lineItems":[{"quantity":5,"menuItemId":"1","name":"Chicken Vindaloo","price":"12.34","total":"61.70"}],"orderTotal":"61.70","restaurantId":1, "consumerId":1511300065921}, "restaurantName" : "Ajanta"}''') 12 | headers { 13 | header('event-aggregate-type', 'net.chrisrichardson.ftgo.orderservice.domain.Order') 14 | header('event-type', 'net.chrisrichardson.ftgo.orderservice.api.events.OrderCreatedEvent') 15 | header('event-aggregate-id', '99') // Matches OrderDetailsMother.ORDER_ID 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ftgo-order-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-order-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-order-service/src/component-test/java/net/chrisrichardson/ftgo/orderservice/cucumber/OrderServiceComponentTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.cucumber; 2 | 3 | import cucumber.api.CucumberOptions; 4 | import cucumber.api.junit.Cucumber; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(Cucumber.class) 8 | @CucumberOptions(features = "src/component-test/resources/features") 9 | public class OrderServiceComponentTest { 10 | } -------------------------------------------------------------------------------- /ftgo-order-service/src/component-test/resources/features/place-order.feature: -------------------------------------------------------------------------------- 1 | Feature: Place Order 2 | 3 | As a consumer of the Order Service 4 | I should be able to place an order 5 | 6 | Scenario: Order authorized 7 | Given A valid consumer 8 | Given using a valid credit card 9 | Given the restaurant is accepting orders 10 | When I place an order for Chicken Vindaloo at Ajanta 11 | Then the order should be APPROVED 12 | And an OrderAuthorized event should be published 13 | 14 | Scenario: Order rejected due to expired credit card 15 | Given A valid consumer 16 | Given using an expired credit card 17 | Given the restaurant is accepting orders 18 | When I place an order for Chicken Vindaloo at Ajanta 19 | Then the order should be REJECTED 20 | And an OrderRejected event should be published 21 | -------------------------------------------------------------------------------- /ftgo-order-service/src/deployment/kubernetes-prometheus/prometheus.yml: -------------------------------------------------------------------------------- 1 | apiVersion: monitoring.coreos.com/v1 2 | kind: ServiceMonitor 3 | metadata: 4 | name: ftgo-monitoring 5 | namespace: monitoring 6 | labels: 7 | prometheus: kube-prometheus 8 | spec: 9 | jobLabel: component 10 | selector: 11 | matchLabels: 12 | app: ftgo 13 | namespaceSelector: 14 | matchNames: 15 | - default 16 | endpoints: 17 | - port: metricsport 18 | path: /actuator/prometheus 19 | interval: 16s 20 | scheme: http 21 | --- 22 | -------------------------------------------------------------------------------- /ftgo-order-service/src/deployment/kubernetes-prometheus/rbac.yml: -------------------------------------------------------------------------------- 1 | apiVersion: rbac.authorization.k8s.io/v1beta1 2 | kind: ClusterRole 3 | metadata: 4 | name: prometheus-operator 5 | rules: 6 | - apiGroups: 7 | - extensions 8 | resources: 9 | - thirdpartyresources 10 | verbs: 11 | - "*" 12 | - apiGroups: 13 | - apiextensions.k8s.io 14 | resources: 15 | - customresourcedefinitions 16 | verbs: 17 | - "*" 18 | - apiGroups: 19 | - monitoring.coreos.com 20 | resources: 21 | - alertmanagers 22 | - prometheuses 23 | - prometheuses/finalizers 24 | - servicemonitors 25 | verbs: 26 | - "*" 27 | - apiGroups: 28 | - apps 29 | resources: 30 | - statefulsets 31 | verbs: ["*"] 32 | - apiGroups: [""] 33 | resources: 34 | - configmaps 35 | - secrets 36 | verbs: ["*"] 37 | - apiGroups: [""] 38 | resources: 39 | - pods 40 | verbs: ["list", "delete"] 41 | - apiGroups: [""] 42 | resources: 43 | - services 44 | - endpoints 45 | verbs: ["get", "create", "update"] 46 | - apiGroups: [""] 47 | resources: 48 | - nodes 49 | verbs: ["list", "watch"] 50 | - apiGroups: [""] 51 | resources: 52 | - namespaces 53 | verbs: ["list"] -------------------------------------------------------------------------------- /ftgo-order-service/src/integration-test/java/net/chrisrichardson/ftgo/orderservice/domain/OrderJpaTestConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import io.eventuate.tram.spring.consumer.jdbc.TramConsumerJdbcAutoConfiguration; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | 8 | @Configuration 9 | @EnableJpaRepositories 10 | @EnableAutoConfiguration(exclude = TramConsumerJdbcAutoConfiguration.class) 11 | public class OrderJpaTestConfiguration { 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-order-service/src/integration-test/java/net/chrisrichardson/ftgo/orderservice/grpc/OrderServiceGrpIntegrationTestConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.grpc; 2 | 3 | import net.chrisrichardson.ftgo.orderservice.domain.OrderService; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.context.annotation.Import; 7 | 8 | import static org.mockito.Mockito.mock; 9 | 10 | @Configuration 11 | @Import(GrpcConfiguration.class) 12 | public class OrderServiceGrpIntegrationTestConfiguration { 13 | 14 | @Bean 15 | public OrderService orderService() { 16 | return mock(OrderService.class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/InvalidMenuItemIdException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class InvalidMenuItemIdException extends RuntimeException { 4 | public InvalidMenuItemIdException(String menuItemId) { 5 | super("Invalid menu item id " + menuItemId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/LineItemQuantityChange.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.common.Money; 4 | 5 | public class LineItemQuantityChange { 6 | final Money currentOrderTotal; 7 | final Money newOrderTotal; 8 | final Money delta; 9 | 10 | public LineItemQuantityChange(Money currentOrderTotal, Money newOrderTotal, Money delta) { 11 | this.currentOrderTotal = currentOrderTotal; 12 | this.newOrderTotal = newOrderTotal; 13 | this.delta = delta; 14 | } 15 | 16 | public Money getCurrentOrderTotal() { 17 | return currentOrderTotal; 18 | } 19 | 20 | public Money getNewOrderTotal() { 21 | return newOrderTotal; 22 | } 23 | 24 | public Money getDelta() { 25 | return delta; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OptimisticOfflineLockException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class OptimisticOfflineLockException extends RuntimeException { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderAuthorizedCancelRequested.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public class OrderAuthorizedCancelRequested implements DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderCancelRequested.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderState; 5 | 6 | public class OrderCancelRequested implements DomainEvent { 7 | private OrderState state; 8 | 9 | public OrderCancelRequested(OrderState state) { 10 | 11 | this.state = state; 12 | } 13 | 14 | public OrderState getState() { 15 | return state; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderDomainEventPublisher.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import io.eventuate.tram.events.aggregates.AbstractAggregateDomainEventPublisher; 4 | import io.eventuate.tram.events.publisher.DomainEventPublisher; 5 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderDomainEvent; 6 | 7 | public class OrderDomainEventPublisher extends AbstractAggregateDomainEventPublisher { 8 | 9 | 10 | public OrderDomainEventPublisher(DomainEventPublisher eventPublisher) { 11 | super(eventPublisher, Order.class, Order::getId); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderLineItemChangeQueued.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public class OrderLineItemChangeQueued implements DomainEvent { 6 | public OrderLineItemChangeQueued(String lineItemId, int newQuantity) { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderMinimumNotMetException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class OrderMinimumNotMetException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderNotFoundException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class OrderNotFoundException extends RuntimeException { 4 | public OrderNotFoundException(Long orderId) { 5 | super("Order not found" + orderId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRejectedCancelRequested.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class OrderRejectedCancelRequested { 4 | } 5 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface OrderRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRevised.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | 4 | import io.eventuate.tram.events.common.DomainEvent; 5 | import net.chrisrichardson.ftgo.common.Money; 6 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderDomainEvent; 7 | 8 | public class OrderRevised implements OrderDomainEvent { 9 | 10 | private final OrderRevision orderRevision; 11 | private final Money currentOrderTotal; 12 | private final Money newOrderTotal; 13 | 14 | public OrderRevision getOrderRevision() { 15 | return orderRevision; 16 | } 17 | 18 | public Money getCurrentOrderTotal() { 19 | return currentOrderTotal; 20 | } 21 | 22 | public Money getNewOrderTotal() { 23 | return newOrderTotal; 24 | } 25 | 26 | public OrderRevised(OrderRevision orderRevision, Money currentOrderTotal, Money newOrderTotal) { 27 | this.orderRevision = orderRevision; 28 | this.currentOrderTotal = currentOrderTotal; 29 | this.newOrderTotal = newOrderTotal; 30 | 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRevisionProposed.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | // import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | import io.eventuate.tram.events.common.DomainEvent; 6 | import net.chrisrichardson.ftgo.common.Money; 7 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderDomainEvent; 8 | 9 | public class OrderRevisionProposed implements OrderDomainEvent { 10 | 11 | 12 | private final OrderRevision orderRevision; 13 | private final Money currentOrderTotal; 14 | private final Money newOrderTotal; 15 | 16 | public OrderRevisionProposed(OrderRevision orderRevision, Money currentOrderTotal, Money newOrderTotal) { 17 | this.orderRevision = orderRevision; 18 | this.currentOrderTotal = currentOrderTotal; 19 | this.newOrderTotal = newOrderTotal; 20 | } 21 | 22 | public OrderRevision getOrderRevision() { 23 | return orderRevision; 24 | } 25 | 26 | public Money getCurrentOrderTotal() { 27 | return currentOrderTotal; 28 | } 29 | 30 | public Money getNewOrderTotal() { 31 | return newOrderTotal; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderRevisionRejected.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | 4 | import io.eventuate.tram.events.common.DomainEvent; 5 | 6 | public class OrderRevisionRejected implements DomainEvent { 7 | 8 | public OrderRevisionRejected(OrderRevision orderRevision) { 9 | throw new UnsupportedOperationException(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/OrderServiceWithRepositoriesConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.context.annotation.Import; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | 8 | @Configuration 9 | @EnableJpaRepositories 10 | @EnableAutoConfiguration 11 | @Import({OrderServiceConfiguration.class}) 12 | public class OrderServiceWithRepositoriesConfiguration { 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/PaymentInformation.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import javax.persistence.Access; 4 | import javax.persistence.AccessType; 5 | 6 | @Access(AccessType.FIELD) 7 | public class PaymentInformation { 8 | 9 | private String paymentToken; 10 | } 11 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/RestaurantNotFoundException.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class RestaurantNotFoundException extends RuntimeException { 4 | public RestaurantNotFoundException(long restaurantId) { 5 | super("Restaurant not found with id " + restaurantId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/RestaurantRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface RestaurantRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/domain/RevisedOrder.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | public class RevisedOrder { 4 | private final Order order; 5 | private final LineItemQuantityChange change; 6 | 7 | public RevisedOrder(Order order, LineItemQuantityChange change) { 8 | this.order = order; 9 | this.change = change; 10 | } 11 | 12 | public Order getOrder() { 13 | return order; 14 | } 15 | 16 | public LineItemQuantityChange getChange() { 17 | return change; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/grpc/GrpcConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.grpc; 2 | 3 | import net.chrisrichardson.ftgo.orderservice.domain.OrderService; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | public class GrpcConfiguration { 9 | 10 | @Bean 11 | public OrderServiceServer helloWorldServer(OrderService orderService) { 12 | return new OrderServiceServer(orderService); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/AccountingServiceProxy.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import io.eventuate.tram.commands.common.Success; 4 | import io.eventuate.tram.sagas.simpledsl.CommandEndpoint; 5 | import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder; 6 | import net.chrisrichardson.ftgo.accountservice.api.AccountingServiceChannels; 7 | import net.chrisrichardson.ftgo.accountservice.api.AuthorizeCommand; 8 | 9 | public class AccountingServiceProxy { 10 | 11 | public final CommandEndpoint authorize= CommandEndpointBuilder 12 | .forCommand(AuthorizeCommand.class) 13 | .withChannel(AccountingServiceChannels.accountingServiceChannel) 14 | .withReply(Success.class) 15 | .build(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/ApproveOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class ApproveOrderCommand extends OrderCommand { 4 | 5 | private ApproveOrderCommand() { 6 | } 7 | 8 | public ApproveOrderCommand(long orderId) { 9 | super(orderId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/BeginCancelCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class BeginCancelCommand extends OrderCommand { 4 | 5 | private BeginCancelCommand() { 6 | } 7 | 8 | public BeginCancelCommand(long orderId) { 9 | super(orderId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/BeginReviseOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import net.chrisrichardson.ftgo.orderservice.domain.OrderRevision; 4 | 5 | public class BeginReviseOrderCommand extends OrderCommand { 6 | 7 | private BeginReviseOrderCommand() { 8 | } 9 | 10 | public BeginReviseOrderCommand(long orderId, OrderRevision revision) { 11 | super(orderId); 12 | this.revision = revision; 13 | } 14 | 15 | private OrderRevision revision; 16 | 17 | public OrderRevision getRevision() { 18 | return revision; 19 | } 20 | 21 | public void setRevision(OrderRevision revision) { 22 | this.revision = revision; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/BeginReviseOrderReply.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | 4 | import net.chrisrichardson.ftgo.common.Money; 5 | 6 | public class BeginReviseOrderReply { 7 | private Money revisedOrderTotal; 8 | 9 | public BeginReviseOrderReply(Money revisedOrderTotal) { 10 | this.revisedOrderTotal = revisedOrderTotal; 11 | } 12 | 13 | public BeginReviseOrderReply() { 14 | } 15 | 16 | public Money getRevisedOrderTotal() { 17 | return revisedOrderTotal; 18 | } 19 | 20 | public void setRevisedOrderTotal(Money revisedOrderTotal) { 21 | this.revisedOrderTotal = revisedOrderTotal; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/ConfirmCancelOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class ConfirmCancelOrderCommand extends OrderCommand { 4 | 5 | private ConfirmCancelOrderCommand() { 6 | } 7 | 8 | public ConfirmCancelOrderCommand(long orderId) { 9 | super(orderId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/ConfirmReviseOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import net.chrisrichardson.ftgo.orderservice.domain.OrderRevision; 4 | 5 | public class ConfirmReviseOrderCommand extends OrderCommand { 6 | 7 | private ConfirmReviseOrderCommand() { 8 | } 9 | 10 | public ConfirmReviseOrderCommand(long orderId, OrderRevision revision) { 11 | super(orderId); 12 | this.revision = revision; 13 | } 14 | 15 | private OrderRevision revision; 16 | 17 | public OrderRevision getRevision() { 18 | return revision; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/ConsumerServiceProxy.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import io.eventuate.tram.commands.common.Success; 4 | import io.eventuate.tram.sagas.simpledsl.CommandEndpoint; 5 | import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder; 6 | import net.chrisrichardson.ftgo.consumerservice.api.ConsumerServiceChannels; 7 | import net.chrisrichardson.ftgo.consumerservice.api.ValidateOrderByConsumer; 8 | 9 | public class ConsumerServiceProxy { 10 | 11 | 12 | public final CommandEndpoint validateOrder= CommandEndpointBuilder 13 | .forCommand(ValidateOrderByConsumer.class) 14 | .withChannel(ConsumerServiceChannels.consumerServiceChannel) 15 | .withReply(Success.class) 16 | .build(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/KitchenServiceProxy.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import io.eventuate.tram.commands.common.Success; 4 | import io.eventuate.tram.sagas.simpledsl.CommandEndpoint; 5 | import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder; 6 | import net.chrisrichardson.ftgo.kitchenservice.api.*; 7 | 8 | public class KitchenServiceProxy { 9 | 10 | public final CommandEndpoint create = CommandEndpointBuilder 11 | .forCommand(CreateTicket.class) 12 | .withChannel(KitchenServiceChannels.COMMAND_CHANNEL) 13 | .withReply(CreateTicketReply.class) 14 | .build(); 15 | 16 | public final CommandEndpoint confirmCreate = CommandEndpointBuilder 17 | .forCommand(ConfirmCreateTicket.class) 18 | .withChannel(KitchenServiceChannels.COMMAND_CHANNEL) 19 | .withReply(Success.class) 20 | .build(); 21 | public final CommandEndpoint cancel = CommandEndpointBuilder 22 | .forCommand(CancelCreateTicket.class) 23 | .withChannel(KitchenServiceChannels.COMMAND_CHANNEL) 24 | .withReply(Success.class) 25 | .build(); 26 | 27 | } -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/OrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import io.eventuate.tram.commands.common.Command; 4 | 5 | public abstract class OrderCommand implements Command { 6 | 7 | private long orderId; 8 | 9 | protected OrderCommand() { 10 | } 11 | 12 | protected OrderCommand(long orderId) { 13 | this.orderId = orderId; 14 | } 15 | 16 | public long getOrderId() { 17 | return orderId; 18 | } 19 | 20 | public void setOrderId(long orderId) { 21 | this.orderId = orderId; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/OrderServiceProxy.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | import io.eventuate.tram.commands.common.Success; 4 | import io.eventuate.tram.sagas.simpledsl.CommandEndpoint; 5 | import io.eventuate.tram.sagas.simpledsl.CommandEndpointBuilder; 6 | import net.chrisrichardson.ftgo.orderservice.api.OrderServiceChannels; 7 | 8 | public class OrderServiceProxy { 9 | 10 | public final CommandEndpoint reject = CommandEndpointBuilder 11 | .forCommand(RejectOrderCommand.class) 12 | .withChannel(OrderServiceChannels.COMMAND_CHANNEL) 13 | .withReply(Success.class) 14 | .build(); 15 | 16 | public final CommandEndpoint approve = CommandEndpointBuilder 17 | .forCommand(ApproveOrderCommand.class) 18 | .withChannel(OrderServiceChannels.COMMAND_CHANNEL) 19 | .withReply(Success.class) 20 | .build(); 21 | 22 | } -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/RejectOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class RejectOrderCommand extends OrderCommand { 4 | 5 | private RejectOrderCommand() { 6 | } 7 | 8 | public RejectOrderCommand(long orderId) { 9 | super(orderId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/ReverseOrderUpdateCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | 4 | import io.eventuate.tram.commands.common.Command; 5 | 6 | public class ReverseOrderUpdateCommand implements Command { 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/UndoBeginCancelCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class UndoBeginCancelCommand extends OrderCommand { 4 | public UndoBeginCancelCommand(long orderId) { 5 | super(orderId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagaparticipants/UndoBeginReviseOrderCommand.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagaparticipants; 2 | 3 | public class UndoBeginReviseOrderCommand extends OrderCommand { 4 | 5 | protected UndoBeginReviseOrderCommand() { 6 | } 7 | 8 | public UndoBeginReviseOrderCommand(long orderId) { 9 | super(orderId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/cancelorder/CancelOrderSagaState.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagas.cancelorder; 2 | 3 | public enum CancelOrderSagaState { 4 | state, WAITING_TO_AUTHORIZE, COMPLETED, REVERSING 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/sagas/reviseorder/ReviseOrderSagaState.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.sagas.reviseorder; 2 | 3 | public enum ReviseOrderSagaState { 4 | REQUESTING_RESTAURANT_ORDER_UPDATE, AUTHORIZATION_INCREASED, COMPLETED, REQUESTING_AUTHORIZATION, REVERSING_ORDER_UPDATE, REVERSING_AUTHORIZATION, WAITING_FOR_CHANGE_TO_BE_MADE 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/GetOrderResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.web; 2 | 3 | import net.chrisrichardson.ftgo.common.Money; 4 | import net.chrisrichardson.ftgo.orderservice.api.events.OrderState; 5 | 6 | public class GetOrderResponse { 7 | private long orderId; 8 | private OrderState state; 9 | private Money orderTotal; 10 | 11 | private GetOrderResponse() { 12 | } 13 | 14 | public GetOrderResponse(long orderId, OrderState state, Money orderTotal) { 15 | this.orderId = orderId; 16 | this.state = state; 17 | this.orderTotal = orderTotal; 18 | } 19 | 20 | public Money getOrderTotal() { 21 | return orderTotal; 22 | } 23 | 24 | public void setOrderTotal(Money orderTotal) { 25 | this.orderTotal = orderTotal; 26 | } 27 | 28 | public long getOrderId() { 29 | return orderId; 30 | } 31 | 32 | public void setOrderId(long orderId) { 33 | this.orderId = orderId; 34 | } 35 | 36 | public OrderState getState() { 37 | return state; 38 | } 39 | 40 | public void setState(OrderState state) { 41 | this.state = state; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/GetRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.web; 2 | 3 | public class GetRestaurantResponse { 4 | private long restaurantId; 5 | 6 | private GetRestaurantResponse() { 7 | } 8 | 9 | public GetRestaurantResponse(long restaurantId) { 10 | 11 | this.restaurantId = restaurantId; 12 | } 13 | 14 | public long getRestaurantId() { 15 | return restaurantId; 16 | } 17 | 18 | public void setRestaurantId(long restaurantId) { 19 | this.restaurantId = restaurantId; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/MenuItemIdAndQuantity.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.web; 2 | 3 | import org.apache.commons.lang.builder.EqualsBuilder; 4 | import org.apache.commons.lang.builder.HashCodeBuilder; 5 | import org.apache.commons.lang.builder.ToStringBuilder; 6 | 7 | public class MenuItemIdAndQuantity { 8 | 9 | private String menuItemId; 10 | private int quantity; 11 | 12 | public String getMenuItemId() { 13 | return menuItemId; 14 | } 15 | 16 | public int getQuantity() { 17 | return quantity; 18 | } 19 | 20 | public void setMenuItemId(String menuItemId) { 21 | this.menuItemId = menuItemId; 22 | } 23 | 24 | public MenuItemIdAndQuantity(String menuItemId, int quantity) { 25 | 26 | this.menuItemId = menuItemId; 27 | this.quantity = quantity; 28 | 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | return EqualsBuilder.reflectionEquals(this, o); 34 | } 35 | 36 | @Override 37 | public int hashCode() { 38 | return HashCodeBuilder.reflectionHashCode(this); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return ToStringBuilder.reflectionToString(this); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/java/net/chrisrichardson/ftgo/orderservice/web/OrderWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.web; 2 | 3 | import brave.sampler.Sampler; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import io.eventuate.common.json.mapper.JSonMapper; 6 | import net.chrisrichardson.ftgo.orderservice.domain.OrderServiceWithRepositoriesConfiguration; 7 | import org.springframework.context.annotation.*; 8 | 9 | @Configuration 10 | @ComponentScan 11 | @Import(OrderServiceWithRepositoriesConfiguration.class) 12 | public class OrderWebConfiguration { 13 | 14 | @Bean 15 | @Primary 16 | public ObjectMapper objectMapper() { 17 | return JSonMapper.objectMapper; 18 | } 19 | 20 | @Bean 21 | public Sampler defaultSampler() { 22 | return Sampler.ALWAYS_SAMPLE; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ftgo-order-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-order-service 2 | management.endpoint.health.show-details=always 3 | spring.sleuth.sampler.probability=1.0 4 | 5 | management.endpoints.web.exposure.include=health,prometheus,beans,endpoints 6 | 7 | logging.level.org.springframework.cloud=INFO 8 | 9 | spring.jpa.generate-ddl=true 10 | logging.level.org.springframework.orm.jpa=INFO 11 | logging.level.org.hibernate.SQL=DEBUG 12 | logging.level.io.eventuate=DEBUG 13 | logging.level.net.chrisrichardson.ftgo=DEBUG 14 | logging.level.io.eventuate.tram=DEBUG 15 | 16 | eventuate.database.schema=none 17 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_order_service 18 | spring.datasource.username=ftgo_order_service_user 19 | spring.datasource.password=ftgo_order_service_password 20 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 21 | 22 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 23 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 24 | -------------------------------------------------------------------------------- /ftgo-order-service/src/test/java/net/chrisrichardson/ftgo/orderservice/domain/OrderDomainEventPublisherTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.orderservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.orderservice.api.OrderServiceChannels; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.*; 7 | 8 | public class OrderDomainEventPublisherTest { 9 | 10 | @Test 11 | public void verifyOrderEventChannel() { 12 | assertEquals(OrderServiceChannels.ORDER_EVENT_CHANNEL, new OrderDomainEventPublisher(null).getAggregateType().getName()); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/MenuItem.json: -------------------------------------------------------------------------------- 1 | { 2 | "type" : "object", 3 | "javaType" : "net.chrisrichardson.ftgo.restaurantservice.events.MenuItem", 4 | "properties" : { 5 | "id" : { 6 | "type" : "string" 7 | }, 8 | "name" : { 9 | "type" : "string" 10 | }, 11 | "price" : { 12 | "type" : "string" 13 | } 14 | }, 15 | "required": [ 16 | "id", 17 | "name", 18 | "price" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantCreated.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "name": { 5 | "type": "string" 6 | }, 7 | "address": { 8 | "type": "object", 9 | "properties": { 10 | "street1": { 11 | "type": "string" 12 | }, 13 | "street2": { 14 | "type": "string" 15 | }, 16 | "city": { 17 | "type": "string" 18 | }, 19 | "state": { 20 | "type": "string" 21 | }, 22 | "zip": { 23 | "type": "string" 24 | } 25 | }, 26 | "required": [ 27 | "street1", 28 | "city", 29 | "state", 30 | "zip" 31 | ] 32 | }, 33 | "menu": { 34 | "type": "object", 35 | "properties": { 36 | "menuItems": { 37 | "type": "array", 38 | "items": { 39 | "$ref": "MenuItem.json" 40 | } 41 | } 42 | } 43 | } 44 | }, 45 | "required": [ 46 | "name", 47 | "menu", 48 | "address" 49 | ], 50 | "javaInterfaces": [ 51 | "io.eventuate.tram.events.common.DomainEvent" 52 | ] 53 | } -------------------------------------------------------------------------------- /ftgo-restaurant-service-api-spec/src/main/resources/ftgo-restaurant-service-api-spec/messages/RestaurantMenuRevised.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "menu": { 5 | "type": "object", 6 | "properties": { 7 | "menuItems": { 8 | "type": "array", 9 | "items": { 10 | "$ref": "MenuItem.json" 11 | } 12 | } 13 | } 14 | } 15 | }, 16 | "required": [ "menu" 17 | ], 18 | "javaInterfaces": [ 19 | "io.eventuate.tram.events.common.DomainEvent" 20 | ] 21 | } -------------------------------------------------------------------------------- /ftgo-restaurant-service-api/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | dependencies { 3 | compile "io.eventuate.tram.core:eventuate-tram-spring-events" 4 | compile project(":ftgo-common") 5 | } 6 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-api/src/main/java/net/chrisrichardson/ftgo/restaurantservice/RestaurantServiceChannels.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice; 2 | 3 | public class RestaurantServiceChannels { 4 | 5 | public static final String RESTAURANT_EVENT_CHANNEL = "net.chrisrichardson.ftgo.restaurantservice.domain.Restaurant"; 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/serverless.yml: -------------------------------------------------------------------------------- 1 | service: ftgo-application-lambda 2 | 3 | provider: 4 | name: aws 5 | runtime: java8 6 | timeout: 35 7 | region: ${env:AWS_REGION} 8 | stage: dev 9 | environment: 10 | SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.jdbc.Driver 11 | SPRING_DATASOURCE_URL: ${env:AWS_RDS_JDBC_URL} 12 | SPRING_DATASOURCE_USERNAME: ${env:AWS_RDS_JDBC_USER_ID} 13 | SPRING_DATASOURCE_PASSWORD: ${env:AWS_RDS_JDBC_USER_PASSWORD} 14 | vpc: 15 | securityGroupIds: 16 | - ${AWS_RDS_SECURITY_GROUP_ID} 17 | subnetIds: 18 | - ${AWS_RDS_SECURITY_VPC_ID} 19 | 20 | package: 21 | artifact: build/distributions/ftgo-restaurant-service-aws-lambda.zip 22 | 23 | 24 | functions: 25 | create-restaurant: 26 | handler: net.chrisrichardson.ftgo.restaurantservice.lambda.CreateRestaurantRequestHandler 27 | events: 28 | - http: 29 | path: restaurants 30 | method: post 31 | find-restaurant: 32 | handler: net.chrisrichardson.ftgo.restaurantservice.lambda.FindRestaurantRequestHandler 33 | events: 34 | - http: 35 | path: restaurants/{restaurantId} 36 | method: get 37 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/integration-test/java/net/chrisrichardson/ftgo/restaurantservice/lambda/RestaurantServiceLambdaConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.lambda; 2 | 3 | import net.chrisrichardson.ftgo.restaurantservice.domain.RestaurantService; 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | @RunWith(SpringRunner.class) 11 | @SpringBootTest(classes = RestaurantServiceLambdaConfiguration.class) 12 | public class RestaurantServiceLambdaConfigurationTest { 13 | 14 | @Autowired 15 | private RestaurantService restaurantService; 16 | @Test 17 | public void shouldInitialize() {} 18 | } -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/aws/AwsLambdaError.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.aws; 2 | 3 | public class AwsLambdaError { 4 | private String type; 5 | private String code; 6 | private String requestId; 7 | private String message; 8 | 9 | public AwsLambdaError() { 10 | } 11 | 12 | public AwsLambdaError(String type, String code, String requestId, String message) { 13 | this.type = type; 14 | this.code = code; 15 | this.requestId = requestId; 16 | this.message = message; 17 | } 18 | 19 | public String getType() { 20 | return type; 21 | } 22 | 23 | public String getCode() { 24 | return code; 25 | } 26 | 27 | public String getRequestId() { 28 | return requestId; 29 | } 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.common.Address; 4 | 5 | public class CreateRestaurantRequest { 6 | 7 | private String name; 8 | private Address address; 9 | private RestaurantMenu menu; 10 | 11 | private CreateRestaurantRequest() { 12 | 13 | } 14 | 15 | public CreateRestaurantRequest(String name, Address address, RestaurantMenu menu) { 16 | this.name = name; 17 | this.address = address; 18 | this.menu = menu; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public RestaurantMenu getMenu() { 30 | return menu; 31 | } 32 | 33 | public void setMenu(RestaurantMenu menu) { 34 | this.menu = menu; 35 | } 36 | 37 | public Address getAddress() { 38 | return address; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import javax.persistence.Access; 4 | import javax.persistence.AccessType; 5 | import javax.persistence.Embedded; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | 11 | @Entity 12 | @Table(name = "restaurants") 13 | @Access(AccessType.FIELD) 14 | public class Restaurant { 15 | 16 | @Id 17 | @GeneratedValue 18 | private Long id; 19 | 20 | private String name; 21 | 22 | @Embedded 23 | private RestaurantMenu menu; 24 | 25 | private Restaurant() { 26 | } 27 | 28 | public void setId(Long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public void setName(String name) { 37 | this.name = name; 38 | } 39 | 40 | 41 | public Restaurant(String name, RestaurantMenu menu) { 42 | this.name = name; 43 | this.menu = menu; 44 | } 45 | 46 | 47 | public Long getId() { 48 | return id; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface RestaurantRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantServiceDomainConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import io.eventuate.tram.spring.events.publisher.TramEventsPublisherConfiguration; 4 | import net.chrisrichardson.ftgo.common.CommonConfiguration; 5 | import org.springframework.boot.autoconfigure.domain.EntityScan; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.context.annotation.Import; 9 | import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; 10 | 11 | @Configuration 12 | @EntityScan 13 | @Import({TramEventsPublisherConfiguration.class, CommonConfiguration.class}) 14 | public class RestaurantServiceDomainConfiguration { 15 | 16 | @Bean 17 | public RestaurantService restaurantService(JpaRepositoryFactoryBean restaurantRepository) { 18 | return new RestaurantService((RestaurantRepository) restaurantRepository.getObject()); 19 | } 20 | 21 | @Bean 22 | public JpaRepositoryFactoryBean restaurantRepository() { 23 | return new JpaRepositoryFactoryBean<>(RestaurantRepository.class); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantDomainEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.events; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public interface RestaurantDomainEvent extends DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantMenuRevised.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.events; 2 | 3 | import net.chrisrichardson.ftgo.restaurantservice.domain.RestaurantMenu; 4 | 5 | public class RestaurantMenuRevised implements RestaurantDomainEvent { 6 | 7 | private RestaurantMenu menu; 8 | 9 | public RestaurantMenu getRevisedMenu() { 10 | return menu; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/lambda/GetRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.lambda; 2 | 3 | public class GetRestaurantResponse { 4 | private String name; 5 | 6 | public String getName() { 7 | return name; 8 | } 9 | 10 | public void setName(String name) { 11 | this.name = name; 12 | } 13 | 14 | public GetRestaurantResponse(String name) { 15 | this.name = name; 16 | 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/lambda/RestaurantServiceLambdaConfiguration.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.lambda; 2 | 3 | import io.eventuate.tram.spring.messaging.producer.jdbc.TramMessageProducerJdbcConfiguration; 4 | import net.chrisrichardson.ftgo.restaurantservice.domain.RestaurantServiceDomainConfiguration; 5 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Import; 8 | 9 | @Configuration 10 | @Import({RestaurantServiceDomainConfiguration.class, TramMessageProducerJdbcConfiguration.class}) 11 | @EnableAutoConfiguration 12 | public class RestaurantServiceLambdaConfiguration { 13 | } 14 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/CreateRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.web; 2 | 3 | public class CreateRestaurantResponse { 4 | private long id; 5 | 6 | public CreateRestaurantResponse() { 7 | } 8 | 9 | public long getId() { 10 | return id; 11 | } 12 | 13 | public void setId(long id) { 14 | this.id = id; 15 | } 16 | 17 | public CreateRestaurantResponse(long id) { 18 | this.id = id; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-aws-lambda/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | logging.level.org.springframework=INFO 2 | logging.level.org.springframework.jdbc.datasource.DataSourceUtils=DEBUG 3 | 4 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/eventuate 5 | spring.datasource.username=mysqluser 6 | spring.datasource.password=mysqlpw 7 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 8 | 9 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 10 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 11 | 12 | aws.access.key_id=id_key 13 | aws.secret.access.key=access_key 14 | aws.dynamodb.endpoint.url=http://${DOCKER_HOST_IP:localhost}:8000 15 | aws.region=us-west-2 16 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-contracts/build.gradle: -------------------------------------------------------------------------------- 1 | 2 | apply plugin: 'groovy' 3 | apply plugin: 'spring-cloud-contract' 4 | apply plugin: 'maven-publish' 5 | 6 | 7 | publishing { 8 | repositories { 9 | maven { 10 | url "${project.rootDir}/build/repo" 11 | } 12 | } 13 | } 14 | 15 | contracts { 16 | contractsDslDir = file("${projectDir}/src/main/resources/contracts") 17 | } 18 | 19 | generateContractTests.enabled = false 20 | 21 | 22 | build.finalizedBy(publish) 23 | 24 | dependencies { 25 | compile 'org.codehaus.groovy:groovy-all:2.4.6' 26 | } 27 | -------------------------------------------------------------------------------- /ftgo-restaurant-service-contracts/src/main/resources/contracts/deliveryservice/messaging/RestaurantCreatedEvent.groovy: -------------------------------------------------------------------------------- 1 | package contracts.deliveryservice.messaging; 2 | 3 | org.springframework.cloud.contract.spec.Contract.make { 4 | label 'restaurantCreatedEvent' 5 | input { 6 | triggeredBy('restaurantCreated()') 7 | } 8 | 9 | outputMessage { 10 | sentTo('net.chrisrichardson.ftgo.restaurantservice.domain.Restaurant') 11 | body('''{"address":{ "street1" : "1 Main Street", "street2" : "Unit 99", "city" : "Oakland", "state" : "CA", "zip" : "94611", }''') 12 | headers { 13 | header('event-aggregate-type', 'net.chrisrichardson.ftgo.restaurantservice.domain.Restaurant') 14 | header('event-type', 'net.chrisrichardson.ftgo.restaurantservice.events.RestaurantCreated') 15 | header('event-aggregate-id', '99') // Matches RestaurantDetailsMother.RESTAURANT_ID 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /ftgo-restaurant-service/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG baseImageVersion 2 | FROM eventuateio/eventuate-examples-docker-images-spring-example-base-image:$baseImageVersion 3 | COPY build/libs/ftgo-restaurant-service.jar service.jar 4 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/RestaurantServiceMain.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice; 2 | 3 | import com.fasterxml.jackson.databind.ObjectMapper; 4 | import io.eventuate.common.json.mapper.JSonMapper; 5 | import io.eventuate.tram.spring.jdbckafka.TramJdbcKafkaConfiguration; 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Import; 10 | import org.springframework.context.annotation.Primary; 11 | 12 | @SpringBootApplication 13 | @Import(TramJdbcKafkaConfiguration.class) 14 | public class RestaurantServiceMain { 15 | 16 | @Bean 17 | @Primary // conflicts with _halObjectMapper 18 | public ObjectMapper objectMapper() { 19 | return JSonMapper.objectMapper; 20 | } 21 | 22 | public static void main(String[] args) { 23 | SpringApplication.run(RestaurantServiceMain.class, args); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/CreateRestaurantRequest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.common.Address; 4 | 5 | public class CreateRestaurantRequest { 6 | 7 | private String name; 8 | private Address address; 9 | private RestaurantMenu menu; 10 | 11 | private CreateRestaurantRequest() { 12 | 13 | } 14 | 15 | public CreateRestaurantRequest(String name, Address address, RestaurantMenu menu) { 16 | this.name = name; 17 | this.address = address; 18 | this.menu = menu; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public RestaurantMenu getMenu() { 30 | return menu; 31 | } 32 | 33 | public void setMenu(RestaurantMenu menu) { 34 | this.menu = menu; 35 | } 36 | 37 | public Address getAddress() { 38 | return address; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/Restaurant.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import javax.persistence.Access; 4 | import javax.persistence.AccessType; 5 | import javax.persistence.Embedded; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.Table; 10 | 11 | @Entity 12 | @Table(name = "restaurants") 13 | @Access(AccessType.FIELD) 14 | public class Restaurant { 15 | 16 | @Id 17 | @GeneratedValue 18 | private Long id; 19 | 20 | private String name; 21 | 22 | @Embedded 23 | private RestaurantMenu menu; 24 | 25 | private Restaurant() { 26 | } 27 | 28 | public void setId(Long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getName() { 33 | return name; 34 | } 35 | 36 | public void setName(String name) { 37 | this.name = name; 38 | } 39 | 40 | 41 | public Restaurant(String name, RestaurantMenu menu) { 42 | this.name = name; 43 | this.menu = menu; 44 | } 45 | 46 | 47 | public Long getId() { 48 | return id; 49 | } 50 | 51 | public RestaurantMenu getMenu() { 52 | return menu; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantDomainEventPublisher.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import io.eventuate.tram.events.aggregates.AbstractAggregateDomainEventPublisher; 4 | import io.eventuate.tram.events.publisher.DomainEventPublisher; 5 | import net.chrisrichardson.ftgo.restaurantservice.events.RestaurantDomainEvent; 6 | 7 | public class RestaurantDomainEventPublisher extends AbstractAggregateDomainEventPublisher { 8 | public RestaurantDomainEventPublisher(DomainEventPublisher eventPublisher) { 9 | super(eventPublisher, Restaurant.class, Restaurant::getId); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantRepository.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | public interface RestaurantRepository extends CrudRepository { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.restaurantservice.events.RestaurantCreated; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | import java.util.Collections; 8 | import java.util.Optional; 9 | 10 | @Transactional 11 | public class RestaurantService { 12 | 13 | 14 | @Autowired 15 | private RestaurantRepository restaurantRepository; 16 | 17 | @Autowired 18 | private RestaurantDomainEventPublisher restaurantDomainEventPublisher; 19 | 20 | public Restaurant create(CreateRestaurantRequest request) { 21 | Restaurant restaurant = new Restaurant(request.getName(), request.getMenu()); 22 | restaurantRepository.save(restaurant); 23 | restaurantDomainEventPublisher.publish(restaurant, Collections.singletonList(new RestaurantCreated(request.getName(), request.getAddress(), request.getMenu()))); 24 | return restaurant; 25 | } 26 | 27 | public Optional findById(long restaurantId) { 28 | return restaurantRepository.findById(restaurantId); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantDomainEvent.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.events; 2 | 3 | import io.eventuate.tram.events.common.DomainEvent; 4 | 5 | public interface RestaurantDomainEvent extends DomainEvent { 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/events/RestaurantMenuRevised.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.events; 2 | 3 | import net.chrisrichardson.ftgo.restaurantservice.domain.RestaurantMenu; 4 | 5 | public class RestaurantMenuRevised implements RestaurantDomainEvent { 6 | 7 | private RestaurantMenu menu; 8 | 9 | public RestaurantMenu getRevisedMenu() { 10 | return menu; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/CreateRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.web; 2 | 3 | public class CreateRestaurantResponse { 4 | private long id; 5 | 6 | public CreateRestaurantResponse() { 7 | } 8 | 9 | public long getId() { 10 | return id; 11 | } 12 | 13 | public void setId(long id) { 14 | this.id = id; 15 | } 16 | 17 | public CreateRestaurantResponse(long id) { 18 | this.id = id; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/web/GetRestaurantResponse.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.web; 2 | 3 | public class GetRestaurantResponse { 4 | private Long id; 5 | 6 | public Long getId() { 7 | return id; 8 | } 9 | 10 | public void setId(Long id) { 11 | this.id = id; 12 | } 13 | 14 | public String getName() { 15 | return name; 16 | } 17 | 18 | public void setName(String name) { 19 | this.name = name; 20 | } 21 | 22 | private String name; 23 | 24 | public GetRestaurantResponse() { 25 | } 26 | 27 | public GetRestaurantResponse(Long id, String name) { 28 | this.id = id; 29 | this.name = name; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=ftgo-restaurant-service 2 | 3 | management.endpoint.health.show-details=always 4 | 5 | spring.jpa.generate-ddl=true 6 | logging.level.org.springframework.orm.jpa=INFO 7 | logging.level.org.hibernate.SQL=DEBUG 8 | logging.level.io.eventuate=DEBUG 9 | logging.level.net.chrisrichardson.ftgo=DEBUG 10 | logging.level.io.eventuate.tram=DEBUG 11 | 12 | spring.datasource.url=jdbc:mysql://${DOCKER_HOST_IP:localhost}/ftgo_restaurant_service 13 | spring.datasource.username=ftgo_restaurant_service_user 14 | spring.datasource.password=ftgo_restaurant_service_password 15 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 16 | 17 | eventuatelocal.kafka.bootstrap.servers=${DOCKER_HOST_IP:localhost}:9092 18 | eventuatelocal.zookeeper.connection.string=${DOCKER_HOST_IP:localhost}:2181 19 | -------------------------------------------------------------------------------- /ftgo-restaurant-service/src/test/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantDomainEventPublisherTest.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.restaurantservice.domain; 2 | 3 | import net.chrisrichardson.ftgo.restaurantservice.RestaurantServiceChannels; 4 | import org.junit.Test; 5 | 6 | import static org.junit.Assert.*; 7 | 8 | public class RestaurantDomainEventPublisherTest { 9 | 10 | @Test 11 | public void verifyRestaurantEventChannel() { 12 | assertEquals(RestaurantServiceChannels.RESTAURANT_EVENT_CHANNEL, new RestaurantDomainEventPublisher(null).getAggregateType().getName()); 13 | } 14 | 15 | 16 | } -------------------------------------------------------------------------------- /ftgo-test-util-json-schema/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "com.github.everit-org.json-schema:org.everit.json.schema:1.12.0" 3 | compile "junit:junit:4.12" 4 | compile "io.eventuate.common:eventuate-common-json-mapper:$eventuateCommonVersion" 5 | 6 | } 7 | -------------------------------------------------------------------------------- /ftgo-test-util/build.gradle: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compile "junit:junit:4.12" 3 | } 4 | -------------------------------------------------------------------------------- /ftgo-test-util/src/main/java/net/chrisrichardson/ftgo/testutil/FtgoTestUtil.java: -------------------------------------------------------------------------------- 1 | package net.chrisrichardson.ftgo.testutil; 2 | 3 | import java.util.Optional; 4 | 5 | import static org.junit.Assert.assertTrue; 6 | 7 | public class FtgoTestUtil { 8 | 9 | public static void assertPresent(Optional value) { 10 | assertTrue(value.isPresent()); 11 | } 12 | 13 | public static String getDockerHostIp() { 14 | return Optional.ofNullable(System.getenv("DOCKER_HOST_IP")).orElse("localhost"); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microservices-patterns/ftgo-application/558dfc53b11d30a5f1d995c0c6d58d5106c28189/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Oct 09 14:55:11 PDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-all.zip 7 | -------------------------------------------------------------------------------- /initialize-dynamodb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | echo preparing dynamodblocal table data 4 | cd dynamodblocal-init 5 | ./create-dynamodb-tables.sh 6 | cd .. 7 | echo data is prepared 8 | -------------------------------------------------------------------------------- /mysql-cli.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | docker run $* \ 4 | --name mysqlterm --rm --network=${PWD##*/}_default \ 5 | mysql/mysql-server:8.0.27-1.2.6-server \ 6 | mysql -hmysql -P3306 -uroot -prootpassword 7 | -------------------------------------------------------------------------------- /mysql/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG EVENTUATE_COMMON_VERSION 2 | FROM eventuateio/eventuate-mysql8:$EVENTUATE_COMMON_VERSION 3 | ARG EVENTUATE_COMMON_VERSION 4 | ARG EVENTUATE_SAGA_VERSION 5 | 6 | COPY compile-schema-per-service.sh /docker-entrypoint-initdb.d/4.compile-schema-per-service.sh 7 | 8 | ADD https://raw.githubusercontent.com/eventuate-foundation/eventuate-common/$EVENTUATE_COMMON_VERSION/mysql/1.initialize-database.sql /docker-entrypoint-initdb.d/template1 9 | ADD https://raw.githubusercontent.com/eventuate-foundation/eventuate-common/$EVENTUATE_COMMON_VERSION/mysql/2.initialize-database.sql /docker-entrypoint-initdb.d/template2 10 | ADD https://raw.githubusercontent.com/eventuate-tram/eventuate-tram-sagas/$EVENTUATE_SAGA_VERSION/mysql/tram-saga-schema.sql /docker-entrypoint-initdb.d/template3 11 | 12 | RUN cat /docker-entrypoint-initdb.d/template? | sed -e 's/eventuate.offset_store/offset_store/' -e /eventuate/d > /docker-entrypoint-initdb.d/template 13 | 14 | RUN touch /docker-entrypoint-initdb.d/5.schema-per-service.sql 15 | RUN chown mysql -R /docker-entrypoint-initdb.d 16 | -------------------------------------------------------------------------------- /mysql/compile-schema-per-service.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | for schema in ftgo_accounting_service ftgo_consumer_service ftgo_order_service ftgo_kitchen_service ftgo_restaurant_service ftgo_delivery_service; 4 | do 5 | user=${schema}_user 6 | password=${schema}_password 7 | cat >> /docker-entrypoint-initdb.d/5.schema-per-service.sql <> /docker-entrypoint-initdb.d/5.schema-per-service.sql 14 | done 15 | -------------------------------------------------------------------------------- /open-swagger-uis.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | 4 | for port in 8081 8084 8082 ; do 5 | open http://${DOCKER_HOST_IP:-localhost}:$port/swagger-ui.html 6 | done 7 | -------------------------------------------------------------------------------- /publish-docker-images.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | DOCKER_COMPOSE_PREFIX="${PWD##*/}_" 4 | 5 | DOCKER_REPO=msapatterns 6 | 7 | $PREFIX docker login -u ${DOCKER_USER_ID?} -p ${DOCKER_PASSWORD?} 8 | 9 | IMAGES="ftgo-consumer-service ftgo-order-service ftgo-kitchen-service ftgo-restaurant-service ftgo-accounting-service ftgo-order-history-service ftgo-api-gateway dynamodblocal-init mysql" 10 | 11 | cd dynamodblocal-init 12 | $PREFIX ./build-docker.sh 13 | $PREFIX docker tag test-dynamodblocal-init:latest ${DOCKER_COMPOSE_PREFIX?}dynamodblocal-init 14 | cd .. 15 | 16 | function tagAndPush() { 17 | LOCAL=$1 18 | REMOTE="$2" 19 | FULL_LOCAL=${DOCKER_COMPOSE_PREFIX?}$LOCAL 20 | FULL_REMOTE="$DOCKER_REPO/$REMOTE:latest" 21 | 22 | $PREFIX docker tag $FULL_LOCAL $FULL_REMOTE 23 | $PREFIX docker push $FULL_REMOTE 24 | } 25 | 26 | for image in $IMAGES ; do 27 | tagAndPush $image $image 28 | done 29 | -------------------------------------------------------------------------------- /run-end-to-end-tests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | ./gradlew :ftgo-end-to-end-tests:cleanTest :ftgo-end-to-end-tests:test 4 | -------------------------------------------------------------------------------- /run-graphql-api-gateway-tests.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | if which npm ; then 4 | echo npm on path. attempting to test GraphQL API gateway 5 | else 6 | echo No Node.JS detected. Skipping test of GraphQL API gateway 7 | exit 0 8 | fi 9 | 10 | cd ftgo-api-gateway-graphql 11 | 12 | if [ ! -d node_modules ] ; then 13 | npm install 14 | fi 15 | 16 | if which tsc ; then 17 | echo tsc installed 18 | else 19 | npm install -g typescript 20 | fi 21 | 22 | npm run unit-test 23 | 24 | docker-compose -f ../docker-compose.yml -f ../docker-compose-api-gateway-graphql.yml up -d --build 25 | 26 | npm run end-to-end-test 27 | -------------------------------------------------------------------------------- /scan-order-history-view.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | export AWS_ACCESS_KEY_ID=id_key AWS_SECRET_ACCESS_KEY=access_key 4 | aws --region ignored --endpoint-url http://${DOCKER_HOST_IP:=localhost}:8000 dynamodb scan --table-name ftgo-order-history 5 | 6 | -------------------------------------------------------------------------------- /set-env.sh: -------------------------------------------------------------------------------- 1 | if [ -z "$DOCKER_HOST_IP" ] ; then 2 | if [ ! -z "$DOCKER_HOST" ] ; then 3 | echo using ${DOCKER_HOST?} 4 | XX=${DOCKER_HOST%\:*} 5 | export DOCKER_HOST_IP=${XX#tcp\:\/\/} 6 | fi 7 | fi 8 | 9 | 10 | if [ -z "$DOCKER_HOST_IP" ] ; then 11 | echo DOCKER_HOST_IP is not set - localhost will be used 12 | else 13 | echo DOCKER_HOST_IP is ${DOCKER_HOST_IP} 14 | fi 15 | 16 | export COMPOSE_HTTP_TIMEOUT=240 17 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | 2 | include "common-swagger" 3 | include "ftgo-test-util" 4 | include "ftgo-test-util-json-schema" 5 | include "ftgo-common" 6 | include "ftgo-common-jpa" 7 | 8 | 9 | include "ftgo-order-service" 10 | 11 | include "ftgo-order-service-api" 12 | include "ftgo-order-service-contracts" 13 | 14 | include "ftgo-kitchen-service-api" 15 | include "ftgo-kitchen-service" 16 | include "ftgo-kitchen-service-contracts" 17 | 18 | include "ftgo-accounting-service-api" 19 | include "ftgo-accounting-service-api-spec" 20 | include "ftgo-accounting-service" 21 | include "ftgo-accounting-service-contracts" 22 | 23 | include "ftgo-consumer-service-api" 24 | include "ftgo-consumer-service-api-spec" 25 | include "ftgo-consumer-service" 26 | include "ftgo-consumer-service-contracts" 27 | 28 | include "ftgo-restaurant-service-api" 29 | include "ftgo-restaurant-service-api-spec" 30 | include "ftgo-restaurant-service-contracts" 31 | include "ftgo-restaurant-service" 32 | 33 | include "ftgo-order-history-service" 34 | 35 | include "ftgo-delivery-service" 36 | include "ftgo-delivery-service-api" 37 | 38 | 39 | include "ftgo-api-gateway" 40 | include "ftgo-end-to-end-tests" 41 | 42 | include "ftgo-restaurant-service-aws-lambda" 43 | -------------------------------------------------------------------------------- /show-swagger-ui-urls.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | ./wait-for-services.sh 4 | 5 | echo Create consumer - open http://${DOCKER_HOST_IP:-localhost}:8081/swagger-ui/index.html 6 | echo Create a restaurant - open http://${DOCKER_HOST_IP:-localhost}:8084/swagger-ui/index.html 7 | echo Create an order - open http://${DOCKER_HOST_IP:-localhost}:8082/swagger-ui/index.html 8 | echo View the order - open http://${DOCKER_HOST_IP:-localhost}:8082/swagger-ui/index.html 9 | echo View the order history - open http://${DOCKER_HOST_IP:-localhost}:8086/swagger-ui/index.html 10 | echo Zipkin distributed tracing - open http://${DOCKER_HOST_IP:-localhost}:9411 11 | 12 | -------------------------------------------------------------------------------- /skaffold.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: skaffold/v1 2 | kind: Config 3 | metadata: 4 | name: ftgo-application 5 | build: 6 | artifacts: 7 | - image: msapatterns/ftgo-consumer-service 8 | context: ftgo-consumer-service 9 | deploy: 10 | kubectl: 11 | manifests: 12 | - deployment/kubernetes/cdc-services/eventuate-local-cdc-service.yml 13 | - deployment/kubernetes/cdc-services/ftgo-tram-cdc-service.yml 14 | - deployment/kubernetes/stateful-services/ftgo-db-secret.yml 15 | - deployment/kubernetes/stateful-services/ftgo-dynamodb-local.yml 16 | - deployment/kubernetes/stateful-services/ftgo-kafka-config.yml 17 | - deployment/kubernetes/stateful-services/ftgo-kafka-deployment.yml 18 | - deployment/kubernetes/stateful-services/ftgo-mysql-deployment.yml 19 | - deployment/kubernetes/stateful-services/ftgo-zookeeper-deployment.yml 20 | - ftgo-consumer-service/src/deployment/kubernetes/ftgo-consumer-service.yml 21 | -------------------------------------------------------------------------------- /start-infrastructure-services.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | docker-compose up -d --build $* mysql cdc-service eventuate-local-cdc-service dynamodblocal 4 | 5 | ./initialize-dynamodb.sh 6 | 7 | 8 | -------------------------------------------------------------------------------- /start-services.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash -e 2 | 3 | docker-compose up -d --build mysql 4 | 5 | ./wait-for-mysql.sh 6 | 7 | docker-compose up -d --build 8 | 9 | echo -n waiting for the services to start... 10 | 11 | ./wait-for-services.sh 12 | -------------------------------------------------------------------------------- /truncate-table.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### from https://gist.github.com/toshke/d972b56c6273639ace5f62361e1ffac1 4 | #### 5 | #### Delete (remove) all items from Aws Dynamo DB table, by specifing table name and primary key 6 | #### 7 | #### Forked from https://gist.github.com/k3karthic/4bc929885eef40dbe010 8 | #### 9 | #### Usage: 10 | #### clean-dynamo-table TABLE_NAME PRIMARY_KEY 11 | #### 12 | 13 | set -e 14 | 15 | TABLE_NAME=$1 16 | KEY_NAME=$2 17 | 18 | # Get id list 19 | aws dynamodb scan --table-name $TABLE_NAME | jq ".Items[].$KEY_NAME.S" > "/tmp/dynamo_${TABLE_NAME}_keys.txt" 20 | 21 | ALL_KEYS=$(cat "/tmp/dynamo_${TABLE_NAME}_keys.txt") 22 | 23 | # Delete from id list 24 | for key in $ALL_KEYS;do 25 | echo "Deleting $key from $TABLE_NAME..." 26 | aws dynamodb delete-item --table-name $TABLE_NAME --key "{ \"$KEY_NAME\": { \"S\": $key }}" 27 | done 28 | 29 | # Remove id list 30 | rm "/tmp/dynamo_${TABLE_NAME}_keys.txt" -------------------------------------------------------------------------------- /wait-for-mysql.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | until (echo select 1 from dual | ./mysql-cli.sh -i > /dev/null) 4 | do 5 | echo sleeping for mysql 6 | sleep 5 7 | done 8 | -------------------------------------------------------------------------------- /wait-for-services.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ./_wait-for-services.sh /actuator/health 8081 8082 8083 8084 8085 8086 8099 4 | --------------------------------------------------------------------------------