From 2af2788bc72842577c46d4bf156d4daf185e901b Mon Sep 17 00:00:00 2001 From: Kenny Bastani Date: Tue, 20 Dec 2016 17:30:24 -0800 Subject: [PATCH] Cleaning up --- .gitmodules | 28 +- {account-parent => account}/README.md | 0 .../account-web/README.md | 0 .../account-web/manifest.yml | 0 .../account-web/pom.xml | 4 +- .../java/demo/AccountServiceApplication.java | 0 .../src/main/java/demo/account/Account.java | 0 .../java/demo/account/AccountCommand.java | 0 .../demo/account/AccountCommandsResource.java | 0 .../java/demo/account/AccountController.java | 0 .../java/demo/account/AccountRepository.java | 0 .../java/demo/account/AccountService.java | 0 .../main/java/demo/account/AccountStatus.java | 0 .../main/java/demo/config/CacheConfig.java | 0 .../src/main/java/demo/config/JpaConfig.java | 0 .../main/java/demo/config/StreamConfig.java | 0 .../main/java/demo/config/WebMvcConfig.java | 0 .../src/main/java/demo/domain/BaseEntity.java | 0 .../main/java/demo/event/AccountEvent.java | 0 .../java/demo/event/AccountEventType.java | 0 .../main/java/demo/event/AccountEvents.java | 0 .../java/demo/event/ConsistencyModel.java | 0 .../main/java/demo/event/EventController.java | 0 .../main/java/demo/event/EventRepository.java | 0 .../main/java/demo/event/EventService.java | 0 .../src/main/resources/application.yml | 0 .../src/main/resources/bootstrap.yml | 0 .../demo/account/AccountControllerTest.java | 0 .../demo/account/AccountServiceTests.java | 0 .../src/test/resources/data-h2.sql | 0 .../account-worker/README.md | 0 .../account-worker/manifest.yml | 0 .../account-worker/pom.xml | 14 +- .../demo/AccountStreamModuleApplication.java | 0 .../src/main/java/demo/account/Account.java | 0 .../main/java/demo/account/AccountStatus.java | 0 .../java/demo/config/AwsLambdaConfig.java | 0 .../java/demo/config/StateMachineConfig.java | 0 .../src/main/java/demo/domain/BaseEntity.java | 0 .../main/java/demo/event/AccountEvent.java | 0 .../java/demo/event/AccountEventStream.java | 0 .../java/demo/event/AccountEventType.java | 0 .../main/java/demo/event/AccountEvents.java | 0 .../main/java/demo/event/EventController.java | 0 .../main/java/demo/event/EventService.java | 0 .../java/demo/function/AccountFunction.java | 0 .../java/demo/function/ActivateAccount.java | 0 .../java/demo/function/ArchiveAccount.java | 0 .../java/demo/function/ConfirmAccount.java | 0 .../java/demo/function/CreateAccount.java | 0 .../java/demo/function/LambdaFunctions.java | 0 .../java/demo/function/SuspendAccount.java | 0 .../java/demo/function/UnarchiveAccount.java | 0 .../java/demo/function/UnsuspendAccount.java | 0 .../java/demo/state/StateMachineService.java | 0 .../src/main/java/demo/util/LambdaUtil.java | 0 .../src/main/resources/application.yml | 0 .../src/main/resources/bootstrap.yml | 0 .../AccountStreamModuleApplicationTests.java | 0 .../functions/account-activated-function | 0 .../functions/account-archived-function | 0 .../functions/account-confirmed-function | 0 .../functions/account-created-function | 0 .../functions/account-suspended-function | 0 .../functions/account-unarchived-function | 0 .../functions/account-unsuspended-function | 0 {account-parent => account}/pom.xml | 6 +- inventory-parent/README.md | 3 - inventory-parent/inventory-web/pom.xml | 39 --- .../demo/InventoryServiceApplication.java | 12 - .../src/main/resources/application.properties | 0 .../InventoryServiceApplicationTests.java | 16 -- inventory-parent/pom.xml | 29 --- invoice-parent/README.md | 3 - invoice-parent/invoice-web/pom.xml | 39 --- .../java/demo/InvoiceServiceApplication.java | 12 - .../src/main/resources/application.properties | 0 .../demo/InvoiceServiceApplicationTests.java | 16 -- invoice-parent/pom.xml | 29 --- order-parent/order-web/pom.xml | 39 --- .../src/main/resources/application.properties | 0 order/README.md | 15 ++ order/order-web/pom.xml | 71 +++++ .../java/demo/OrderServiceApplication.java | 0 .../src/main/java/demo/address/Address.java | 100 +++++++ .../main/java/demo/address/AddressType.java | 6 + .../main/java/demo/config/CacheConfig.java | 46 ++++ .../src/main/java/demo/config/JpaConfig.java | 13 + .../main/java/demo/config/StreamConfig.java | 10 + .../main/java/demo/config/WebMvcConfig.java | 36 +++ .../src/main/java/demo/domain/BaseEntity.java | 48 ++++ .../java/demo/event/ConsistencyModel.java | 6 + .../main/java/demo/event/EventController.java | 39 +++ .../main/java/demo/event/EventRepository.java | 10 + .../main/java/demo/event/EventService.java | 214 +++++++++++++++ .../src/main/java/demo/event/OrderEvent.java | 73 ++++++ .../main/java/demo/event/OrderEventType.java | 15 ++ .../src/main/java/demo/event/OrderEvents.java | 74 ++++++ .../src/main/java/demo/order/LineItem.java | 93 +++++++ .../src/main/java/demo/order/Order.java | 110 ++++++++ .../main/java/demo/order/OrderCommand.java | 6 + .../main/java/demo/order/OrderCommands.java | 12 + .../main/java/demo/order/OrderController.java | 246 ++++++++++++++++++ .../main/java/demo/order/OrderRepository.java | 7 + .../main/java/demo/order/OrderService.java | 168 ++++++++++++ .../src/main/java/demo/order/OrderStatus.java | 9 + .../src/main/resources/application.yml | 17 ++ .../src/main/resources/bootstrap.yml | 4 + .../demo/OrderServiceApplicationTests.java | 0 order/order-worker/pom.xml | 95 +++++++ .../java/demo/OrderWorkerApplication.java | 16 ++ .../src/main/java/demo/address/Address.java | 92 +++++++ .../main/java/demo/address/AddressType.java | 6 + .../java/demo/config/AwsLambdaConfig.java | 25 ++ .../java/demo/config/StateMachineConfig.java | 104 ++++++++ .../src/main/java/demo/domain/BaseEntity.java | 36 +++ .../main/java/demo/event/EventController.java | 28 ++ .../main/java/demo/event/EventService.java | 82 ++++++ .../src/main/java/demo/event/OrderEvent.java | 30 +++ .../java/demo/event/OrderEventStream.java | 31 +++ .../main/java/demo/event/OrderEventType.java | 5 + .../src/main/java/demo/event/OrderEvents.java | 7 + .../java/demo/function/LambdaFunctions.java | 5 + .../java/demo/function/OrderFunction.java | 51 ++++ .../src/main/java/demo/order/LineItem.java | 74 ++++++ .../src/main/java/demo/order/Order.java | 97 +++++++ .../src/main/java/demo/order/OrderStatus.java | 14 + .../java/demo/state/StateMachineService.java | 42 +++ .../src/main/java/demo/util/LambdaUtil.java | 29 +++ .../src/main/resources/application.yml | 24 ++ .../src/main/resources/bootstrap.yml | 4 + .../AccountStreamModuleApplicationTests.java | 6 +- {order-parent => order}/pom.xml | 12 +- pom.xml | 21 +- {user-parent => spring-boot-starters}/pom.xml | 14 +- .../spring-boot-starter-aws-lambda/README.md | 92 +++++++ .../spring-boot-starter-aws-lambda}/pom.xml | 13 +- .../aws/AWSLambdaConfigurerAdapter.java | 11 +- .../amazon/aws/AmazonAutoConfiguration.java | 0 .../java/amazon/aws/AmazonProperties.java | 2 +- .../spring-configuration-metadata.json | 0 .../main/resources/META-INF/spring.factories | 0 .../src/main/resources/application.properties | 0 .../amazon/aws/AmazonConfigurationTest.java | 0 user-parent/README.md | 3 - user-parent/user-web/pom.xml | 39 --- .../java/demo/UserServiceApplication.java | 12 - .../src/main/resources/application.properties | 0 warehouse-parent/README.md | 3 - warehouse-parent/pom.xml | 29 --- warehouse-parent/warehouse-web/pom.xml | 39 --- .../demo/WarehouseServiceApplication.java | 12 - .../src/main/resources/application.properties | 0 .../WarehouseServiceApplicationTests.java | 16 -- 154 files changed, 2507 insertions(+), 451 deletions(-) rename {account-parent => account}/README.md (100%) rename {account-parent => account}/account-web/README.md (100%) rename {account-parent => account}/account-web/manifest.yml (100%) rename {account-parent => account}/account-web/pom.xml (95%) rename {account-parent => account}/account-web/src/main/java/demo/AccountServiceApplication.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/Account.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountCommand.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountCommandsResource.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountController.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountRepository.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountService.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/account/AccountStatus.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/config/CacheConfig.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/config/JpaConfig.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/config/StreamConfig.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/config/WebMvcConfig.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/domain/BaseEntity.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/AccountEvent.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/AccountEventType.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/AccountEvents.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/ConsistencyModel.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/EventController.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/EventRepository.java (100%) rename {account-parent => account}/account-web/src/main/java/demo/event/EventService.java (100%) rename {account-parent => account}/account-web/src/main/resources/application.yml (100%) rename {account-parent => account}/account-web/src/main/resources/bootstrap.yml (100%) rename {account-parent => account}/account-web/src/test/java/demo/account/AccountControllerTest.java (100%) rename {account-parent => account}/account-web/src/test/java/demo/account/AccountServiceTests.java (100%) rename {account-parent => account}/account-web/src/test/resources/data-h2.sql (100%) rename {account-parent => account}/account-worker/README.md (100%) rename {account-parent => account}/account-worker/manifest.yml (100%) rename {account-parent => account}/account-worker/pom.xml (88%) rename {account-parent => account}/account-worker/src/main/java/demo/AccountStreamModuleApplication.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/account/Account.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/account/AccountStatus.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/config/AwsLambdaConfig.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/config/StateMachineConfig.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/domain/BaseEntity.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/AccountEvent.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/AccountEventStream.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/AccountEventType.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/AccountEvents.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/EventController.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/event/EventService.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/AccountFunction.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/ActivateAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/ArchiveAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/ConfirmAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/CreateAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/LambdaFunctions.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/SuspendAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/UnarchiveAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/function/UnsuspendAccount.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/state/StateMachineService.java (100%) rename {account-parent => account}/account-worker/src/main/java/demo/util/LambdaUtil.java (100%) rename {account-parent => account}/account-worker/src/main/resources/application.yml (100%) rename {account-parent => account}/account-worker/src/main/resources/bootstrap.yml (100%) rename {account-parent => account}/account-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java (100%) rename {account-parent => account}/functions/account-activated-function (100%) rename {account-parent => account}/functions/account-archived-function (100%) rename {account-parent => account}/functions/account-confirmed-function (100%) rename {account-parent => account}/functions/account-created-function (100%) rename {account-parent => account}/functions/account-suspended-function (100%) rename {account-parent => account}/functions/account-unarchived-function (100%) rename {account-parent => account}/functions/account-unsuspended-function (100%) rename {account-parent => account}/pom.xml (80%) delete mode 100644 inventory-parent/README.md delete mode 100644 inventory-parent/inventory-web/pom.xml delete mode 100644 inventory-parent/inventory-web/src/main/java/demo/InventoryServiceApplication.java delete mode 100644 inventory-parent/inventory-web/src/main/resources/application.properties delete mode 100644 inventory-parent/inventory-web/src/test/java/demo/InventoryServiceApplicationTests.java delete mode 100644 inventory-parent/pom.xml delete mode 100644 invoice-parent/README.md delete mode 100644 invoice-parent/invoice-web/pom.xml delete mode 100644 invoice-parent/invoice-web/src/main/java/demo/InvoiceServiceApplication.java delete mode 100644 invoice-parent/invoice-web/src/main/resources/application.properties delete mode 100644 invoice-parent/invoice-web/src/test/java/demo/InvoiceServiceApplicationTests.java delete mode 100644 invoice-parent/pom.xml delete mode 100644 order-parent/order-web/pom.xml delete mode 100644 order-parent/order-web/src/main/resources/application.properties create mode 100644 order/README.md create mode 100644 order/order-web/pom.xml rename {order-parent => order}/order-web/src/main/java/demo/OrderServiceApplication.java (100%) create mode 100644 order/order-web/src/main/java/demo/address/Address.java create mode 100644 order/order-web/src/main/java/demo/address/AddressType.java create mode 100644 order/order-web/src/main/java/demo/config/CacheConfig.java create mode 100644 order/order-web/src/main/java/demo/config/JpaConfig.java create mode 100644 order/order-web/src/main/java/demo/config/StreamConfig.java create mode 100644 order/order-web/src/main/java/demo/config/WebMvcConfig.java create mode 100644 order/order-web/src/main/java/demo/domain/BaseEntity.java create mode 100644 order/order-web/src/main/java/demo/event/ConsistencyModel.java create mode 100644 order/order-web/src/main/java/demo/event/EventController.java create mode 100644 order/order-web/src/main/java/demo/event/EventRepository.java create mode 100644 order/order-web/src/main/java/demo/event/EventService.java create mode 100644 order/order-web/src/main/java/demo/event/OrderEvent.java create mode 100644 order/order-web/src/main/java/demo/event/OrderEventType.java create mode 100644 order/order-web/src/main/java/demo/event/OrderEvents.java create mode 100644 order/order-web/src/main/java/demo/order/LineItem.java create mode 100644 order/order-web/src/main/java/demo/order/Order.java create mode 100644 order/order-web/src/main/java/demo/order/OrderCommand.java create mode 100644 order/order-web/src/main/java/demo/order/OrderCommands.java create mode 100644 order/order-web/src/main/java/demo/order/OrderController.java create mode 100644 order/order-web/src/main/java/demo/order/OrderRepository.java create mode 100644 order/order-web/src/main/java/demo/order/OrderService.java create mode 100644 order/order-web/src/main/java/demo/order/OrderStatus.java create mode 100644 order/order-web/src/main/resources/application.yml create mode 100644 order/order-web/src/main/resources/bootstrap.yml rename {order-parent => order}/order-web/src/test/java/demo/OrderServiceApplicationTests.java (100%) create mode 100644 order/order-worker/pom.xml create mode 100644 order/order-worker/src/main/java/demo/OrderWorkerApplication.java create mode 100644 order/order-worker/src/main/java/demo/address/Address.java create mode 100644 order/order-worker/src/main/java/demo/address/AddressType.java create mode 100644 order/order-worker/src/main/java/demo/config/AwsLambdaConfig.java create mode 100644 order/order-worker/src/main/java/demo/config/StateMachineConfig.java create mode 100644 order/order-worker/src/main/java/demo/domain/BaseEntity.java create mode 100644 order/order-worker/src/main/java/demo/event/EventController.java create mode 100644 order/order-worker/src/main/java/demo/event/EventService.java create mode 100644 order/order-worker/src/main/java/demo/event/OrderEvent.java create mode 100644 order/order-worker/src/main/java/demo/event/OrderEventStream.java create mode 100644 order/order-worker/src/main/java/demo/event/OrderEventType.java create mode 100644 order/order-worker/src/main/java/demo/event/OrderEvents.java create mode 100644 order/order-worker/src/main/java/demo/function/LambdaFunctions.java create mode 100644 order/order-worker/src/main/java/demo/function/OrderFunction.java create mode 100644 order/order-worker/src/main/java/demo/order/LineItem.java create mode 100644 order/order-worker/src/main/java/demo/order/Order.java create mode 100644 order/order-worker/src/main/java/demo/order/OrderStatus.java create mode 100644 order/order-worker/src/main/java/demo/state/StateMachineService.java create mode 100644 order/order-worker/src/main/java/demo/util/LambdaUtil.java create mode 100644 order/order-worker/src/main/resources/application.yml create mode 100644 order/order-worker/src/main/resources/bootstrap.yml rename user-parent/user-web/src/test/java/demo/UserServiceApplicationTests.java => order/order-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java (57%) rename {order-parent => order}/pom.xml (75%) rename {user-parent => spring-boot-starters}/pom.xml (70%) create mode 100644 spring-boot-starters/spring-boot-starter-aws-lambda/README.md rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/pom.xml (81%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java (83%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/java/amazon/aws/AmazonAutoConfiguration.java (100%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/java/amazon/aws/AmazonProperties.java (96%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/resources/META-INF/spring-configuration-metadata.json (100%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/resources/META-INF/spring.factories (100%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/main/resources/application.properties (100%) rename {spring-boot-starter-aws-lambda => spring-boot-starters/spring-boot-starter-aws-lambda}/src/test/java/amazon/aws/AmazonConfigurationTest.java (100%) delete mode 100644 user-parent/README.md delete mode 100644 user-parent/user-web/pom.xml delete mode 100644 user-parent/user-web/src/main/java/demo/UserServiceApplication.java delete mode 100644 user-parent/user-web/src/main/resources/application.properties delete mode 100644 warehouse-parent/README.md delete mode 100644 warehouse-parent/pom.xml delete mode 100644 warehouse-parent/warehouse-web/pom.xml delete mode 100644 warehouse-parent/warehouse-web/src/main/java/demo/WarehouseServiceApplication.java delete mode 100644 warehouse-parent/warehouse-web/src/main/resources/application.properties delete mode 100644 warehouse-parent/warehouse-web/src/test/java/demo/WarehouseServiceApplicationTests.java diff --git a/.gitmodules b/.gitmodules index eef4f1a..a1c66d7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,21 +1,21 @@ -[submodule "account-parent/functions/account-created-function"] - path = account-parent/functions/account-created-function +[submodule "account/functions/account-created-function"] + path = account/functions/account-created-function url = https://github.com/event-stream-processing-microservices/account-created-function.git -[submodule "account-parent/functions/account-confirmed-function"] - path = account-parent/functions/account-confirmed-function +[submodule "account/functions/account-confirmed-function"] + path = account/functions/account-confirmed-function url = https://github.com/event-stream-processing-microservices/account-confirmed-function.git -[submodule "account-parent/functions/account-suspended-function"] - path = account-parent/functions/account-suspended-function +[submodule "account/functions/account-suspended-function"] + path = account/functions/account-suspended-function url = https://github.com/event-stream-processing-microservices/account-suspended-function.git -[submodule "account-parent/functions/account-activated-function"] - path = account-parent/functions/account-activated-function +[submodule "account/functions/account-activated-function"] + path = account/functions/account-activated-function url = https://github.com/event-stream-processing-microservices/account-activated-function.git -[submodule "account-parent/functions/account-archived-function"] - path = account-parent/functions/account-archived-function +[submodule "account/functions/account-archived-function"] + path = account/functions/account-archived-function url = https://github.com/event-stream-processing-microservices/account-archived-function.git -[submodule "account-parent/functions/account-unsuspended-function"] - path = account-parent/functions/account-unsuspended-function +[submodule "account/functions/account-unsuspended-function"] + path = account/functions/account-unsuspended-function url = https://github.com/event-stream-processing-microservices/account-unsuspended-function.git -[submodule "account-parent/functions/account-unarchived-function"] - path = account-parent/functions/account-unarchived-function +[submodule "account/functions/account-unarchived-function"] + path = account/functions/account-unarchived-function url = https://github.com/event-stream-processing-microservices/account-unarchived-function.git diff --git a/account-parent/README.md b/account/README.md similarity index 100% rename from account-parent/README.md rename to account/README.md diff --git a/account-parent/account-web/README.md b/account/account-web/README.md similarity index 100% rename from account-parent/account-web/README.md rename to account/account-web/README.md diff --git a/account-parent/account-web/manifest.yml b/account/account-web/manifest.yml similarity index 100% rename from account-parent/account-web/manifest.yml rename to account/account-web/manifest.yml diff --git a/account-parent/account-web/pom.xml b/account/account-web/pom.xml similarity index 95% rename from account-parent/account-web/pom.xml rename to account/account-web/pom.xml index 9883667..fde7703 100644 --- a/account-parent/account-web/pom.xml +++ b/account/account-web/pom.xml @@ -7,11 +7,11 @@ 0.0.1-SNAPSHOT jar - │   │   ├── account-web + account-web org.kbastani - account-parent + account 1.0-SNAPSHOT ../ diff --git a/account-parent/account-web/src/main/java/demo/AccountServiceApplication.java b/account/account-web/src/main/java/demo/AccountServiceApplication.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/AccountServiceApplication.java rename to account/account-web/src/main/java/demo/AccountServiceApplication.java diff --git a/account-parent/account-web/src/main/java/demo/account/Account.java b/account/account-web/src/main/java/demo/account/Account.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/Account.java rename to account/account-web/src/main/java/demo/account/Account.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountCommand.java b/account/account-web/src/main/java/demo/account/AccountCommand.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountCommand.java rename to account/account-web/src/main/java/demo/account/AccountCommand.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountCommandsResource.java b/account/account-web/src/main/java/demo/account/AccountCommandsResource.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountCommandsResource.java rename to account/account-web/src/main/java/demo/account/AccountCommandsResource.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountController.java b/account/account-web/src/main/java/demo/account/AccountController.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountController.java rename to account/account-web/src/main/java/demo/account/AccountController.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountRepository.java b/account/account-web/src/main/java/demo/account/AccountRepository.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountRepository.java rename to account/account-web/src/main/java/demo/account/AccountRepository.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountService.java b/account/account-web/src/main/java/demo/account/AccountService.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountService.java rename to account/account-web/src/main/java/demo/account/AccountService.java diff --git a/account-parent/account-web/src/main/java/demo/account/AccountStatus.java b/account/account-web/src/main/java/demo/account/AccountStatus.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/account/AccountStatus.java rename to account/account-web/src/main/java/demo/account/AccountStatus.java diff --git a/account-parent/account-web/src/main/java/demo/config/CacheConfig.java b/account/account-web/src/main/java/demo/config/CacheConfig.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/config/CacheConfig.java rename to account/account-web/src/main/java/demo/config/CacheConfig.java diff --git a/account-parent/account-web/src/main/java/demo/config/JpaConfig.java b/account/account-web/src/main/java/demo/config/JpaConfig.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/config/JpaConfig.java rename to account/account-web/src/main/java/demo/config/JpaConfig.java diff --git a/account-parent/account-web/src/main/java/demo/config/StreamConfig.java b/account/account-web/src/main/java/demo/config/StreamConfig.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/config/StreamConfig.java rename to account/account-web/src/main/java/demo/config/StreamConfig.java diff --git a/account-parent/account-web/src/main/java/demo/config/WebMvcConfig.java b/account/account-web/src/main/java/demo/config/WebMvcConfig.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/config/WebMvcConfig.java rename to account/account-web/src/main/java/demo/config/WebMvcConfig.java diff --git a/account-parent/account-web/src/main/java/demo/domain/BaseEntity.java b/account/account-web/src/main/java/demo/domain/BaseEntity.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/domain/BaseEntity.java rename to account/account-web/src/main/java/demo/domain/BaseEntity.java diff --git a/account-parent/account-web/src/main/java/demo/event/AccountEvent.java b/account/account-web/src/main/java/demo/event/AccountEvent.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/AccountEvent.java rename to account/account-web/src/main/java/demo/event/AccountEvent.java diff --git a/account-parent/account-web/src/main/java/demo/event/AccountEventType.java b/account/account-web/src/main/java/demo/event/AccountEventType.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/AccountEventType.java rename to account/account-web/src/main/java/demo/event/AccountEventType.java diff --git a/account-parent/account-web/src/main/java/demo/event/AccountEvents.java b/account/account-web/src/main/java/demo/event/AccountEvents.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/AccountEvents.java rename to account/account-web/src/main/java/demo/event/AccountEvents.java diff --git a/account-parent/account-web/src/main/java/demo/event/ConsistencyModel.java b/account/account-web/src/main/java/demo/event/ConsistencyModel.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/ConsistencyModel.java rename to account/account-web/src/main/java/demo/event/ConsistencyModel.java diff --git a/account-parent/account-web/src/main/java/demo/event/EventController.java b/account/account-web/src/main/java/demo/event/EventController.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/EventController.java rename to account/account-web/src/main/java/demo/event/EventController.java diff --git a/account-parent/account-web/src/main/java/demo/event/EventRepository.java b/account/account-web/src/main/java/demo/event/EventRepository.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/EventRepository.java rename to account/account-web/src/main/java/demo/event/EventRepository.java diff --git a/account-parent/account-web/src/main/java/demo/event/EventService.java b/account/account-web/src/main/java/demo/event/EventService.java similarity index 100% rename from account-parent/account-web/src/main/java/demo/event/EventService.java rename to account/account-web/src/main/java/demo/event/EventService.java diff --git a/account-parent/account-web/src/main/resources/application.yml b/account/account-web/src/main/resources/application.yml similarity index 100% rename from account-parent/account-web/src/main/resources/application.yml rename to account/account-web/src/main/resources/application.yml diff --git a/account-parent/account-web/src/main/resources/bootstrap.yml b/account/account-web/src/main/resources/bootstrap.yml similarity index 100% rename from account-parent/account-web/src/main/resources/bootstrap.yml rename to account/account-web/src/main/resources/bootstrap.yml diff --git a/account-parent/account-web/src/test/java/demo/account/AccountControllerTest.java b/account/account-web/src/test/java/demo/account/AccountControllerTest.java similarity index 100% rename from account-parent/account-web/src/test/java/demo/account/AccountControllerTest.java rename to account/account-web/src/test/java/demo/account/AccountControllerTest.java diff --git a/account-parent/account-web/src/test/java/demo/account/AccountServiceTests.java b/account/account-web/src/test/java/demo/account/AccountServiceTests.java similarity index 100% rename from account-parent/account-web/src/test/java/demo/account/AccountServiceTests.java rename to account/account-web/src/test/java/demo/account/AccountServiceTests.java diff --git a/account-parent/account-web/src/test/resources/data-h2.sql b/account/account-web/src/test/resources/data-h2.sql similarity index 100% rename from account-parent/account-web/src/test/resources/data-h2.sql rename to account/account-web/src/test/resources/data-h2.sql diff --git a/account-parent/account-worker/README.md b/account/account-worker/README.md similarity index 100% rename from account-parent/account-worker/README.md rename to account/account-worker/README.md diff --git a/account-parent/account-worker/manifest.yml b/account/account-worker/manifest.yml similarity index 100% rename from account-parent/account-worker/manifest.yml rename to account/account-worker/manifest.yml diff --git a/account-parent/account-worker/pom.xml b/account/account-worker/pom.xml similarity index 88% rename from account-parent/account-worker/pom.xml rename to account/account-worker/pom.xml index 681f166..4e76279 100644 --- a/account-parent/account-worker/pom.xml +++ b/account/account-worker/pom.xml @@ -7,11 +7,11 @@ 0.0.1-SNAPSHOT jar - │   │   └── account-worker + account-worker org.kbastani - account-parent + account 1.0-SNAPSHOT ../ @@ -46,17 +46,17 @@ org.springframework.statemachine spring-statemachine-core - 1.1.1.RELEASE + ${spring-statemachine-core.version} org.kbastani spring-boot-starter-aws-lambda - 1.0-SNAPSHOT + ${spring-boot-starter-aws-lambda.version} com.amazonaws aws-java-sdk-sts - 1.11.67 + ${aws-java-sdk-sts.version} com.amazonaws @@ -66,7 +66,7 @@ com.jayway.jsonpath json-path - 2.2.0 + ${json-path.version} @@ -75,7 +75,7 @@ com.amazonaws aws-java-sdk-bom - 1.11.67 + ${aws-java-sdk-sts.version} pom import diff --git a/account-parent/account-worker/src/main/java/demo/AccountStreamModuleApplication.java b/account/account-worker/src/main/java/demo/AccountStreamModuleApplication.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/AccountStreamModuleApplication.java rename to account/account-worker/src/main/java/demo/AccountStreamModuleApplication.java diff --git a/account-parent/account-worker/src/main/java/demo/account/Account.java b/account/account-worker/src/main/java/demo/account/Account.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/account/Account.java rename to account/account-worker/src/main/java/demo/account/Account.java diff --git a/account-parent/account-worker/src/main/java/demo/account/AccountStatus.java b/account/account-worker/src/main/java/demo/account/AccountStatus.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/account/AccountStatus.java rename to account/account-worker/src/main/java/demo/account/AccountStatus.java diff --git a/account-parent/account-worker/src/main/java/demo/config/AwsLambdaConfig.java b/account/account-worker/src/main/java/demo/config/AwsLambdaConfig.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/config/AwsLambdaConfig.java rename to account/account-worker/src/main/java/demo/config/AwsLambdaConfig.java diff --git a/account-parent/account-worker/src/main/java/demo/config/StateMachineConfig.java b/account/account-worker/src/main/java/demo/config/StateMachineConfig.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/config/StateMachineConfig.java rename to account/account-worker/src/main/java/demo/config/StateMachineConfig.java diff --git a/account-parent/account-worker/src/main/java/demo/domain/BaseEntity.java b/account/account-worker/src/main/java/demo/domain/BaseEntity.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/domain/BaseEntity.java rename to account/account-worker/src/main/java/demo/domain/BaseEntity.java diff --git a/account-parent/account-worker/src/main/java/demo/event/AccountEvent.java b/account/account-worker/src/main/java/demo/event/AccountEvent.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/AccountEvent.java rename to account/account-worker/src/main/java/demo/event/AccountEvent.java diff --git a/account-parent/account-worker/src/main/java/demo/event/AccountEventStream.java b/account/account-worker/src/main/java/demo/event/AccountEventStream.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/AccountEventStream.java rename to account/account-worker/src/main/java/demo/event/AccountEventStream.java diff --git a/account-parent/account-worker/src/main/java/demo/event/AccountEventType.java b/account/account-worker/src/main/java/demo/event/AccountEventType.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/AccountEventType.java rename to account/account-worker/src/main/java/demo/event/AccountEventType.java diff --git a/account-parent/account-worker/src/main/java/demo/event/AccountEvents.java b/account/account-worker/src/main/java/demo/event/AccountEvents.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/AccountEvents.java rename to account/account-worker/src/main/java/demo/event/AccountEvents.java diff --git a/account-parent/account-worker/src/main/java/demo/event/EventController.java b/account/account-worker/src/main/java/demo/event/EventController.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/EventController.java rename to account/account-worker/src/main/java/demo/event/EventController.java diff --git a/account-parent/account-worker/src/main/java/demo/event/EventService.java b/account/account-worker/src/main/java/demo/event/EventService.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/event/EventService.java rename to account/account-worker/src/main/java/demo/event/EventService.java diff --git a/account-parent/account-worker/src/main/java/demo/function/AccountFunction.java b/account/account-worker/src/main/java/demo/function/AccountFunction.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/AccountFunction.java rename to account/account-worker/src/main/java/demo/function/AccountFunction.java diff --git a/account-parent/account-worker/src/main/java/demo/function/ActivateAccount.java b/account/account-worker/src/main/java/demo/function/ActivateAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/ActivateAccount.java rename to account/account-worker/src/main/java/demo/function/ActivateAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/ArchiveAccount.java b/account/account-worker/src/main/java/demo/function/ArchiveAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/ArchiveAccount.java rename to account/account-worker/src/main/java/demo/function/ArchiveAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/ConfirmAccount.java b/account/account-worker/src/main/java/demo/function/ConfirmAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/ConfirmAccount.java rename to account/account-worker/src/main/java/demo/function/ConfirmAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/CreateAccount.java b/account/account-worker/src/main/java/demo/function/CreateAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/CreateAccount.java rename to account/account-worker/src/main/java/demo/function/CreateAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/LambdaFunctions.java b/account/account-worker/src/main/java/demo/function/LambdaFunctions.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/LambdaFunctions.java rename to account/account-worker/src/main/java/demo/function/LambdaFunctions.java diff --git a/account-parent/account-worker/src/main/java/demo/function/SuspendAccount.java b/account/account-worker/src/main/java/demo/function/SuspendAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/SuspendAccount.java rename to account/account-worker/src/main/java/demo/function/SuspendAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/UnarchiveAccount.java b/account/account-worker/src/main/java/demo/function/UnarchiveAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/UnarchiveAccount.java rename to account/account-worker/src/main/java/demo/function/UnarchiveAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/function/UnsuspendAccount.java b/account/account-worker/src/main/java/demo/function/UnsuspendAccount.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/function/UnsuspendAccount.java rename to account/account-worker/src/main/java/demo/function/UnsuspendAccount.java diff --git a/account-parent/account-worker/src/main/java/demo/state/StateMachineService.java b/account/account-worker/src/main/java/demo/state/StateMachineService.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/state/StateMachineService.java rename to account/account-worker/src/main/java/demo/state/StateMachineService.java diff --git a/account-parent/account-worker/src/main/java/demo/util/LambdaUtil.java b/account/account-worker/src/main/java/demo/util/LambdaUtil.java similarity index 100% rename from account-parent/account-worker/src/main/java/demo/util/LambdaUtil.java rename to account/account-worker/src/main/java/demo/util/LambdaUtil.java diff --git a/account-parent/account-worker/src/main/resources/application.yml b/account/account-worker/src/main/resources/application.yml similarity index 100% rename from account-parent/account-worker/src/main/resources/application.yml rename to account/account-worker/src/main/resources/application.yml diff --git a/account-parent/account-worker/src/main/resources/bootstrap.yml b/account/account-worker/src/main/resources/bootstrap.yml similarity index 100% rename from account-parent/account-worker/src/main/resources/bootstrap.yml rename to account/account-worker/src/main/resources/bootstrap.yml diff --git a/account-parent/account-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java b/account/account-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java similarity index 100% rename from account-parent/account-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java rename to account/account-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java diff --git a/account-parent/functions/account-activated-function b/account/functions/account-activated-function similarity index 100% rename from account-parent/functions/account-activated-function rename to account/functions/account-activated-function diff --git a/account-parent/functions/account-archived-function b/account/functions/account-archived-function similarity index 100% rename from account-parent/functions/account-archived-function rename to account/functions/account-archived-function diff --git a/account-parent/functions/account-confirmed-function b/account/functions/account-confirmed-function similarity index 100% rename from account-parent/functions/account-confirmed-function rename to account/functions/account-confirmed-function diff --git a/account-parent/functions/account-created-function b/account/functions/account-created-function similarity index 100% rename from account-parent/functions/account-created-function rename to account/functions/account-created-function diff --git a/account-parent/functions/account-suspended-function b/account/functions/account-suspended-function similarity index 100% rename from account-parent/functions/account-suspended-function rename to account/functions/account-suspended-function diff --git a/account-parent/functions/account-unarchived-function b/account/functions/account-unarchived-function similarity index 100% rename from account-parent/functions/account-unarchived-function rename to account/functions/account-unarchived-function diff --git a/account-parent/functions/account-unsuspended-function b/account/functions/account-unsuspended-function similarity index 100% rename from account-parent/functions/account-unsuspended-function rename to account/functions/account-unsuspended-function diff --git a/account-parent/pom.xml b/account/pom.xml similarity index 80% rename from account-parent/pom.xml rename to account/pom.xml index fc166a2..0932902 100644 --- a/account-parent/pom.xml +++ b/account/pom.xml @@ -4,15 +4,15 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - account-parent + account 1.0-SNAPSHOT pom - │   ├── account-parent + account org.kbastani - event-stream-processing-parent + event-stream-processing-microservices 1.0-SNAPSHOT ../ diff --git a/inventory-parent/README.md b/inventory-parent/README.md deleted file mode 100644 index 08cca30..0000000 --- a/inventory-parent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Inventory Microservice - -This is the parent project that contains the modules of a microservice for the _Inventory_ domain context. \ No newline at end of file diff --git a/inventory-parent/inventory-web/pom.xml b/inventory-parent/inventory-web/pom.xml deleted file mode 100644 index e62df8d..0000000 --- a/inventory-parent/inventory-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - inventory-web - 0.0.1-SNAPSHOT - jar - - │   │   └── inventory-web - - - org.kbastani - inventory-parent - 1.0-SNAPSHOT - ../ - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - diff --git a/inventory-parent/inventory-web/src/main/java/demo/InventoryServiceApplication.java b/inventory-parent/inventory-web/src/main/java/demo/InventoryServiceApplication.java deleted file mode 100644 index 4a22c48..0000000 --- a/inventory-parent/inventory-web/src/main/java/demo/InventoryServiceApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class InventoryServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(InventoryServiceApplication.class, args); - } -} diff --git a/inventory-parent/inventory-web/src/main/resources/application.properties b/inventory-parent/inventory-web/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/inventory-parent/inventory-web/src/test/java/demo/InventoryServiceApplicationTests.java b/inventory-parent/inventory-web/src/test/java/demo/InventoryServiceApplicationTests.java deleted file mode 100644 index c987d67..0000000 --- a/inventory-parent/inventory-web/src/test/java/demo/InventoryServiceApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package demo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class InventoryServiceApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/inventory-parent/pom.xml b/inventory-parent/pom.xml deleted file mode 100644 index d7e0bdb..0000000 --- a/inventory-parent/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - inventory-parent - 1.0-SNAPSHOT - pom - - │   ├── inventory-parent - - - org.kbastani - event-stream-processing-parent - 1.0-SNAPSHOT - ../ - - - - inventory-web - - - - - - - - \ No newline at end of file diff --git a/invoice-parent/README.md b/invoice-parent/README.md deleted file mode 100644 index eee1ac6..0000000 --- a/invoice-parent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Order Microservice - -This is the parent project that contains the modules of a microservice for the _Order_ domain context. \ No newline at end of file diff --git a/invoice-parent/invoice-web/pom.xml b/invoice-parent/invoice-web/pom.xml deleted file mode 100644 index d4e8a30..0000000 --- a/invoice-parent/invoice-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - invoice-web - 0.0.1-SNAPSHOT - jar - - │   │   └── invoice-web - - - org.kbastani - invoice-parent - 1.0-SNAPSHOT - ../ - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - diff --git a/invoice-parent/invoice-web/src/main/java/demo/InvoiceServiceApplication.java b/invoice-parent/invoice-web/src/main/java/demo/InvoiceServiceApplication.java deleted file mode 100644 index 2a2740c..0000000 --- a/invoice-parent/invoice-web/src/main/java/demo/InvoiceServiceApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class InvoiceServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(InvoiceServiceApplication.class, args); - } -} diff --git a/invoice-parent/invoice-web/src/main/resources/application.properties b/invoice-parent/invoice-web/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/invoice-parent/invoice-web/src/test/java/demo/InvoiceServiceApplicationTests.java b/invoice-parent/invoice-web/src/test/java/demo/InvoiceServiceApplicationTests.java deleted file mode 100644 index 4e20da1..0000000 --- a/invoice-parent/invoice-web/src/test/java/demo/InvoiceServiceApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package demo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class InvoiceServiceApplicationTests { - - @Test - public void contextLoads() { - } - -} diff --git a/invoice-parent/pom.xml b/invoice-parent/pom.xml deleted file mode 100644 index 03af861..0000000 --- a/invoice-parent/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - invoice-parent - 1.0-SNAPSHOT - pom - - │   ├── invoice-parent - - - org.kbastani - event-stream-processing-parent - 1.0-SNAPSHOT - ../ - - - - invoice-web - - - - - - - - \ No newline at end of file diff --git a/order-parent/order-web/pom.xml b/order-parent/order-web/pom.xml deleted file mode 100644 index 08bd92e..0000000 --- a/order-parent/order-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - order-web - 0.0.1-SNAPSHOT - jar - - │   │   └── order-web - - - org.kbastani - order-parent - 1.0-SNAPSHOT - ../ - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - diff --git a/order-parent/order-web/src/main/resources/application.properties b/order-parent/order-web/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/order/README.md b/order/README.md new file mode 100644 index 0000000..2cd593f --- /dev/null +++ b/order/README.md @@ -0,0 +1,15 @@ +# Order Microservice + +This is the parent project that contains modules of a microservice deployment for the _Order_ domain context. The two modules contained in this project are separated into separate deployment artifacts, one for synchronous HTTP-based interactions and one for asynchronous AMQP-based messaging. + +## Order Web + +The `order-web` module is a web application that produces a REST API that can be used by consumers to interact with and manage domain objects in the `Order` context. _Domain Events_ can be triggered directly over HTTP, and will also be produced in the response to actions that alter the state of the `Order` object. This web service also provides built-in hypermedia support for looking up the event logs on an aggregate domain object. + +## Order Worker + +The `order-worker` module is a event stream processing application that listens for `Order` domain events as AMQP messages. The domain events that are generated by the `order-web` application are processed in this module. The worker is responsible for durable transaction processing for workflows that are required to coordinate asynchronously with applications residing in other domain contexts. + +## Work-in-progress + +This microservice is unfinished. If you're looking for a more polished and complete reference, please take a look at the _Account_ module in the parent project. diff --git a/order/order-web/pom.xml b/order/order-web/pom.xml new file mode 100644 index 0000000..f169d55 --- /dev/null +++ b/order/order-web/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + + order-web + 0.0.1-SNAPSHOT + jar + + order-web + + + org.kbastani + order + 1.0-SNAPSHOT + ../ + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-redis + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-hateoas + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + org.springframework.boot + spring-boot-starter-integration + + + + com.h2database + h2 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/order-parent/order-web/src/main/java/demo/OrderServiceApplication.java b/order/order-web/src/main/java/demo/OrderServiceApplication.java similarity index 100% rename from order-parent/order-web/src/main/java/demo/OrderServiceApplication.java rename to order/order-web/src/main/java/demo/OrderServiceApplication.java diff --git a/order/order-web/src/main/java/demo/address/Address.java b/order/order-web/src/main/java/demo/address/Address.java new file mode 100644 index 0000000..54d4024 --- /dev/null +++ b/order/order-web/src/main/java/demo/address/Address.java @@ -0,0 +1,100 @@ +package demo.address; + +import javax.persistence.*; +import java.io.Serializable; + +@Entity +public class Address implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String street1, street2, state, city, country; + private Integer zipCode; + + @Enumerated(EnumType.STRING) + private AddressType addressType; + + public Address() { + } + + public Address(String street1, String street2, String state, + String city, String country, Integer zipCode) { + this.street1 = street1; + this.street2 = street2; + this.state = state; + this.city = city; + this.country = country; + this.zipCode = zipCode; + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public Integer getZipCode() { + return zipCode; + } + + public void setZipCode(Integer zipCode) { + this.zipCode = zipCode; + } + + public AddressType getAddressType() { + return addressType; + } + + public void setAddressType(AddressType addressType) { + this.addressType = addressType; + } + + @Override + public String toString() { + return "Address{" + + "street1='" + street1 + '\'' + + ", street2='" + street2 + '\'' + + ", state='" + state + '\'' + + ", city='" + city + '\'' + + ", country='" + country + '\'' + + ", zipCode=" + zipCode + + ", addressType=" + addressType + + '}'; + } +} diff --git a/order/order-web/src/main/java/demo/address/AddressType.java b/order/order-web/src/main/java/demo/address/AddressType.java new file mode 100644 index 0000000..f6ba778 --- /dev/null +++ b/order/order-web/src/main/java/demo/address/AddressType.java @@ -0,0 +1,6 @@ +package demo.address; + +public enum AddressType { + SHIPPING, + BILLING +} diff --git a/order/order-web/src/main/java/demo/config/CacheConfig.java b/order/order-web/src/main/java/demo/config/CacheConfig.java new file mode 100644 index 0000000..91fddaa --- /dev/null +++ b/order/order-web/src/main/java/demo/config/CacheConfig.java @@ -0,0 +1,46 @@ +package demo.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; + +import java.util.Arrays; + +@Configuration +@EnableCaching +public class CacheConfig { + + @Bean + public JedisConnectionFactory redisConnectionFactory( + @Value("${spring.redis.port}") Integer redisPort, + @Value("${spring.redis.host}") String redisHost) { + JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); + + redisConnectionFactory.setHostName(redisHost); + redisConnectionFactory.setPort(redisPort); + + return redisConnectionFactory; + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory cf) { + RedisTemplate redisTemplate = new RedisTemplate(); + redisTemplate.setConnectionFactory(cf); + return redisTemplate; + } + + @Bean + public CacheManager cacheManager(RedisTemplate redisTemplate) { + RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); + cacheManager.setDefaultExpiration(50000); + cacheManager.setCacheNames(Arrays.asList("orders", "order-events")); + cacheManager.setUsePrefix(true); + return cacheManager; + } +} \ No newline at end of file diff --git a/order/order-web/src/main/java/demo/config/JpaConfig.java b/order/order-web/src/main/java/demo/config/JpaConfig.java new file mode 100644 index 0000000..c6c09e0 --- /dev/null +++ b/order/order-web/src/main/java/demo/config/JpaConfig.java @@ -0,0 +1,13 @@ +package demo.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; + +/** + * Enable JPA auditing on an empty configuration class to disable auditing on + * + */ +@Configuration +@EnableJpaAuditing +public class JpaConfig { +} diff --git a/order/order-web/src/main/java/demo/config/StreamConfig.java b/order/order-web/src/main/java/demo/config/StreamConfig.java new file mode 100644 index 0000000..2eaf902 --- /dev/null +++ b/order/order-web/src/main/java/demo/config/StreamConfig.java @@ -0,0 +1,10 @@ +package demo.config; + +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.messaging.Source; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableBinding(Source.class) +public class StreamConfig { +} diff --git a/order/order-web/src/main/java/demo/config/WebMvcConfig.java b/order/order-web/src/main/java/demo/config/WebMvcConfig.java new file mode 100644 index 0000000..9282e23 --- /dev/null +++ b/order/order-web/src/main/java/demo/config/WebMvcConfig.java @@ -0,0 +1,36 @@ +package demo.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import java.util.Collections; +import java.util.List; + +@Configuration +public class WebMvcConfig extends WebMvcConfigurerAdapter { + + private ObjectMapper objectMapper; + + public WebMvcConfig(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public void configureMessageConverters(List> converters) { + final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + converters.add(converter); + } + + @Bean + protected RestTemplate restTemplate(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return new RestTemplate(Collections.singletonList(converter)); + } +} \ No newline at end of file diff --git a/order/order-web/src/main/java/demo/domain/BaseEntity.java b/order/order-web/src/main/java/demo/domain/BaseEntity.java new file mode 100644 index 0000000..fb472ef --- /dev/null +++ b/order/order-web/src/main/java/demo/domain/BaseEntity.java @@ -0,0 +1,48 @@ +package demo.domain; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; +import org.springframework.hateoas.ResourceSupport; + +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; +import java.io.Serializable; + +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public class BaseEntity extends ResourceSupport implements Serializable { + + @CreatedDate + private Long createdAt; + + @LastModifiedDate + private Long lastModified; + + public BaseEntity() { + } + + public Long getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Long createdAt) { + this.createdAt = createdAt; + } + + public Long getLastModified() { + return lastModified; + } + + public void setLastModified(Long lastModified) { + this.lastModified = lastModified; + } + + @Override + public String toString() { + return "BaseEntity{" + + "createdAt=" + createdAt + + ", lastModified=" + lastModified + + '}'; + } +} diff --git a/order/order-web/src/main/java/demo/event/ConsistencyModel.java b/order/order-web/src/main/java/demo/event/ConsistencyModel.java new file mode 100644 index 0000000..8bef081 --- /dev/null +++ b/order/order-web/src/main/java/demo/event/ConsistencyModel.java @@ -0,0 +1,6 @@ +package demo.event; + +public enum ConsistencyModel { + BASE, + ACID +} diff --git a/order/order-web/src/main/java/demo/event/EventController.java b/order/order-web/src/main/java/demo/event/EventController.java new file mode 100644 index 0000000..ffcd8da --- /dev/null +++ b/order/order-web/src/main/java/demo/event/EventController.java @@ -0,0 +1,39 @@ +package demo.event; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + +@RestController +@RequestMapping("/v1") +public class EventController { + + private final EventService eventService; + + public EventController(EventService eventService) { + this.eventService = eventService; + } + + @PostMapping(path = "/events/{id}") + public ResponseEntity createEvent(@RequestBody OrderEvent event, @PathVariable Long id) { + return Optional.ofNullable(eventService.createEvent(id, event, ConsistencyModel.ACID)) + .map(e -> new ResponseEntity<>(e, HttpStatus.CREATED)) + .orElseThrow(() -> new IllegalArgumentException("Event creation failed")); + } + + @PutMapping(path = "/events/{id}") + public ResponseEntity updateEvent(@RequestBody OrderEvent event, @PathVariable Long id) { + return Optional.ofNullable(eventService.updateEvent(id, event)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElseThrow(() -> new IllegalArgumentException("Event update failed")); + } + + @GetMapping(path = "/events/{id}") + public ResponseEntity getEvent(@PathVariable Long id) { + return Optional.ofNullable(eventService.getEvent(id)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); + } +} diff --git a/order/order-web/src/main/java/demo/event/EventRepository.java b/order/order-web/src/main/java/demo/event/EventRepository.java new file mode 100644 index 0000000..a17083d --- /dev/null +++ b/order/order-web/src/main/java/demo/event/EventRepository.java @@ -0,0 +1,10 @@ +package demo.event; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; + +public interface EventRepository extends JpaRepository { + Page findOrderEventsByOrderId(@Param("orderId") Long orderId, Pageable pageable); +} diff --git a/order/order-web/src/main/java/demo/event/EventService.java b/order/order-web/src/main/java/demo/event/EventService.java new file mode 100644 index 0000000..d344a70 --- /dev/null +++ b/order/order-web/src/main/java/demo/event/EventService.java @@ -0,0 +1,214 @@ +package demo.event; + +import demo.order.Order; +import demo.order.OrderController; +import org.apache.log4j.Logger; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.cloud.stream.messaging.Source; +import org.springframework.data.domain.PageRequest; +import org.springframework.hateoas.MediaTypes; +import org.springframework.hateoas.Resource; +import org.springframework.http.RequestEntity; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.client.RestTemplate; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; + +/** + * The {@link EventService} provides transactional service methods for {@link OrderEvent} + * entities of the Order Service. Order domain events are generated with a {@link OrderEventType}, + * and action logs are appended to the {@link OrderEvent}. + * + * @author kbastani + */ +@Service +@CacheConfig(cacheNames = {"order-events"}) +public class EventService { + + private final Logger log = Logger.getLogger(EventService.class); + + private final EventRepository eventRepository; + private final Source orderStreamSource; + private final RestTemplate restTemplate; + + public EventService(EventRepository eventRepository, Source orderStreamSource, RestTemplate restTemplate) { + this.eventRepository = eventRepository; + this.orderStreamSource = orderStreamSource; + this.restTemplate = restTemplate; + } + + /** + * Create a new {@link OrderEvent} and append it to the event log of the referenced {@link Order}. + * After the {@link OrderEvent} has been persisted, send the event to the order stream. Events can + * be raised as a blocking or non-blocking operation depending on the {@link ConsistencyModel}. + * + * @param orderId is the unique identifier for the {@link Order} + * @param event is the {@link OrderEvent} to create + * @param consistencyModel is the desired consistency model for the response + * @return an {@link OrderEvent} that has been appended to the {@link Order}'s event log + */ + public OrderEvent createEvent(Long orderId, OrderEvent event, ConsistencyModel consistencyModel) { + event = createEvent(orderId, event); + return raiseEvent(event, consistencyModel); + } + + /** + * Raise an {@link OrderEvent} that attempts to transition the state of an {@link Order}. + * + * @param event is an {@link OrderEvent} that will be raised + * @param consistencyModel is the consistency model for this request + * @return an {@link OrderEvent} that has been appended to the {@link Order}'s event log + */ + public OrderEvent raiseEvent(OrderEvent event, ConsistencyModel consistencyModel) { + switch (consistencyModel) { + case BASE: + asyncRaiseEvent(event); + break; + case ACID: + event = raiseEvent(event); + break; + } + + return event; + } + + /** + * Raise an asynchronous {@link OrderEvent} by sending an AMQP message to the order stream. Any + * state changes will be applied to the {@link Order} outside of the current HTTP request context. + *

+ * Use this operation when a workflow can be processed asynchronously outside of the current HTTP + * request context. + * + * @param event is an {@link OrderEvent} that will be raised + */ + private void asyncRaiseEvent(OrderEvent event) { + // Append the order event to the stream + orderStreamSource.output() + .send(MessageBuilder + .withPayload(getOrderEventResource(event)) + .build()); + } + + /** + * Raise a synchronous {@link OrderEvent} by sending a HTTP request to the order stream. The response + * is a blocking operation, which ensures that the result of a multi-step workflow will not return until + * the transaction reaches a consistent state. + *

+ * Use this operation when the result of a workflow must be returned within the current HTTP request context. + * + * @param event is an {@link OrderEvent} that will be raised + * @return an {@link OrderEvent} which contains the consistent state of an {@link Order} + */ + private OrderEvent raiseEvent(OrderEvent event) { + try { + // Create a new request entity + RequestEntity> requestEntity = RequestEntity.post( + URI.create("http://localhost:8081/v1/events")) + .contentType(MediaTypes.HAL_JSON) + .body(getOrderEventResource(event), Resource.class); + + // Update the order entity's status + Order result = restTemplate.exchange(requestEntity, Order.class) + .getBody(); + + log.info(result); + event.setOrder(result); + } catch (Exception ex) { + log.error(ex); + } + + return event; + } + + + /** + * Create a new {@link OrderEvent} and publish it to the order stream. + * + * @param event is the {@link OrderEvent} to publish to the order stream + * @return a hypermedia {@link OrderEvent} resource + */ + @CacheEvict(cacheNames = "order-events", key = "#id.toString()") + public OrderEvent createEvent(Long id, OrderEvent event) { + // Save new event + event = addEvent(event); + Assert.notNull(event, "The event could not be appended to the order"); + + return event; + } + + /** + * Get an {@link OrderEvent} with the supplied identifier. + * + * @param id is the unique identifier for the {@link OrderEvent} + * @return an {@link OrderEvent} + */ + public Resource getEvent(Long id) { + return getOrderEventResource(eventRepository.findOne(id)); + } + + /** + * Update an {@link OrderEvent} with the supplied identifier. + * + * @param id is the unique identifier for the {@link OrderEvent} + * @param event is the {@link OrderEvent} to update + * @return the updated {@link OrderEvent} + */ + @CacheEvict(cacheNames = "order-events", key = "#event.order().getOrderId().toString()") + public OrderEvent updateEvent(Long id, OrderEvent event) { + Assert.notNull(id); + Assert.isTrue(event.getId() == null || Objects.equals(id, event.getId())); + + return eventRepository.save(event); + } + + /** + * Get {@link OrderEvents} for the supplied {@link Order} identifier. + * + * @param id is the unique identifier of the {@link Order} + * @return a list of {@link OrderEvent} wrapped in a hypermedia {@link OrderEvents} resource + */ + @Cacheable(cacheNames = "order-events", key = "#id.toString()") + public List getOrderEvents(Long id) { + return eventRepository.findOrderEventsByOrderId(id, + new PageRequest(0, Integer.MAX_VALUE)).getContent(); + } + + /** + * Gets a hypermedia resource for a {@link OrderEvent} entity. + * + * @param event is the {@link OrderEvent} to enrich with hypermedia + * @return a hypermedia resource for the supplied {@link OrderEvent} entity + */ + private Resource getOrderEventResource(OrderEvent event) { + return new Resource(event, Arrays.asList( + linkTo(OrderController.class) + .slash("events") + .slash(event.getEventId()) + .withSelfRel(), + linkTo(OrderController.class) + .slash("orders") + .slash(event.getOrder().getOrderId()) + .withRel("order"))); + } + + /** + * Add a {@link OrderEvent} to an {@link Order} entity. + * + * @param event is the {@link OrderEvent} to append to an {@link Order} entity + * @return the newly appended {@link OrderEvent} entity + */ + @CacheEvict(cacheNames = "order-events", key = "#event.order().getOrderId().toString()") + private OrderEvent addEvent(OrderEvent event) { + event = eventRepository.saveAndFlush(event); + return event; + } +} diff --git a/order/order-web/src/main/java/demo/event/OrderEvent.java b/order/order-web/src/main/java/demo/event/OrderEvent.java new file mode 100644 index 0000000..c494449 --- /dev/null +++ b/order/order-web/src/main/java/demo/event/OrderEvent.java @@ -0,0 +1,73 @@ +package demo.event; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import demo.domain.BaseEntity; +import demo.order.Order; + +import javax.persistence.*; + +/** + * The domain event {@link OrderEvent} tracks the type and state of events as + * applied to the {@link Order} domain object. This event resource can be used + * to event source the aggregate state of {@link Order}. + *

+ * This event resource also provides a transaction log that can be used to append + * actions to the event. + * + * @author kbastani + */ +@Entity +public class OrderEvent extends BaseEntity { + + @Id + @GeneratedValue + private Long id; + + @Enumerated(EnumType.STRING) + private OrderEventType type; + + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JsonIgnore + private Order order; + + public OrderEvent() { + } + + public OrderEvent(OrderEventType type) { + this.type = type; + } + + @JsonIgnore + public Long getEventId() { + return id; + } + + public void setEventId(Long id) { + this.id = id; + } + + public OrderEventType getType() { + return type; + } + + public void setType(OrderEventType type) { + this.type = type; + } + + public Order getOrder() { + return order; + } + + public void setOrder(Order order) { + this.order = order; + } + + @Override + public String toString() { + return "OrderEvent{" + + "id=" + id + + ", type=" + type + + ", order=" + order + + "} " + super.toString(); + } +} diff --git a/order/order-web/src/main/java/demo/event/OrderEventType.java b/order/order-web/src/main/java/demo/event/OrderEventType.java new file mode 100644 index 0000000..85305f2 --- /dev/null +++ b/order/order-web/src/main/java/demo/event/OrderEventType.java @@ -0,0 +1,15 @@ +package demo.event; + +import demo.order.Order; +import demo.order.OrderStatus; + +/** + * The {@link OrderEventType} represents a collection of possible events that describe + * state transitions of {@link OrderStatus} on the {@link Order} aggregate. + * + * @author kbastani + */ +public enum OrderEventType { + // TODO: Implement + ORDER_CREATED +} diff --git a/order/order-web/src/main/java/demo/event/OrderEvents.java b/order/order-web/src/main/java/demo/event/OrderEvents.java new file mode 100644 index 0000000..8eb0356 --- /dev/null +++ b/order/order-web/src/main/java/demo/event/OrderEvents.java @@ -0,0 +1,74 @@ +package demo.event; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import demo.order.Order; +import demo.order.OrderController; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkBuilder; +import org.springframework.hateoas.Resources; + +import java.io.Serializable; +import java.util.List; + +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; + +/** + * The {@link OrderEvents} is a hypermedia collection of {@link OrderEvent} resources. + * + * @author kbastani + */ +public class OrderEvents extends Resources implements Serializable { + + private Long orderId; + + /** + * Create a new {@link OrderEvents} hypermedia resources collection for an {@link Order}. + * + * @param orderId is the unique identifier for the {@link Order} + * @param content is the collection of {@link OrderEvents} attached to the {@link Order} + */ + public OrderEvents(Long orderId, List content) { + this(content); + this.orderId = orderId; + + // Add hypermedia links to resources parent + add(linkTo(OrderController.class) + .slash("orders") + .slash(orderId) + .slash("events") + .withSelfRel(), + linkTo(OrderController.class) + .slash("orders") + .slash(orderId) + .withRel("order")); + + LinkBuilder linkBuilder = linkTo(EventController.class); + + // Add hypermedia links to each item of the collection + content.stream().parallel().forEach(event -> event.add( + linkBuilder.slash("events") + .slash(event.getEventId()) + .withSelfRel() + )); + } + + /** + * Creates a {@link Resources} instance with the given content and {@link Link}s (optional). + * + * @param content must not be {@literal null}. + * @param links the links to be added to the {@link Resources}. + */ + private OrderEvents(Iterable content, Link... links) { + super(content, links); + } + + /** + * Get the {@link Order} identifier that the {@link OrderEvents} apply to. + * + * @return the order identifier + */ + @JsonIgnore + public Long getOrderId() { + return orderId; + } +} diff --git a/order/order-web/src/main/java/demo/order/LineItem.java b/order/order-web/src/main/java/demo/order/LineItem.java new file mode 100644 index 0000000..2d3f2d0 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/LineItem.java @@ -0,0 +1,93 @@ +package demo.order; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import java.io.Serializable; + +@Entity +public class LineItem implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + + private String name, productId; + private Integer quantity; + private Double price, tax; + + public LineItem() { + } + + public LineItem(String name, String productId, Integer quantity, + Double price, Double tax) { + this.name = name; + this.productId = productId; + this.quantity = quantity; + this.price = price; + this.tax = tax; + } + + @JsonIgnore + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Double getTax() { + return tax; + } + + public void setTax(Double tax) { + this.tax = tax; + } + + @Override + public String toString() { + return "LineItem{" + + "name='" + name + '\'' + + ", productId='" + productId + '\'' + + ", quantity=" + quantity + + ", price=" + price + + ", tax=" + tax + + '}'; + } +} \ No newline at end of file diff --git a/order/order-web/src/main/java/demo/order/Order.java b/order/order-web/src/main/java/demo/order/Order.java new file mode 100644 index 0000000..dca0545 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/Order.java @@ -0,0 +1,110 @@ +package demo.order; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import demo.address.Address; +import demo.address.AddressType; +import demo.domain.BaseEntity; +import demo.event.OrderEvent; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; + +@Entity(name = "orders") +public class Order extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + private String accountNumber; + + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private Set events = new HashSet<>(); + + @Enumerated(value = EnumType.STRING) + private OrderStatus status; + + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) + private Set lineItems = new HashSet<>(); + + @OneToOne(cascade = CascadeType.ALL) + private Address shippingAddress; + + public Order() { + this.status = OrderStatus.PURCHASED; + } + + public Order(String accountNumber, Address shippingAddress) { + this(); + this.accountNumber = accountNumber; + this.shippingAddress = shippingAddress; + if (shippingAddress.getAddressType() == null) + this.shippingAddress.setAddressType(AddressType.SHIPPING); + } + + @JsonIgnore + public Long getOrderId() { + return id; + } + + public void setOrderId(Long id) { + this.id = id; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public OrderStatus getStatus() { + return status; + } + + public void setStatus(OrderStatus status) { + this.status = status; + } + + @JsonIgnore + public Set getEvents() { + return events; + } + + public void setEvents(Set events) { + this.events = events; + } + + public Set getLineItems() { + return lineItems; + } + + public void setLineItems(Set lineItems) { + this.lineItems = lineItems; + } + + public Address getShippingAddress() { + return shippingAddress; + } + + public void setShippingAddress(Address shippingAddress) { + this.shippingAddress = shippingAddress; + } + + public void addLineItem(LineItem lineItem) { + lineItems.add(lineItem); + } + + @Override + public String toString() { + return "Order{" + + "id=" + id + + ", accountNumber='" + accountNumber + '\'' + + ", events=" + events + + ", status=" + status + + ", lineItems=" + lineItems + + ", shippingAddress=" + shippingAddress + + "} " + super.toString(); + } +} diff --git a/order/order-web/src/main/java/demo/order/OrderCommand.java b/order/order-web/src/main/java/demo/order/OrderCommand.java new file mode 100644 index 0000000..f938f04 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderCommand.java @@ -0,0 +1,6 @@ +package demo.order; + +public enum OrderCommand { + // TODO: Create commands + TODO +} diff --git a/order/order-web/src/main/java/demo/order/OrderCommands.java b/order/order-web/src/main/java/demo/order/OrderCommands.java new file mode 100644 index 0000000..c491ac1 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderCommands.java @@ -0,0 +1,12 @@ +package demo.order; + +import org.springframework.hateoas.ResourceSupport; + +/** + * A hypermedia resource that describes the collection of commands that + * can be applied to a {@link Order} aggregate. + * + * @author kbastani + */ +public class OrderCommands extends ResourceSupport { +} diff --git a/order/order-web/src/main/java/demo/order/OrderController.java b/order/order-web/src/main/java/demo/order/OrderController.java new file mode 100644 index 0000000..bf4b32d --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderController.java @@ -0,0 +1,246 @@ +package demo.order; + +import demo.event.OrderEvent; +import demo.event.OrderEvents; +import demo.event.EventController; +import demo.event.EventService; +import org.springframework.hateoas.LinkBuilder; +import org.springframework.hateoas.Resource; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.*; + +import java.util.Optional; + +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; + +@RestController +@RequestMapping("/v1") +public class OrderController { + + private final OrderService orderService; + private final EventService eventService; + + public OrderController(OrderService orderService, EventService eventService) { + this.orderService = orderService; + this.eventService = eventService; + } + + @PostMapping(path = "/orders") + public ResponseEntity createOrder(@RequestBody Order order) { + return Optional.ofNullable(createOrderResource(order)) + .map(e -> new ResponseEntity<>(e, HttpStatus.CREATED)) + .orElseThrow(() -> new RuntimeException("Order creation failed")); + } + + @PutMapping(path = "/orders/{id}") + public ResponseEntity updateOrder(@RequestBody Order order, @PathVariable Long id) { + return Optional.ofNullable(updateOrderResource(id, order)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElseThrow(() -> new RuntimeException("Order update failed")); + } + + @GetMapping(path = "/orders/{id}") + public ResponseEntity getOrder(@PathVariable Long id) { + return Optional.ofNullable(getOrderResource(id)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); + } + + @DeleteMapping(path = "/orders/{id}") + public ResponseEntity deleteOrder(@PathVariable Long id) { + return Optional.ofNullable(orderService.deleteOrder(id)) + .map(e -> new ResponseEntity<>(HttpStatus.NO_CONTENT)) + .orElseThrow(() -> new RuntimeException("Order deletion failed")); + } + + @GetMapping(path = "/orders/{id}/events") + public ResponseEntity getOrderEvents(@PathVariable Long id) { + return Optional.of(getOrderEventResources(id)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElseThrow(() -> new RuntimeException("Could not get order events")); + } + + @PostMapping(path = "/orders/{id}/events") + public ResponseEntity createOrder(@PathVariable Long id, @RequestBody OrderEvent event) { + return Optional.ofNullable(appendEventResource(id, event)) + .map(e -> new ResponseEntity<>(e, HttpStatus.CREATED)) + .orElseThrow(() -> new RuntimeException("Append order event failed")); + } + + @GetMapping(path = "/orders/{id}/commands") + public ResponseEntity getOrderCommands(@PathVariable Long id) { + return Optional.ofNullable(getCommandsResource(id)) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElseThrow(() -> new RuntimeException("The order could not be found")); + } + + @GetMapping(path = "/orders/{id}/commands/todo") + public ResponseEntity confirmOrder(@PathVariable Long id) { + return Optional.ofNullable(getOrderResource( + orderService.applyCommand(id, OrderCommand.TODO))) + .map(e -> new ResponseEntity<>(e, HttpStatus.OK)) + .orElseThrow(() -> new RuntimeException("The command could not be applied")); + } + + /** + * Retrieves a hypermedia resource for {@link Order} with the specified identifier. + * + * @param id is the unique identifier for looking up the {@link Order} entity + * @return a hypermedia resource for the fetched {@link Order} + */ + private Resource getOrderResource(Long id) { + Resource orderResource = null; + + // Get the order for the provided id + Order order = orderService.getOrder(id); + + // If the order exists, wrap the hypermedia response + if (order != null) + orderResource = getOrderResource(order); + + + return orderResource; + } + + /** + * Creates a new {@link Order} entity and persists the result to the repository. + * + * @param order is the {@link Order} model used to create a new order + * @return a hypermedia resource for the newly created {@link Order} + */ + private Resource createOrderResource(Order order) { + Assert.notNull(order, "Order body must not be null"); + + // Create the new order + order = orderService.registerOrder(order); + + return getOrderResource(order); + } + + /** + * Update a {@link Order} entity for the provided identifier. + * + * @param id is the unique identifier for the {@link Order} update + * @param order is the entity representation containing any updated {@link Order} fields + * @return a hypermedia resource for the updated {@link Order} + */ + private Resource updateOrderResource(Long id, Order order) { + return getOrderResource(orderService.updateOrder(id, order)); + } + + /** + * Appends an {@link OrderEvent} domain event to the event log of the {@link Order} + * aggregate with the specified orderId. + * + * @param orderId is the unique identifier for the {@link Order} + * @param event is the {@link OrderEvent} that attempts to alter the state of the {@link Order} + * @return a hypermedia resource for the newly appended {@link OrderEvent} + */ + private Resource appendEventResource(Long orderId, OrderEvent event) { + Resource eventResource = null; + + event = orderService.appendEvent(orderId, event); + + if (event != null) { + eventResource = new Resource<>(event, + linkTo(EventController.class) + .slash("events") + .slash(event.getEventId()) + .withSelfRel(), + linkTo(OrderController.class) + .slash("orders") + .slash(orderId) + .withRel("order") + ); + } + + return eventResource; + } + + /** + * Get the {@link OrderCommand} hypermedia resource that lists the available commands that can be applied + * to an {@link Order} entity. + * + * @param id is the {@link Order} identifier to provide command links for + * @return an {@link OrderCommands} with a collection of embedded command links + */ + private OrderCommands getCommandsResource(Long id) { + // Get the order resource for the identifier + Resource orderResource = getOrderResource(id); + + // Create a new order commands hypermedia resource + OrderCommands commandResource = new OrderCommands(); + + // Add order command hypermedia links + if (orderResource != null) { + commandResource.add( + getCommandLinkBuilder(id) + .slash("confirm") + .withRel("confirm"), + getCommandLinkBuilder(id) + .slash("activate") + .withRel("activate"), + getCommandLinkBuilder(id) + .slash("suspend") + .withRel("suspend"), + getCommandLinkBuilder(id) + .slash("archive") + .withRel("archive") + ); + } + + return commandResource; + } + + /** + * Get {@link OrderEvents} for the supplied {@link Order} identifier. + * + * @param id is the unique identifier of the {@link Order} + * @return a list of {@link OrderEvent} wrapped in a hypermedia {@link OrderEvents} resource + */ + private OrderEvents getOrderEventResources(Long id) { + return new OrderEvents(id, eventService.getOrderEvents(id)); + } + + /** + * Generate a {@link LinkBuilder} for generating the {@link OrderCommands}. + * + * @param id is the unique identifier for a {@link Order} + * @return a {@link LinkBuilder} for the {@link OrderCommands} + */ + private LinkBuilder getCommandLinkBuilder(Long id) { + return linkTo(OrderController.class) + .slash("orders") + .slash(id) + .slash("commands"); + } + + /** + * Get a hypermedia enriched {@link Order} entity. + * + * @param order is the {@link Order} to enrich with hypermedia links + * @return is a hypermedia enriched resource for the supplied {@link Order} entity + */ + private Resource getOrderResource(Order order) { + Resource orderResource; + + // Prepare hypermedia response + orderResource = new Resource<>(order, + linkTo(OrderController.class) + .slash("orders") + .slash(order.getOrderId()) + .withSelfRel(), + linkTo(OrderController.class) + .slash("orders") + .slash(order.getOrderId()) + .slash("events") + .withRel("events"), + getCommandLinkBuilder(order.getOrderId()) + .withRel("commands") + ); + + return orderResource; + } +} diff --git a/order/order-web/src/main/java/demo/order/OrderRepository.java b/order/order-web/src/main/java/demo/order/OrderRepository.java new file mode 100644 index 0000000..24baa90 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderRepository.java @@ -0,0 +1,7 @@ +package demo.order; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface OrderRepository extends JpaRepository { + +} diff --git a/order/order-web/src/main/java/demo/order/OrderService.java b/order/order-web/src/main/java/demo/order/OrderService.java new file mode 100644 index 0000000..4e074be --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderService.java @@ -0,0 +1,168 @@ +package demo.order; + +import demo.event.ConsistencyModel; +import demo.event.EventService; +import demo.event.OrderEvent; +import demo.event.OrderEventType; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; + +import java.util.Objects; + +@Service +@CacheConfig(cacheNames = {"orders"}) +public class OrderService { + + private final OrderRepository orderRepository; + private final EventService eventService; + private final CacheManager cacheManager; + + public OrderService(OrderRepository orderRepository, EventService eventService, CacheManager cacheManager) { + this.orderRepository = orderRepository; + this.eventService = eventService; + this.cacheManager = cacheManager; + } + + @CacheEvict(cacheNames = "orders", key = "#order.getOrderId().toString()") + public Order registerOrder(Order order) { + + order = createOrder(order); + + cacheManager.getCache("orders") + .evict(order.getOrderId()); + + // Trigger the order creation event + OrderEvent event = appendEvent(order.getOrderId(), + new OrderEvent(OrderEventType.ORDER_CREATED)); + + // Attach order identifier + event.getOrder().setOrderId(order.getOrderId()); + + // Return the result + return event.getOrder(); + } + + /** + * Create a new {@link Order} entity. + * + * @param order is the {@link Order} to create + * @return the newly created {@link Order} + */ + @CacheEvict(cacheNames = "orders", key = "#order.getOrderId().toString()") + public Order createOrder(Order order) { + + // Save the order to the repository + order = orderRepository.saveAndFlush(order); + + return order; + } + + /** + * Get an {@link Order} entity for the supplied identifier. + * + * @param id is the unique identifier of a {@link Order} entity + * @return an {@link Order} entity + */ + @Cacheable(cacheNames = "orders", key = "#id.toString()") + public Order getOrder(Long id) { + return orderRepository.findOne(id); + } + + /** + * Update an {@link Order} entity with the supplied identifier. + * + * @param id is the unique identifier of the {@link Order} entity + * @param order is the {@link Order} containing updated fields + * @return the updated {@link Order} entity + */ + @CachePut(cacheNames = "orders", key = "#id.toString()") + public Order updateOrder(Long id, Order order) { + Assert.notNull(id, "Order id must be present in the resource URL"); + Assert.notNull(order, "Order request body cannot be null"); + + if (order.getOrderId() != null) { + Assert.isTrue(Objects.equals(id, order.getOrderId()), + "The order id in the request body must match the resource URL"); + } else { + order.setOrderId(id); + } + + Assert.state(orderRepository.exists(id), + "The order with the supplied id does not exist"); + + Order currentOrder = orderRepository.findOne(id); + currentOrder.setAccountNumber(order.getAccountNumber()); + currentOrder.setLineItems(order.getLineItems()); + currentOrder.setShippingAddress(order.getShippingAddress()); + currentOrder.setStatus(order.getStatus()); + + return orderRepository.save(currentOrder); + } + + /** + * Delete the {@link Order} with the supplied identifier. + * + * @param id is the unique identifier for the {@link Order} + */ + @CacheEvict(cacheNames = "orders", key = "#id.toString()") + public Boolean deleteOrder(Long id) { + Assert.state(orderRepository.exists(id), + "The order with the supplied id does not exist"); + this.orderRepository.delete(id); + return true; + } + + /** + * Append a new {@link OrderEvent} to the {@link Order} reference for the supplied identifier. + * + * @param orderId is the unique identifier for the {@link Order} + * @param event is the {@link OrderEvent} to append to the {@link Order} entity + * @return the newly appended {@link OrderEvent} + */ + public OrderEvent appendEvent(Long orderId, OrderEvent event) { + return appendEvent(orderId, event, ConsistencyModel.ACID); + } + + /** + * Append a new {@link OrderEvent} to the {@link Order} reference for the supplied identifier. + * + * @param orderId is the unique identifier for the {@link Order} + * @param event is the {@link OrderEvent} to append to the {@link Order} entity + * @return the newly appended {@link OrderEvent} + */ + public OrderEvent appendEvent(Long orderId, OrderEvent event, ConsistencyModel consistencyModel) { + Order order = getOrder(orderId); + Assert.notNull(order, "The order with the supplied id does not exist"); + event.setOrder(order); + event = eventService.createEvent(orderId, event); + order.getEvents().add(event); + orderRepository.saveAndFlush(order); + eventService.raiseEvent(event, consistencyModel); + return event; + } + + /** + * Apply an {@link OrderCommand} to the {@link Order} with a specified identifier. + * + * @param id is the unique identifier of the {@link Order} + * @param orderCommand is the command to apply to the {@link Order} + * @return a hypermedia resource containing the updated {@link Order} + */ + @CachePut(cacheNames = "orders", key = "#id.toString()") + public Order applyCommand(Long id, OrderCommand orderCommand) { + Order order = getOrder(id); + + Assert.notNull(order, "The order for the supplied id could not be found"); + + OrderStatus status = order.getStatus(); + + // TODO: Implement apply command + + return order; + } +} diff --git a/order/order-web/src/main/java/demo/order/OrderStatus.java b/order/order-web/src/main/java/demo/order/OrderStatus.java new file mode 100644 index 0000000..257cd01 --- /dev/null +++ b/order/order-web/src/main/java/demo/order/OrderStatus.java @@ -0,0 +1,9 @@ +package demo.order; + +public enum OrderStatus { + PURCHASED, + PENDING, + CONFIRMED, + SHIPPED, + DELIVERED +} diff --git a/order/order-web/src/main/resources/application.yml b/order/order-web/src/main/resources/application.yml new file mode 100644 index 0000000..ff1a082 --- /dev/null +++ b/order/order-web/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + profiles: + active: development +--- +spring: + profiles: development + cloud: + stream: + bindings: + output: + destination: order + contentType: 'application/json' + redis: + host: localhost + port: 6379 +server: + port: 8080 \ No newline at end of file diff --git a/order/order-web/src/main/resources/bootstrap.yml b/order/order-web/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..71311e6 --- /dev/null +++ b/order/order-web/src/main/resources/bootstrap.yml @@ -0,0 +1,4 @@ +spring: + application: + name: order-web +--- \ No newline at end of file diff --git a/order-parent/order-web/src/test/java/demo/OrderServiceApplicationTests.java b/order/order-web/src/test/java/demo/OrderServiceApplicationTests.java similarity index 100% rename from order-parent/order-web/src/test/java/demo/OrderServiceApplicationTests.java rename to order/order-web/src/test/java/demo/OrderServiceApplicationTests.java diff --git a/order/order-worker/pom.xml b/order/order-worker/pom.xml new file mode 100644 index 0000000..99973c2 --- /dev/null +++ b/order/order-worker/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + order-worker + 0.0.1-SNAPSHOT + jar + + order-worker + + + org.kbastani + order + 1.0-SNAPSHOT + ../ + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-hateoas + + + org.springframework.cloud + spring-cloud-starter-stream-rabbit + + + org.springframework.boot + spring-boot-starter-integration + + + org.springframework.statemachine + spring-statemachine-core + ${spring-statemachine-core.version} + + + org.kbastani + spring-boot-starter-aws-lambda + ${spring-boot-starter-aws-lambda.version} + + + com.amazonaws + aws-java-sdk-sts + ${aws-java-sdk-sts.version} + + + com.amazonaws + aws-java-sdk-lambda + + + + com.jayway.jsonpath + json-path + ${json-path.version} + + + + + + + com.amazonaws + aws-java-sdk-bom + ${aws-java-sdk-sts.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/order/order-worker/src/main/java/demo/OrderWorkerApplication.java b/order/order-worker/src/main/java/demo/OrderWorkerApplication.java new file mode 100644 index 0000000..f21b5c1 --- /dev/null +++ b/order/order-worker/src/main/java/demo/OrderWorkerApplication.java @@ -0,0 +1,16 @@ +package demo; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.hateoas.config.EnableHypermediaSupport; +import org.springframework.hateoas.config.EnableHypermediaSupport.HypermediaType; + +@SpringBootApplication +@EnableHypermediaSupport(type = {HypermediaType.HAL}) +public class OrderWorkerApplication { + public static void main(String[] args) { + SpringApplication.run(OrderWorkerApplication.class, args); + } +} + + diff --git a/order/order-worker/src/main/java/demo/address/Address.java b/order/order-worker/src/main/java/demo/address/Address.java new file mode 100644 index 0000000..265bd5c --- /dev/null +++ b/order/order-worker/src/main/java/demo/address/Address.java @@ -0,0 +1,92 @@ +package demo.address; + +import java.io.Serializable; + +public class Address implements Serializable { + + private String street1, street2, state, city, country; + private Integer zipCode; + private AddressType addressType; + + public Address() { + } + + public Address(String street1, String street2, String state, + String city, String country, Integer zipCode) { + this.street1 = street1; + this.street2 = street2; + this.state = state; + this.city = city; + this.country = country; + this.zipCode = zipCode; + } + + public String getStreet1() { + return street1; + } + + public void setStreet1(String street1) { + this.street1 = street1; + } + + public String getStreet2() { + return street2; + } + + public void setStreet2(String street2) { + this.street2 = street2; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public Integer getZipCode() { + return zipCode; + } + + public void setZipCode(Integer zipCode) { + this.zipCode = zipCode; + } + + public AddressType getAddressType() { + return addressType; + } + + public void setAddressType(AddressType addressType) { + this.addressType = addressType; + } + + @Override + public String toString() { + return "Address{" + + "street1='" + street1 + '\'' + + ", street2='" + street2 + '\'' + + ", state='" + state + '\'' + + ", city='" + city + '\'' + + ", country='" + country + '\'' + + ", zipCode=" + zipCode + + ", addressType=" + addressType + + '}'; + } +} diff --git a/order/order-worker/src/main/java/demo/address/AddressType.java b/order/order-worker/src/main/java/demo/address/AddressType.java new file mode 100644 index 0000000..f6ba778 --- /dev/null +++ b/order/order-worker/src/main/java/demo/address/AddressType.java @@ -0,0 +1,6 @@ +package demo.address; + +public enum AddressType { + SHIPPING, + BILLING +} diff --git a/order/order-worker/src/main/java/demo/config/AwsLambdaConfig.java b/order/order-worker/src/main/java/demo/config/AwsLambdaConfig.java new file mode 100644 index 0000000..47022a5 --- /dev/null +++ b/order/order-worker/src/main/java/demo/config/AwsLambdaConfig.java @@ -0,0 +1,25 @@ +package demo.config; + +import amazon.aws.AWSLambdaConfigurerAdapter; +import com.fasterxml.jackson.databind.ObjectMapper; +import demo.function.LambdaFunctions; +import demo.util.LambdaUtil; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; + +@Configuration +@Profile("cloud") +public class AwsLambdaConfig { + + @Bean + public LambdaFunctions lambdaInvoker(AWSLambdaConfigurerAdapter configurerAdapter) { + return configurerAdapter + .getFunctionInstance(LambdaFunctions.class); + } + + @Bean + public LambdaUtil lambdaUtil(ObjectMapper objectMapper) { + return new LambdaUtil(objectMapper); + } +} diff --git a/order/order-worker/src/main/java/demo/config/StateMachineConfig.java b/order/order-worker/src/main/java/demo/config/StateMachineConfig.java new file mode 100644 index 0000000..b2abd4f --- /dev/null +++ b/order/order-worker/src/main/java/demo/config/StateMachineConfig.java @@ -0,0 +1,104 @@ +package demo.config; + +import demo.event.OrderEvent; +import demo.event.OrderEventType; +import demo.function.OrderFunction; +import demo.order.Order; +import demo.order.OrderStatus; +import org.apache.log4j.Logger; +import org.springframework.context.annotation.Configuration; +import org.springframework.statemachine.StateContext; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.action.Action; +import org.springframework.statemachine.config.EnableStateMachineFactory; +import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter; +import org.springframework.statemachine.config.builders.StateMachineStateConfigurer; +import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer; + +import java.util.EnumSet; + +/** + * A configuration adapter for describing a {@link StateMachine} factory that maps actions to functional + * expressions. Actions are executed during transitions between a source state and a target state. + *

+ * A state machine provides a robust declarative language for describing the state of an {@link Order} + * resource given a sequence of ordered {@link demo.event.OrderEvents}. When an event is received + * in {@link demo.event.OrderEventStream}, an in-memory state machine is fully replicated given the + * {@link demo.event.OrderEvents} attached to an {@link Order} resource. + * + * @author kbastani + */ +@Configuration +@EnableStateMachineFactory +public class StateMachineConfig extends EnumStateMachineConfigurerAdapter { + + final private Logger log = Logger.getLogger(StateMachineConfig.class); + + /** + * Configures the initial conditions of a new in-memory {@link StateMachine} for {@link Order}. + * + * @param states is the {@link StateMachineStateConfigurer} used to describe the initial condition + */ + @Override + public void configure(StateMachineStateConfigurer states) { + try { + // Describe the initial condition of the order state machine + states.withStates() + .initial(OrderStatus.PENDING) + .states(EnumSet.allOf(OrderStatus.class)); + } catch (Exception e) { + throw new RuntimeException("State machine configuration failed", e); + } + } + + /** + * Configures the {@link StateMachine} that describes how {@link OrderEventType} drives the state + * of an {@link Order}. Events are applied as transitions from a source {@link OrderStatus} to + * a target {@link OrderStatus}. An {@link Action} is attached to each transition, which maps to a + * function that is executed in the context of an {@link OrderEvent}. + * + * @param transitions is the {@link StateMachineTransitionConfigurer} used to describe state transitions + */ + @Override + public void configure(StateMachineTransitionConfigurer transitions) { + try { + // Describe state machine transitions for orders + // TODO: Configure state machine + } catch (Exception e) { + throw new RuntimeException("Could not configure state machine transitions", e); + } + } + + /** + * Functions are mapped to actions that are triggered during the replication of a state machine. Functions + * should only be executed after the state machine has completed replication. This method checks the state + * context of the machine for an {@link OrderEvent}, which signals that the state machine is finished + * replication. + *

+ * The {@link OrderFunction} argument is only applied if an {@link OrderEvent} is provided as a + * message header in the {@link StateContext}. + * + * @param context is the state machine context that may include an {@link OrderEvent} + * @param orderFunction is the order function to apply after the state machine has completed replication + * @return an {@link OrderEvent} only if this event has not yet been processed, otherwise returns null + */ + private OrderEvent applyEvent(StateContext context, + OrderFunction orderFunction) { + OrderEvent orderEvent = null; + + // Log out the progress of the state machine replication + log.info("Replicate event: " + context.getMessage().getPayload()); + + // The machine is finished replicating when an OrderEvent is found in the message header + if (context.getMessageHeader("event") != null) { + orderEvent = (OrderEvent) context.getMessageHeader("event"); + log.info("State machine replicated: " + orderEvent.getType()); + + // Apply the provided function to the OrderEvent + orderFunction.apply(orderEvent); + } + + return orderEvent; + } +} + diff --git a/order/order-worker/src/main/java/demo/domain/BaseEntity.java b/order/order-worker/src/main/java/demo/domain/BaseEntity.java new file mode 100644 index 0000000..586dbb4 --- /dev/null +++ b/order/order-worker/src/main/java/demo/domain/BaseEntity.java @@ -0,0 +1,36 @@ +package demo.domain; + +import org.springframework.hateoas.ResourceSupport; + +public class BaseEntity extends ResourceSupport { + + private Long createdAt; + private Long lastModified; + + public BaseEntity() { + } + + public Long getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(Long createdAt) { + this.createdAt = createdAt; + } + + public Long getLastModified() { + return lastModified; + } + + public void setLastModified(Long lastModified) { + this.lastModified = lastModified; + } + + @Override + public String toString() { + return "BaseEntity{" + + "createdAt=" + createdAt + + ", lastModified=" + lastModified + + "} " + super.toString(); + } +} diff --git a/order/order-worker/src/main/java/demo/event/EventController.java b/order/order-worker/src/main/java/demo/event/EventController.java new file mode 100644 index 0000000..1bb5607 --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/EventController.java @@ -0,0 +1,28 @@ +package demo.event; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Optional; + +@RestController +@RequestMapping("/v1") +public class EventController { + + private EventService eventService; + + public EventController(EventService eventService) { + this.eventService = eventService; + } + + @PostMapping(path = "/events") + public ResponseEntity handleEvent(@RequestBody OrderEvent event) { + return Optional.ofNullable(eventService.apply(event)) + .map(e -> new ResponseEntity<>(e, HttpStatus.CREATED)) + .orElseThrow(() -> new RuntimeException("Apply event failed")); + } +} diff --git a/order/order-worker/src/main/java/demo/event/EventService.java b/order/order-worker/src/main/java/demo/event/EventService.java new file mode 100644 index 0000000..dc7ee97 --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/EventService.java @@ -0,0 +1,82 @@ +package demo.event; + +import demo.order.Order; +import demo.order.OrderStatus; +import demo.state.StateMachineService; +import org.apache.log4j.Logger; +import org.springframework.hateoas.MediaTypes; +import org.springframework.hateoas.client.Traverson; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.MessageBuilder; +import org.springframework.statemachine.StateMachine; +import org.springframework.stereotype.Service; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +@Service +public class EventService { + + final private Logger log = Logger.getLogger(EventService.class); + final private StateMachineService stateMachineService; + + public EventService(StateMachineService stateMachineService) { + this.stateMachineService = stateMachineService; + } + + public Order apply(OrderEvent orderEvent) { + + Order result; + + log.info("Order event received: " + orderEvent.getLink("self").getHref()); + + // Generate a state machine for computing the state of the order resource + StateMachine stateMachine = + stateMachineService.getStateMachine(); + + // Follow the hypermedia link to fetch the attached order + Traverson traverson = new Traverson( + URI.create(orderEvent.getLink("order").getHref()), + MediaTypes.HAL_JSON + ); + + // Get the event log for the attached order resource + OrderEvents events = traverson.follow("events") + .toEntity(OrderEvents.class) + .getBody(); + + // Prepare order event message headers + Map headerMap = new HashMap<>(); + headerMap.put("event", orderEvent); + + // Replicate the current state of the order resource + events.getContent() + .stream() + .sorted((a1, a2) -> a1.getCreatedAt().compareTo(a2.getCreatedAt())) + .forEach(e -> { + MessageHeaders headers = new MessageHeaders(null); + + // Check to see if this is the current event + if (e.getLink("self").equals(orderEvent.getLink("self"))) { + headers = new MessageHeaders(headerMap); + } + + // Send the event to the state machine + stateMachine.sendEvent(MessageBuilder.createMessage(e.getType(), headers)); + }); + + + // Get result + Map context = stateMachine.getExtendedState() + .getVariables(); + + // Get the order result + result = (Order) context.getOrDefault("order", null); + + // Destroy the state machine + stateMachine.stop(); + + return result; + } +} diff --git a/order/order-worker/src/main/java/demo/event/OrderEvent.java b/order/order-worker/src/main/java/demo/event/OrderEvent.java new file mode 100644 index 0000000..605803e --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/OrderEvent.java @@ -0,0 +1,30 @@ +package demo.event; + +import demo.domain.BaseEntity; + +public class OrderEvent extends BaseEntity { + + private OrderEventType type; + + public OrderEvent() { + } + + public OrderEvent(OrderEventType type) { + this.type = type; + } + + public OrderEventType getType() { + return type; + } + + public void setType(OrderEventType type) { + this.type = type; + } + + @Override + public String toString() { + return "AccountEvent{" + + "type=" + type + + "} " + super.toString(); + } +} diff --git a/order/order-worker/src/main/java/demo/event/OrderEventStream.java b/order/order-worker/src/main/java/demo/event/OrderEventStream.java new file mode 100644 index 0000000..cd2b471 --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/OrderEventStream.java @@ -0,0 +1,31 @@ +package demo.event; + +import demo.order.Order; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.cloud.stream.annotation.EnableBinding; +import org.springframework.cloud.stream.annotation.StreamListener; +import org.springframework.cloud.stream.messaging.Sink; +import org.springframework.context.annotation.Profile; + +/** + * The {@link OrderEventStream} monitors for a variety of {@link OrderEvent} domain + * events for an {@link Order}. + * + * @author kbastani + */ +@EnableAutoConfiguration +@EnableBinding(Sink.class) +@Profile({ "cloud", "development" }) +public class OrderEventStream { + + private EventService eventService; + + public OrderEventStream(EventService eventService) { + this.eventService = eventService; + } + + @StreamListener(Sink.INPUT) + public void streamListerner(OrderEvent orderEvent) { + eventService.apply(orderEvent); + } +} diff --git a/order/order-worker/src/main/java/demo/event/OrderEventType.java b/order/order-worker/src/main/java/demo/event/OrderEventType.java new file mode 100644 index 0000000..0984b05 --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/OrderEventType.java @@ -0,0 +1,5 @@ +package demo.event; + +public enum OrderEventType { + // TODO: Add event types +} diff --git a/order/order-worker/src/main/java/demo/event/OrderEvents.java b/order/order-worker/src/main/java/demo/event/OrderEvents.java new file mode 100644 index 0000000..f67c72a --- /dev/null +++ b/order/order-worker/src/main/java/demo/event/OrderEvents.java @@ -0,0 +1,7 @@ +package demo.event; + +import org.springframework.hateoas.Resources; + +public class OrderEvents extends Resources { + +} diff --git a/order/order-worker/src/main/java/demo/function/LambdaFunctions.java b/order/order-worker/src/main/java/demo/function/LambdaFunctions.java new file mode 100644 index 0000000..e35fc2f --- /dev/null +++ b/order/order-worker/src/main/java/demo/function/LambdaFunctions.java @@ -0,0 +1,5 @@ +package demo.function; + +public interface LambdaFunctions { + // TODO: Implement +} diff --git a/order/order-worker/src/main/java/demo/function/OrderFunction.java b/order/order-worker/src/main/java/demo/function/OrderFunction.java new file mode 100644 index 0000000..cb34c50 --- /dev/null +++ b/order/order-worker/src/main/java/demo/function/OrderFunction.java @@ -0,0 +1,51 @@ +package demo.function; + +import demo.order.Order; +import demo.order.OrderStatus; +import demo.event.OrderEvent; +import demo.event.OrderEventType; +import org.apache.log4j.Logger; +import org.springframework.statemachine.StateContext; + +import java.util.function.Function; + +/** + * The {@link OrderFunction} is an abstraction used to map actions that are triggered by + * state transitions on a {@link demo.order.Order} resource on to a function. Mapped functions + * can take multiple forms and reside either remotely or locally on the classpath of this application. + * + * @author kbastani + */ +public abstract class OrderFunction { + + final private Logger log = Logger.getLogger(OrderFunction.class); + final protected StateContext context; + final protected Function lambda; + + /** + * Create a new instance of a class that extends {@link OrderFunction}, supplying + * a state context and a lambda function used to apply {@link OrderEvent} to a provided + * action. + * + * @param context is the {@link StateContext} for a replicated state machine + * @param lambda is the lambda function describing an action that consumes an {@link OrderEvent} + */ + public OrderFunction(StateContext context, + Function lambda) { + this.context = context; + this.lambda = lambda; + } + + /** + * Apply an {@link OrderEvent} to the lambda function that was provided through the + * constructor of this {@link OrderFunction}. + * + * @param event is the {@link OrderEvent} to apply to the lambda function + */ + public Order apply(OrderEvent event) { + // Execute the lambda function + Order result = lambda.apply(event); + context.getExtendedState().getVariables().put("order", result); + return result; + } +} diff --git a/order/order-worker/src/main/java/demo/order/LineItem.java b/order/order-worker/src/main/java/demo/order/LineItem.java new file mode 100644 index 0000000..f26f9db --- /dev/null +++ b/order/order-worker/src/main/java/demo/order/LineItem.java @@ -0,0 +1,74 @@ +package demo.order; + +/** + * A simple domain class for the {@link LineItem} concept in the order context. + * + * @author Kenny Bastani + * @author Josh Long + */ +public class LineItem { + + private String name, productId; + private Integer quantity; + private Double price, tax; + + public LineItem(String name, String productId, Integer quantity, + Double price, Double tax) { + this.name = name; + this.productId = productId; + this.quantity = quantity; + this.price = price; + this.tax = tax; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getProductId() { + return productId; + } + + public void setProductId(String productId) { + this.productId = productId; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public Double getPrice() { + return price; + } + + public void setPrice(Double price) { + this.price = price; + } + + public Double getTax() { + return tax; + } + + public void setTax(Double tax) { + this.tax = tax; + } + + @Override + public String toString() { + return "LineItem{" + + "name='" + name + '\'' + + ", productId='" + productId + '\'' + + ", quantity=" + quantity + + ", price=" + price + + ", tax=" + tax + + '}'; + } +} diff --git a/order/order-worker/src/main/java/demo/order/Order.java b/order/order-worker/src/main/java/demo/order/Order.java new file mode 100644 index 0000000..d493f19 --- /dev/null +++ b/order/order-worker/src/main/java/demo/order/Order.java @@ -0,0 +1,97 @@ +package demo.order; + +import demo.address.Address; +import demo.address.AddressType; +import demo.domain.BaseEntity; +import demo.event.OrderEvent; + +import java.util.HashSet; +import java.util.Set; + +public class Order extends BaseEntity { + + private Long orderId; + private String accountNumber; + + private OrderStatus status; + + private Set events = new HashSet<>(); + + private Set lineItems = new HashSet<>(); + + private Address shippingAddress; + + public Order() { + } + + public Order(String accountNumber, Address shippingAddress) { + this(); + this.accountNumber = accountNumber; + this.shippingAddress = shippingAddress; + if (shippingAddress.getAddressType() == null) + this.shippingAddress.setAddressType(AddressType.SHIPPING); + } + + public Long getOrderId() { + return orderId; + } + + public void setOrderId(Long id) { + this.orderId = orderId; + } + + public String getAccountNumber() { + return accountNumber; + } + + public void setAccountNumber(String accountNumber) { + this.accountNumber = accountNumber; + } + + public OrderStatus getStatus() { + return status; + } + + public void setStatus(OrderStatus status) { + this.status = status; + } + + public Set getEvents() { + return events; + } + + public void setEvents(Set events) { + this.events = events; + } + + public Set getLineItems() { + return lineItems; + } + + public void setLineItems(Set lineItems) { + this.lineItems = lineItems; + } + + public Address getShippingAddress() { + return shippingAddress; + } + + public void setShippingAddress(Address shippingAddress) { + this.shippingAddress = shippingAddress; + } + + public void addLineItem(LineItem lineItem) { + lineItems.add(lineItem); + } + + @Override + public String toString() { + return "Order{" + + "orderId='" + orderId + '\'' + + ", accountNumber='" + accountNumber + '\'' + + ", status=" + status + + ", lineItems=" + lineItems + + ", shippingAddress=" + shippingAddress + + "} " + super.toString(); + } +} diff --git a/order/order-worker/src/main/java/demo/order/OrderStatus.java b/order/order-worker/src/main/java/demo/order/OrderStatus.java new file mode 100644 index 0000000..7ffb9bb --- /dev/null +++ b/order/order-worker/src/main/java/demo/order/OrderStatus.java @@ -0,0 +1,14 @@ +package demo.order; + +/** + * Describes the state of an {@link Order}. + * + * @author Kenny Bastani + * @author Josh Long + */ +public enum OrderStatus { + PENDING, + CONFIRMED, + SHIPPED, + DELIVERED +} diff --git a/order/order-worker/src/main/java/demo/state/StateMachineService.java b/order/order-worker/src/main/java/demo/state/StateMachineService.java new file mode 100644 index 0000000..b3327dc --- /dev/null +++ b/order/order-worker/src/main/java/demo/state/StateMachineService.java @@ -0,0 +1,42 @@ +package demo.state; + +import demo.order.OrderStatus; +import demo.event.OrderEventType; +import org.springframework.statemachine.StateMachine; +import org.springframework.statemachine.config.StateMachineFactory; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +/** + * The {@link StateMachineService} provides factory access to get new state machines for + * replicating the state of an {@link demo.order.Order} from {@link demo.event.OrderEvents}. + * + * @author kbastani + */ +@Service +public class StateMachineService { + + private final StateMachineFactory factory; + + public StateMachineService(StateMachineFactory factory) { + this.factory = factory; + } + + /** + * Create a new state machine that is initially configured and ready for replicating + * the state of an {@link demo.order.Order} from a sequence of {@link demo.event.OrderEvent}. + * + * @return a new instance of {@link StateMachine} + */ + public StateMachine getStateMachine() { + // Create a new state machine in its initial state + StateMachine stateMachine = + factory.getStateMachine(UUID.randomUUID().toString()); + + // Start the new state machine + stateMachine.start(); + + return stateMachine; + } +} diff --git a/order/order-worker/src/main/java/demo/util/LambdaUtil.java b/order/order-worker/src/main/java/demo/util/LambdaUtil.java new file mode 100644 index 0000000..bd282f4 --- /dev/null +++ b/order/order-worker/src/main/java/demo/util/LambdaUtil.java @@ -0,0 +1,29 @@ +package demo.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.HashMap; + +@Component +public class LambdaUtil { + + private ObjectMapper objectMapper; + + public LambdaUtil(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + public HashMap objectToMap(Object object) { + HashMap result = null; + + try { + result = objectMapper.readValue(objectMapper.writeValueAsString(object), HashMap.class); + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } +} diff --git a/order/order-worker/src/main/resources/application.yml b/order/order-worker/src/main/resources/application.yml new file mode 100644 index 0000000..37237e4 --- /dev/null +++ b/order/order-worker/src/main/resources/application.yml @@ -0,0 +1,24 @@ +spring: + profiles: + active: development +--- +spring: + profiles: development + cloud: + stream: + bindings: + input: + destination: account + group: account-group + contentType: 'application/json' + consumer: + durableSubscription: true +server: + port: 8081 +amazon: + aws: + access-key-id: replace + access-key-secret: replace +--- +spring: + profiles: test \ No newline at end of file diff --git a/order/order-worker/src/main/resources/bootstrap.yml b/order/order-worker/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..7983fac --- /dev/null +++ b/order/order-worker/src/main/resources/bootstrap.yml @@ -0,0 +1,4 @@ +spring: + application: + name: account-worker +--- \ No newline at end of file diff --git a/user-parent/user-web/src/test/java/demo/UserServiceApplicationTests.java b/order/order-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java similarity index 57% rename from user-parent/user-web/src/test/java/demo/UserServiceApplicationTests.java rename to order/order-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java index 3fb79f3..7d74e07 100644 --- a/user-parent/user-web/src/test/java/demo/UserServiceApplicationTests.java +++ b/order/order-worker/src/test/java/demo/AccountStreamModuleApplicationTests.java @@ -3,11 +3,13 @@ package demo; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) -@SpringBootTest -public class UserServiceApplicationTests { +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) +@ActiveProfiles("test") +public class AccountStreamModuleApplicationTests { @Test public void contextLoads() { diff --git a/order-parent/pom.xml b/order/pom.xml similarity index 75% rename from order-parent/pom.xml rename to order/pom.xml index 566fe7c..ea51010 100644 --- a/order-parent/pom.xml +++ b/order/pom.xml @@ -4,26 +4,22 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - order-parent + order 1.0-SNAPSHOT pom - │   ├── order-parent + order org.kbastani - event-stream-processing-parent + event-stream-processing-microservices 1.0-SNAPSHOT ../ order-web + order-worker - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index a9e2d9d..5f1af4f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,11 @@ 4.0.0 org.kbastani - event-stream-processing-parent + event-stream-processing-microservices 1.0-SNAPSHOT pom - ├── event-stream-processing-parent + event-stream-processing-parent org.springframework.boot @@ -18,14 +18,17 @@ + + 1.1.1.RELEASE + 1.0-SNAPSHOT + 1.11.67 + 2.2.0 + + - account-parent - inventory-parent - invoice-parent - order-parent - user-parent - warehouse-parent - spring-boot-starter-aws-lambda + spring-boot-starters + account + order diff --git a/user-parent/pom.xml b/spring-boot-starters/pom.xml similarity index 70% rename from user-parent/pom.xml rename to spring-boot-starters/pom.xml index e8b13b7..4b21d6a 100644 --- a/user-parent/pom.xml +++ b/spring-boot-starters/pom.xml @@ -4,26 +4,20 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - user-parent + spring-boot-starters 1.0-SNAPSHOT pom - │   ├── user-parent + spring-boot-starters org.kbastani - event-stream-processing-parent + event-stream-processing-microservices 1.0-SNAPSHOT ../ - user-web + spring-boot-starter-aws-lambda - - - - - - \ No newline at end of file diff --git a/spring-boot-starters/spring-boot-starter-aws-lambda/README.md b/spring-boot-starters/spring-boot-starter-aws-lambda/README.md new file mode 100644 index 0000000..6233891 --- /dev/null +++ b/spring-boot-starters/spring-boot-starter-aws-lambda/README.md @@ -0,0 +1,92 @@ +# Spring Boot Starter AWS Lambda + +This starter project provides auto-configuration support classes to easily invoke _AWS Lambda Functions_ from a Spring Boot application. + +* Configuration property classes for externalizing AWS credentials as IAM access tokens +* Automatic authenticated session management for securely invoking Lambda functions +* Provides a Spring Boot friendly config adapter for easily registering Lambda function invocation interfaces + +## Usage + +In your Spring Boot project, add the starter project dependency to your class path. For Maven, add the following dependency to your `pom.xml`. + +```xml + + + org.kbastani + spring-boot-starter-aws-lambda + ${spring-boot-starter-aws-lambda.version} + + + ... + +``` + +Next, inject your AWS IAM credentials safely into the `application.properties|yaml` file for your Spring Boot application. The snippet below shows an example of how to source the access credentials from the environment. + +```yaml +spring: + profiles: development +server: + port: 8081 +amazon: + aws: + access-key-id: ${AWS_ACCESS_KEY_ID} + access-key-secret: ${AWS_ACCESS_KEY_SECRET} +``` + +You can also set the properties using command line arguments with the Maven Spring Boot plugin, shown in the snippet below. + +```bash +$ mvn spring-boot:run -Drun.arguments="--amazon.aws.access-key-id=ABCDEFG,--amazon.aws.access-key-secret=ZYXKGFWG" +``` + +You can now begin to invoke AWS Lambda functions from your AWS account. The next thing you'll need to do is to define an interface of lambda function references to invoke. + +```java +public interface LambdaFunctions { + + @LambdaFunction(functionName="account-created-13P0EDGLDE399", logType = LogType.Tail) + Account accountCreated(AccountEvent event); + + @LambdaFunction(functionName="account-activated-1P0I6FTFCMHKH", logType = LogType.Tail) + Account accountActivated(AccountEvent event); +} +``` + +To start invoking your AWS Lambda functions, you can define a new bean that creates a proxy instance of your lambda interface. + +``` +@Configuration +public class AwsLambdaConfig { + + @Bean + public LambdaFunctions lambdaFunctions(AWSLambdaConfigurerAdapter configurerAdapter) { + return configurerAdapter.getFunctionInstance(LambdaFunctions.class); + } +} +``` + +In the example above, we inject the auto-configured `AWSLambdaConfigurerAdapter` dependency from `spring-boot-starter-aws-lambda` into a new Spring bean definition named `lambdaFunctions`. The configurer adapter will create an instance of an interface that contains `@LambdaFunction` annotated methods—like in the example snippet for the `LambdaFunctions` interface. + +We can now inject the `LambdaFunctions` as a dependency into other Spring components in our application in order to easily invoke remote Lambda functions on AWS. + + ``` + @Service + public class AccountService { + + final private LambdaFunctions lambdaFunctions; + + public AccountService(LambdaFunctions lambdaFunctions) { + this.lambdaFunctions = lambdaFunctions; + } + + public Account createAccount(Account account) { + // Trigger the new event by invoking AWS lambda + Account result = lambdaFunctions + .accountCreated(new AccountEvent(account, EventType.ACCOUNT_CREATED)); + + return result; + } + } + ``` \ No newline at end of file diff --git a/spring-boot-starter-aws-lambda/pom.xml b/spring-boot-starters/spring-boot-starter-aws-lambda/pom.xml similarity index 81% rename from spring-boot-starter-aws-lambda/pom.xml rename to spring-boot-starters/spring-boot-starter-aws-lambda/pom.xml index 18674fd..b78e3eb 100755 --- a/spring-boot-starter-aws-lambda/pom.xml +++ b/spring-boot-starters/spring-boot-starter-aws-lambda/pom.xml @@ -7,7 +7,7 @@ org.kbastani - event-stream-processing-parent + spring-boot-starters 1.0-SNAPSHOT ../ @@ -21,6 +21,11 @@ org.springframework.boot spring-boot-starter-test + + org.springframework.boot + spring-boot-configuration-processor + true + com.amazonaws aws-java-sdk-lambda @@ -28,7 +33,7 @@ com.amazonaws aws-java-sdk-sts - 1.11.67 + ${aws-java-sdk-sts.version} junit @@ -42,11 +47,13 @@ com.amazonaws aws-java-sdk-bom - 1.11.67 + ${aws-java-sdk-sts.version} pom import + + diff --git a/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java similarity index 83% rename from spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java index c8ccc51..79bfe59 100755 --- a/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java +++ b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AWSLambdaConfigurerAdapter.java @@ -2,6 +2,7 @@ package amazon.aws; import com.amazonaws.auth.*; import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.invoke.LambdaFunction; import com.amazonaws.services.lambda.invoke.LambdaInvokerFactory; import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient; import com.amazonaws.services.securitytoken.model.Credentials; @@ -11,7 +12,9 @@ import org.springframework.stereotype.Component; import java.util.Date; /** - * This class is a client for interacting with Amazon S3 bucket resources. + * Provides a configurer for invoking remote AWS Lambda functions using {@link LambdaInvokerFactory}. + * This component also manages the authenticated session for an IAM user that has provided valid + * access keys to access AWS resources. * * @author kbastani */ @@ -35,7 +38,11 @@ public class AWSLambdaConfigurerAdapter { } /** - * Gets an instance of a function interface + * Creates a proxy instance of a supplied interface that contains methods annotated with + * {@link LambdaFunction}. Provides automatic credential support to authenticate with an IAM + * access keys using {@link BasicSessionCredentials} auto-configured from Spring Boot + * configuration properties in {@link AmazonProperties}. + * * @param type * @param * @return diff --git a/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonAutoConfiguration.java b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonAutoConfiguration.java similarity index 100% rename from spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonAutoConfiguration.java rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonAutoConfiguration.java diff --git a/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java similarity index 96% rename from spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java index 07bb250..a68314a 100755 --- a/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java +++ b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/java/amazon/aws/AmazonProperties.java @@ -5,7 +5,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.context.annotation.Configuration; /** - * Configuration property group for Amazon S3 and AWS + * Provides a configuration properties model for authenticating with AWS. * * @author kbastani */ diff --git a/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring-configuration-metadata.json b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring-configuration-metadata.json similarity index 100% rename from spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring-configuration-metadata.json rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring-configuration-metadata.json diff --git a/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring.factories b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring.factories similarity index 100% rename from spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring.factories rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/META-INF/spring.factories diff --git a/spring-boot-starter-aws-lambda/src/main/resources/application.properties b/spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/application.properties similarity index 100% rename from spring-boot-starter-aws-lambda/src/main/resources/application.properties rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/main/resources/application.properties diff --git a/spring-boot-starter-aws-lambda/src/test/java/amazon/aws/AmazonConfigurationTest.java b/spring-boot-starters/spring-boot-starter-aws-lambda/src/test/java/amazon/aws/AmazonConfigurationTest.java similarity index 100% rename from spring-boot-starter-aws-lambda/src/test/java/amazon/aws/AmazonConfigurationTest.java rename to spring-boot-starters/spring-boot-starter-aws-lambda/src/test/java/amazon/aws/AmazonConfigurationTest.java diff --git a/user-parent/README.md b/user-parent/README.md deleted file mode 100644 index cbb8419..0000000 --- a/user-parent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# User Microservice - -This is the parent project that contains the modules of a microservice for the _User_ domain context. \ No newline at end of file diff --git a/user-parent/user-web/pom.xml b/user-parent/user-web/pom.xml deleted file mode 100644 index a1369b2..0000000 --- a/user-parent/user-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - user-web - 0.0.1-SNAPSHOT - jar - - │   │   └── user-web - - - org.kbastani - user-parent - 1.0-SNAPSHOT - ../ - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - diff --git a/user-parent/user-web/src/main/java/demo/UserServiceApplication.java b/user-parent/user-web/src/main/java/demo/UserServiceApplication.java deleted file mode 100644 index 999268c..0000000 --- a/user-parent/user-web/src/main/java/demo/UserServiceApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class UserServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(UserServiceApplication.class, args); - } -} diff --git a/user-parent/user-web/src/main/resources/application.properties b/user-parent/user-web/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/warehouse-parent/README.md b/warehouse-parent/README.md deleted file mode 100644 index d67c6c1..0000000 --- a/warehouse-parent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Warehouse Microservice - -This is the parent project that contains the modules of a microservice for the _Warehouse_ domain context. \ No newline at end of file diff --git a/warehouse-parent/pom.xml b/warehouse-parent/pom.xml deleted file mode 100644 index 183e49d..0000000 --- a/warehouse-parent/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - 4.0.0 - - warehouse-parent - 1.0-SNAPSHOT - pom - - │   ├── warehouse-parent - - - org.kbastani - event-stream-processing-parent - 1.0-SNAPSHOT - ../ - - - - warehouse-web - - - - - - - - \ No newline at end of file diff --git a/warehouse-parent/warehouse-web/pom.xml b/warehouse-parent/warehouse-web/pom.xml deleted file mode 100644 index 1d0575a..0000000 --- a/warehouse-parent/warehouse-web/pom.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - 4.0.0 - - warehouse-web - 0.0.1-SNAPSHOT - jar - - │   │   └── warehouse-web - - - org.kbastani - warehouse-parent - 1.0-SNAPSHOT - ../ - - - - UTF-8 - UTF-8 - 1.8 - - - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - diff --git a/warehouse-parent/warehouse-web/src/main/java/demo/WarehouseServiceApplication.java b/warehouse-parent/warehouse-web/src/main/java/demo/WarehouseServiceApplication.java deleted file mode 100644 index 12b17bb..0000000 --- a/warehouse-parent/warehouse-web/src/main/java/demo/WarehouseServiceApplication.java +++ /dev/null @@ -1,12 +0,0 @@ -package demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class WarehouseServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(WarehouseServiceApplication.class, args); - } -} diff --git a/warehouse-parent/warehouse-web/src/main/resources/application.properties b/warehouse-parent/warehouse-web/src/main/resources/application.properties deleted file mode 100644 index e69de29..0000000 diff --git a/warehouse-parent/warehouse-web/src/test/java/demo/WarehouseServiceApplicationTests.java b/warehouse-parent/warehouse-web/src/test/java/demo/WarehouseServiceApplicationTests.java deleted file mode 100644 index 5f0a208..0000000 --- a/warehouse-parent/warehouse-web/src/test/java/demo/WarehouseServiceApplicationTests.java +++ /dev/null @@ -1,16 +0,0 @@ -package demo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class WarehouseServiceApplicationTests { - - @Test - public void contextLoads() { - } - -}