├── .idea
├── .gitignore
├── vcs.xml
├── aws.xml
├── encodings.xml
├── misc.xml
├── uiDesigner.xml
└── dbnavigator.xml
├── payments-service
├── .idea
│ ├── .gitignore
│ ├── vcs.xml
│ ├── aws.xml
│ ├── misc.xml
│ ├── encodings.xml
│ ├── uiDesigner.xml
│ └── dbnavigator.xml
├── README.md
├── src
│ └── main
│ │ ├── java
│ │ └── br
│ │ │ └── com
│ │ │ └── souza
│ │ │ └── eventsdrivenarchitecture
│ │ │ ├── enums
│ │ │ └── ValidPaymentTypeEnum.java
│ │ │ ├── service
│ │ │ ├── payment
│ │ │ │ ├── PaymentStatusEnum.java
│ │ │ │ ├── PaymentHistoricDTO.java
│ │ │ │ └── PaymentService.java
│ │ │ ├── sqs
│ │ │ │ └── OrdersQueueConsumer.java
│ │ │ └── sns
│ │ │ │ └── AwsSnsService.java
│ │ │ ├── dto
│ │ │ ├── CustomErrorResponse.java
│ │ │ ├── QueueMessageRequest.java
│ │ │ ├── Product.java
│ │ │ └── OrderResponse.java
│ │ │ ├── PaymentsServiceApplication.java
│ │ │ └── config
│ │ │ ├── SQSConfig.java
│ │ │ └── SNSConfig.java
│ │ └── resources
│ │ └── application.yml
├── .gitignore
└── pom.xml
├── orders-service
├── README.md
├── src
│ ├── main
│ │ ├── java
│ │ │ └── br
│ │ │ │ └── com
│ │ │ │ └── souza
│ │ │ │ └── eventsdrivenarchitecture
│ │ │ │ ├── controller
│ │ │ │ ├── IOrderController.java
│ │ │ │ ├── IProductController.java
│ │ │ │ └── impl
│ │ │ │ │ ├── OrderControllerImpl.java
│ │ │ │ │ └── ProductControllerImpl.java
│ │ │ │ ├── enums
│ │ │ │ ├── PaymentStatusEnum.java
│ │ │ │ └── PaymentTypeEnum.java
│ │ │ │ ├── exceptions
│ │ │ │ ├── OrderNotFoundException.java
│ │ │ │ ├── ProductNotFoundException.java
│ │ │ │ ├── InsufficientStockException.java
│ │ │ │ └── ProductNameAlreadyExistsException.java
│ │ │ │ ├── dto
│ │ │ │ ├── CustomErrorResponse.java
│ │ │ │ ├── ProductRequest.java
│ │ │ │ ├── OrderRequest.java
│ │ │ │ └── OrderResponse.java
│ │ │ │ ├── OrdersServiceApplication.java
│ │ │ │ ├── database
│ │ │ │ ├── repository
│ │ │ │ │ ├── IOrderRepository.java
│ │ │ │ │ └── IProductRepository.java
│ │ │ │ └── model
│ │ │ │ │ ├── Product.java
│ │ │ │ │ └── Order.java
│ │ │ │ ├── config
│ │ │ │ ├── SQSConfig.java
│ │ │ │ └── SNSConfig.java
│ │ │ │ ├── service
│ │ │ │ ├── sns
│ │ │ │ │ └── AwsSnsService.java
│ │ │ │ ├── sqs
│ │ │ │ │ └── ProcessedPaymentsQueueConsumer.java
│ │ │ │ ├── product
│ │ │ │ │ └── ProductService.java
│ │ │ │ └── order
│ │ │ │ │ └── OrderService.java
│ │ │ │ └── handler
│ │ │ │ └── GlobalExceptionHandler.java
│ │ └── resources
│ │ │ └── application.yml
│ └── test
│ │ └── java
│ │ └── br
│ │ └── com
│ │ └── souza
│ │ └── eventsdrivenarchitecture
│ │ └── EventsDrivenArchitectureApplicationTests.java
├── .gitignore
└── pom.xml
├── README.md
├── pom.xml
├── .gitignore
└── payments-historic-lambda
├── .gitignore
├── pom.xml
└── src
└── main
└── java
└── br
└── com
└── souza
└── paymentshistoriclambda
└── PaymentsHistoricFunction.java
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/payments-service/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/orders-service/README.md:
--------------------------------------------------------------------------------
1 | # Event_Driven_Architecture_Example
2 | EDA (Events-Driven Architecture) example with Java, Spring, AWS SNS, AWS SQS and AWS Lambda.
3 |
--------------------------------------------------------------------------------
/payments-service/README.md:
--------------------------------------------------------------------------------
1 | # Event_Driven_Architecture_Example
2 | EDA (Events-Driven Architecture) example with Java, Spring, AWS SNS, AWS SQS and AWS Lambda.
3 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/controller/IOrderController.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.controller;
2 |
3 | public interface IOrderController {
4 | }
5 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/controller/IProductController.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.controller;
2 |
3 | public interface IProductController {
4 | }
5 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/enums/PaymentStatusEnum.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.enums;
2 |
3 | public enum PaymentStatusEnum {
4 |
5 | PENDING
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/enums/ValidPaymentTypeEnum.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.enums;
2 |
3 | public enum ValidPaymentTypeEnum {
4 |
5 | PIX,
6 | DEBIT_CARD
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/payment/PaymentStatusEnum.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.payment;
2 |
3 | public enum PaymentStatusEnum {
4 |
5 | APPROVED,
6 | RECUSED
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/enums/PaymentTypeEnum.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.enums;
2 |
3 | public enum PaymentTypeEnum {
4 |
5 | PIX,
6 | CREDIT_CARD,
7 | DEBIT_CARD,
8 | PAYPAL
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/exceptions/OrderNotFoundException.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.exceptions;
2 |
3 | public class OrderNotFoundException extends Exception{
4 |
5 | public OrderNotFoundException() {
6 | super();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/exceptions/ProductNotFoundException.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.exceptions;
2 |
3 | public class ProductNotFoundException extends Exception{
4 |
5 | public ProductNotFoundException() {
6 | super();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/exceptions/InsufficientStockException.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.exceptions;
2 |
3 | public class InsufficientStockException extends Exception{
4 |
5 | public InsufficientStockException() {
6 | super();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/exceptions/ProductNameAlreadyExistsException.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.exceptions;
2 |
3 | public class ProductNameAlreadyExistsException extends Exception{
4 |
5 | public ProductNameAlreadyExistsException() {
6 | super();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/payments-service/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ecommerce Events Driven Architecture
2 |
Project Architecture
3 |
4 | Used technologies
5 | -Java
6 | -Spring
7 | -MongoDB
8 | -SNS
9 | -SQS
10 | -Lambda
11 | -Bucket S3
12 |
--------------------------------------------------------------------------------
/orders-service/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | data:
3 | mongodb:
4 | uri: mongodb://root:root@localhost
5 | database: ecommerce
6 |
7 | aws:
8 | region: us-east-1
9 | sqs:
10 | endpoint: https://sqs.us-east-1.amazonaws.com/337328321041/processed-orders-queue
11 | sns:
12 | orders-topic: arn:aws:sns:us-east-1:337328321041:orders-topic
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/CustomErrorResponse.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class CustomErrorResponse {
11 |
12 | private String error;
13 | private int status;
14 | }
15 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/CustomErrorResponse.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class CustomErrorResponse {
11 |
12 | private String error;
13 | private int status;
14 | }
15 |
--------------------------------------------------------------------------------
/payments-service/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | data:
3 | mongodb:
4 | uri: mongodb://root:root@localhost
5 | database: payments
6 |
7 | aws:
8 | region: us-east-1
9 | sqs:
10 | endpoint: https://sqs.us-east-1.amazonaws.com/337328321041/orders-queue
11 | sns:
12 | processed-orders-topic: arn:aws:sns:us-east-1:337328321041:processed-orders-topic
13 |
14 | server:
15 | port: 8081
--------------------------------------------------------------------------------
/orders-service/src/test/java/br/com/souza/eventsdrivenarchitecture/EventsDrivenArchitectureApplicationTests.java:
--------------------------------------------------------------------------------
1 | //package br.com.souza.eventsdrivenarchitecture;
2 | //
3 | //import org.junit.jupiter.api.Test;
4 | //import org.springframework.boot.test.context.SpringBootTest;
5 | //
6 | //@SpringBootTest
7 | //class EventsDrivenArchitectureApplicationTests {
8 | //
9 | // @Test
10 | // void contextLoads() {
11 | // }
12 | //
13 | //}
14 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/OrdersServiceApplication.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class OrdersServiceApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(OrdersServiceApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/PaymentsServiceApplication.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class PaymentsServiceApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(PaymentsServiceApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/database/repository/IOrderRepository.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.database.repository;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Order;
4 | import java.util.UUID;
5 | import org.springframework.data.mongodb.repository.MongoRepository;
6 | import org.springframework.stereotype.Repository;
7 |
8 | @Repository
9 | public interface IOrderRepository extends MongoRepository {
10 | }
11 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 | org.example
5 | ecommerce_events_driven
6 | 1.0-SNAPSHOT
7 | Archetype - ecommerce_event_driven
8 | http://maven.apache.org
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/QueueMessageRequest.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @AllArgsConstructor
9 | @NoArgsConstructor
10 | public class QueueMessageRequest {
11 |
12 | private String Type;
13 | private String MessageId;
14 | private String TopicArn;
15 | private OrderResponse Message;
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/orders-service/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
--------------------------------------------------------------------------------
/payments-service/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/database/repository/IProductRepository.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.database.repository;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Product;
4 | import java.util.Optional;
5 | import java.util.UUID;
6 | import org.springframework.data.mongodb.repository.MongoRepository;
7 | import org.springframework.stereotype.Repository;
8 |
9 | @Repository
10 | public interface IProductRepository extends MongoRepository {
11 |
12 | Optional findByName(String name);
13 | }
14 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/ProductRequest.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import jakarta.validation.constraints.NotNull;
4 | import java.math.BigDecimal;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Builder;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | @Builder
14 | public class ProductRequest {
15 |
16 | @NotNull
17 | private String name;
18 | @NotNull
19 | private BigDecimal price;
20 | @NotNull
21 | private Integer quantity;
22 | }
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/payments-service/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/payments-historic-lambda/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/OrderRequest.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.enums.PaymentTypeEnum;
4 | import jakarta.validation.constraints.NotNull;
5 | import java.util.UUID;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | @Data
12 | @NoArgsConstructor
13 | @AllArgsConstructor
14 | @Builder
15 | public class OrderRequest {
16 |
17 | @NotNull
18 | private UUID productId;
19 | @NotNull
20 | private Integer quantity;
21 | @NotNull
22 | private PaymentTypeEnum paymentType;
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/payments-service/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/Product.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.UUID;
5 | import org.json.JSONObject;
6 | import org.springframework.data.annotation.Id;
7 |
8 | public class Product {
9 |
10 | private UUID id;
11 | private String name;
12 | private BigDecimal price;
13 | private Integer quantity;
14 |
15 | @Override
16 | public String toString(){
17 | JSONObject json = new JSONObject();
18 | json.put("id", id);
19 | json.put("name", name);
20 | json.put("quantity", quantity);
21 | json.put("price", price);
22 |
23 | return json.toString();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/payments-service/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/sqs/OrdersQueueConsumer.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.sqs;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.service.payment.PaymentService;
4 | import io.awspring.cloud.sqs.annotation.SqsListener;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class OrdersQueueConsumer {
9 |
10 | private final PaymentService paymentService;
11 |
12 | public OrdersQueueConsumer(PaymentService paymentService) {
13 | this.paymentService = paymentService;
14 | }
15 |
16 | @SqsListener("orders-queue")
17 | public void listen(String message) throws Exception{
18 | paymentService.validateOrderPayment(message);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/config/SQSConfig.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.config;
2 |
3 | import java.net.URI;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import software.amazon.awssdk.regions.Region;
8 | import software.amazon.awssdk.services.sqs.SqsAsyncClient;
9 |
10 | @Configuration
11 | public class SQSConfig {
12 |
13 | @Value("${aws.sqs.endpoint}")
14 | private String amazonSqsEndpoint;
15 |
16 | @Bean
17 | public SqsAsyncClient amazonSQSAsync() {
18 | return SqsAsyncClient.builder()
19 | .endpointOverride(URI.create(amazonSqsEndpoint))
20 | .region(Region.US_EAST_1)
21 | .build();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/config/SQSConfig.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.config;
2 |
3 | import java.net.URI;
4 | import org.springframework.beans.factory.annotation.Value;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import software.amazon.awssdk.regions.Region;
8 | import software.amazon.awssdk.services.sqs.SqsAsyncClient;
9 |
10 | @Configuration
11 | public class SQSConfig {
12 |
13 | @Value("${aws.sqs.endpoint}")
14 | private String amazonSqsEndpoint;
15 |
16 | @Bean
17 | public SqsAsyncClient amazonSQSAsync() {
18 | return SqsAsyncClient.builder()
19 | .endpointOverride(URI.create(amazonSqsEndpoint))
20 | .region(Region.US_EAST_1)
21 | .build();
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/payment/PaymentHistoricDTO.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.payment;
2 |
3 | import java.util.UUID;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Builder;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 | import org.json.JSONObject;
9 | import org.springframework.data.annotation.Id;
10 | import org.springframework.data.mongodb.core.mapping.Document;
11 |
12 | @Data
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | @Builder
16 | public class PaymentHistoricDTO {
17 |
18 | private UUID orderId;
19 | private String paymentStatus;
20 |
21 | @Override
22 | public String toString(){
23 | JSONObject json = new JSONObject();
24 | json.put("orderId", orderId);
25 | json.put("paymentStatus", paymentStatus);
26 |
27 | return json.toString();
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/sns/AwsSnsService.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.sns;
2 |
3 | import com.amazonaws.services.sns.AmazonSNS;
4 | import com.amazonaws.services.sns.model.Topic;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Qualifier;
7 | import org.springframework.stereotype.Service;
8 |
9 | @Slf4j
10 | @Service
11 | public class AwsSnsService {
12 | private final AmazonSNS snsClient;
13 | private final Topic ordersTopic;
14 |
15 | public AwsSnsService(AmazonSNS snsClient,
16 | @Qualifier("ordersTopic") Topic ordersTopic){
17 | this.snsClient = snsClient;
18 | this.ordersTopic = ordersTopic;
19 | }
20 |
21 | public void publish(String message){
22 | snsClient.publish(ordersTopic.getTopicArn(), message);
23 | System.out.println("Message published");
24 | }
25 | }
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/sns/AwsSnsService.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.sns;
2 |
3 | import com.amazonaws.services.sns.AmazonSNS;
4 | import com.amazonaws.services.sns.model.Topic;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Qualifier;
7 | import org.springframework.stereotype.Service;
8 |
9 | @Slf4j
10 | @Service
11 | public class AwsSnsService {
12 | private final AmazonSNS snsClient;
13 | private final Topic processedPaymentsTopic;
14 |
15 | public AwsSnsService(AmazonSNS snsClient,
16 | Topic processedPaymentsTopic){
17 | this.snsClient = snsClient;
18 | this.processedPaymentsTopic = processedPaymentsTopic;
19 | }
20 |
21 | public void publish(String message){
22 | snsClient.publish(processedPaymentsTopic.getTopicArn(), message);
23 | System.out.println("Message published");
24 | }
25 | }
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/OrderResponse.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import java.math.BigDecimal;
4 | import java.time.LocalDateTime;
5 | import java.util.UUID;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 | import org.json.JSONObject;
11 |
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | @Builder
16 | public class OrderResponse {
17 |
18 | private UUID id;
19 | private Integer quantity;
20 | private BigDecimal amount;
21 | private LocalDateTime orderTime;
22 | private String paymentStatus;
23 | private Product product;
24 |
25 | @Override
26 | public String toString(){
27 | JSONObject json = new JSONObject();
28 | json.put("id", id);
29 | json.put("quantity", quantity);
30 | json.put("amount", amount);
31 | json.put("paymentStatus", paymentStatus);
32 | json.put("product", product.toString());
33 |
34 | return json.toString();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/config/SNSConfig.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.config;
2 |
3 | import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
4 | import com.amazonaws.services.sns.AmazonSNS;
5 | import com.amazonaws.services.sns.AmazonSNSClientBuilder;
6 | import com.amazonaws.services.sns.model.Topic;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | public class SNSConfig {
13 |
14 | @Value("${aws.region}")
15 | private String region;
16 | @Value("${aws.sns.orders-topic}")
17 | private String ordersTopicArn;
18 |
19 | @Bean
20 | public AmazonSNS amazonSNSBuilder(){
21 | return AmazonSNSClientBuilder.standard()
22 | .withCredentials(new DefaultAWSCredentialsProviderChain())
23 | .withRegion(region)
24 | .build();
25 | }
26 |
27 | @Bean(name = "ordersTopic")
28 | public Topic snsOrdersTopicBuilder(){
29 | return new Topic().withTopicArn(ordersTopicArn);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/config/SNSConfig.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.config;
2 |
3 | import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
4 | import com.amazonaws.services.sns.AmazonSNS;
5 | import com.amazonaws.services.sns.AmazonSNSClientBuilder;
6 | import com.amazonaws.services.sns.model.Topic;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 |
11 | @Configuration
12 | public class SNSConfig {
13 |
14 | @Value("${aws.region}")
15 | private String region;
16 | @Value("${aws.sns.processed-orders-topic}")
17 | private String processedOrdersTopicArn;
18 |
19 | @Bean
20 | public AmazonSNS amazonSNSBuilder(){
21 | return AmazonSNSClientBuilder.standard()
22 | .withCredentials(new DefaultAWSCredentialsProviderChain())
23 | .withRegion(region)
24 | .build();
25 | }
26 |
27 | @Bean
28 | public Topic snsProcessedOrdersTopicBuilder(){
29 | return new Topic().withTopicArn(processedOrdersTopicArn);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/database/model/Product.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.database.model;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.dto.ProductRequest;
4 | import java.math.BigDecimal;
5 | import java.util.UUID;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Builder;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 | import org.json.JSONObject;
11 | import org.springframework.data.annotation.Id;
12 | import org.springframework.data.mongodb.core.mapping.Document;
13 |
14 | @Data
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | @Builder
18 | @Document(collection = "products")
19 | public class Product {
20 |
21 | @Id
22 | private UUID id;
23 | private String name;
24 | private BigDecimal price;
25 | private Integer quantity;
26 |
27 | public Product(ProductRequest request){
28 | this.id = UUID.randomUUID();
29 | this.name = request.getName();
30 | this.price = request.getPrice();
31 | this.quantity = request.getQuantity();
32 | }
33 |
34 | @Override
35 | public String toString(){
36 | JSONObject json = new JSONObject();
37 | json.put("id", id);
38 | json.put("name", name);
39 | json.put("quantity", quantity);
40 | json.put("price", price);
41 |
42 | return json.toString();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/sqs/ProcessedPaymentsQueueConsumer.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.sqs;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.service.order.OrderService;
4 | import io.awspring.cloud.sqs.annotation.SqsListener;
5 | import java.util.UUID;
6 | import lombok.extern.slf4j.Slf4j;
7 | import org.json.JSONObject;
8 | import org.springframework.stereotype.Component;
9 |
10 | @Slf4j
11 | @Component
12 | public class ProcessedPaymentsQueueConsumer {
13 |
14 | private final OrderService orderService;
15 |
16 | public ProcessedPaymentsQueueConsumer(OrderService orderService) {
17 | this.orderService = orderService;
18 | }
19 |
20 | @SqsListener("processed-orders-queue")
21 | public void listen(String message) throws Exception{
22 | System.out.println("Payment processed");
23 | JSONObject queueMessage = new JSONObject(message);
24 | String messageJsonString = queueMessage.getString("Message");
25 |
26 | JSONObject messageObject = null;
27 | try {
28 | messageObject = new JSONObject(messageJsonString);
29 | }catch (Exception e){
30 | log.error("Error: ", e);
31 | return;
32 | }
33 |
34 | orderService.updatePaymentStatus(UUID.fromString(messageObject.getString("orderId")), messageObject.getString("paymentStatus"));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/product/ProductService.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.product;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Product;
4 | import br.com.souza.eventsdrivenarchitecture.database.repository.IProductRepository;
5 | import br.com.souza.eventsdrivenarchitecture.dto.ProductRequest;
6 | import br.com.souza.eventsdrivenarchitecture.exceptions.ProductNameAlreadyExistsException;
7 | import br.com.souza.eventsdrivenarchitecture.exceptions.ProductNotFoundException;
8 | import java.util.List;
9 | import java.util.UUID;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Service
13 | public class ProductService {
14 |
15 | private final IProductRepository iProductRepository;
16 |
17 | public ProductService(IProductRepository iProductRepository) {
18 | this.iProductRepository = iProductRepository;
19 | }
20 |
21 | public void saveNewProduct(ProductRequest request) throws Exception {
22 | if (iProductRepository.findByName(request.getName()).isPresent()) {
23 | throw new ProductNameAlreadyExistsException();
24 | }
25 |
26 | iProductRepository.save(new Product(request));
27 | }
28 |
29 | public void updateProduct(Product product) throws Exception {
30 | getProductById(product.getId());
31 | iProductRepository.save(product);
32 | }
33 |
34 | public Product getProductById(UUID id) throws Exception{
35 | return iProductRepository.findById(id)
36 | .orElseThrow(ProductNotFoundException::new);
37 | }
38 |
39 | public List getAllProducts() {
40 | return iProductRepository.findAll();
41 | }
42 |
43 | public void deleteProduct(UUID id) throws Exception{
44 | iProductRepository.delete(getProductById(id));
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/dto/OrderResponse.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.dto;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Order;
4 | import br.com.souza.eventsdrivenarchitecture.database.model.Product;
5 | import br.com.souza.eventsdrivenarchitecture.database.repository.IProductRepository;
6 | import java.math.BigDecimal;
7 | import java.time.LocalDateTime;
8 | import java.util.UUID;
9 | import lombok.AllArgsConstructor;
10 | import lombok.Builder;
11 | import lombok.Data;
12 | import lombok.NoArgsConstructor;
13 | import org.json.JSONObject;
14 |
15 | @Data
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @Builder
19 | public class OrderResponse {
20 |
21 | private UUID id;
22 | private Integer quantity;
23 | private BigDecimal amount;
24 | private LocalDateTime orderTime;
25 | private String paymentStatus;
26 | private String paymentType;
27 | private Product product;
28 |
29 | public OrderResponse(Order order, IProductRepository iProductRepository){
30 | this.id = order.getId();
31 | this.quantity = order.getQuantity();
32 | this.amount = order.getAmount();
33 | this.orderTime = order.getOrderTime();
34 | this.paymentStatus = order.getPaymentStatus();
35 | this.paymentType = order.getPaymentType();
36 | this.product = iProductRepository.findById(order.getProductId())
37 | .orElse(null);
38 | }
39 |
40 | @Override
41 | public String toString(){
42 | JSONObject json = new JSONObject();
43 | json.put("id", id);
44 | json.put("quantity", quantity);
45 | json.put("amount", amount);
46 | json.put("orderTime", orderTime);
47 | json.put("paymentStatus", paymentStatus);
48 | json.put("paymentType", paymentType);
49 | json.put("product", product.toString());
50 |
51 | return json.toString();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/database/model/Order.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.database.model;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.dto.OrderRequest;
4 | import br.com.souza.eventsdrivenarchitecture.enums.PaymentStatusEnum;
5 | import java.math.BigDecimal;
6 | import java.time.LocalDateTime;
7 | import java.util.UUID;
8 | import lombok.AllArgsConstructor;
9 | import lombok.Builder;
10 | import lombok.Data;
11 | import lombok.NoArgsConstructor;
12 | import org.json.JSONObject;
13 | import org.springframework.data.annotation.Id;
14 | import org.springframework.data.mongodb.core.mapping.Document;
15 |
16 | @Data
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | @Builder
20 | @Document(collection = "orders")
21 | public class Order {
22 |
23 | @Id
24 | private UUID id;
25 | private UUID productId;
26 | private Integer quantity;
27 | private BigDecimal amount;
28 | private LocalDateTime orderTime;
29 | private String paymentStatus;
30 | private String paymentType;
31 |
32 | public Order(OrderRequest request, Product product){
33 | this.id = UUID.randomUUID();
34 | this.productId = request.getProductId();
35 | this.quantity = request.getQuantity();
36 | this.amount = product.getPrice().multiply(new BigDecimal(request.getQuantity()));
37 | this.orderTime = LocalDateTime.now();
38 | this.paymentStatus = PaymentStatusEnum.PENDING.name().toUpperCase();
39 | this.paymentType = request.getPaymentType().name().toUpperCase();
40 | }
41 |
42 | @Override
43 | public String toString(){
44 | JSONObject json = new JSONObject();
45 | json.put("id", id);
46 | json.put("productId", productId);
47 | json.put("quantity", quantity);
48 | json.put("amount", amount);
49 | json.put("paymentType", paymentType);
50 | json.put("paymentStatus", paymentStatus);
51 | json.put("orderTime", orderTime);
52 |
53 | return json.toString();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/controller/impl/OrderControllerImpl.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.controller.impl;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.dto.OrderRequest;
4 | import br.com.souza.eventsdrivenarchitecture.dto.OrderResponse;
5 | import br.com.souza.eventsdrivenarchitecture.service.order.OrderService;
6 | import java.util.List;
7 | import java.util.UUID;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.PathVariable;
13 | import org.springframework.web.bind.annotation.PostMapping;
14 | import org.springframework.web.bind.annotation.RequestBody;
15 | import org.springframework.web.bind.annotation.RequestMapping;
16 | import org.springframework.web.bind.annotation.RestController;
17 |
18 | @RestController
19 | @RequestMapping(value = "/v1/order")
20 | public class OrderControllerImpl {
21 |
22 | private final OrderService orderService;
23 |
24 | public OrderControllerImpl(OrderService orderService) {
25 | this.orderService = orderService;
26 | }
27 |
28 | @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
29 | public ResponseEntity createNewOrder(@RequestBody OrderRequest request) throws Exception {
30 | orderService.saveNewOrder(request);
31 | return new ResponseEntity<>(HttpStatus.CREATED);
32 | }
33 |
34 | @GetMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
35 | public ResponseEntity getOrderById(@PathVariable("id") UUID id) throws Exception {
36 | return new ResponseEntity<>(orderService.getOrderById(id), HttpStatus.OK);
37 | }
38 |
39 | @GetMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
40 | public ResponseEntity> getAllOrders(){
41 | return new ResponseEntity<>(orderService.getAllOrders(), HttpStatus.OK);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/payments-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/payment/PaymentService.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.payment;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.enums.ValidPaymentTypeEnum;
4 | import br.com.souza.eventsdrivenarchitecture.service.sns.AwsSnsService;
5 | import java.util.Arrays;
6 | import java.util.List;
7 | import java.util.UUID;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.json.JSONObject;
10 | import org.springframework.stereotype.Service;
11 |
12 | @Slf4j
13 | @Service
14 | public class PaymentService {
15 |
16 | private final AwsSnsService awsSnsService;
17 |
18 | public PaymentService(AwsSnsService awsSnsService) {
19 | this.awsSnsService = awsSnsService;
20 | }
21 |
22 | public void validateOrderPayment(String message) throws Exception{
23 | System.out.println("Processando tipo de pagamento do pedido...");
24 |
25 | JSONObject queueMessage = new JSONObject(message);
26 | String messageJsonString = queueMessage.getString("Message");
27 |
28 | JSONObject messageObject = null;
29 | try {
30 | messageObject = new JSONObject(messageJsonString);
31 | }catch (Exception e){
32 | log.error("Error: ", e);
33 | return;
34 | }
35 | String paymentType = messageObject.getString("paymentType");
36 |
37 | PaymentHistoricDTO paymentHistoricLog = PaymentHistoricDTO.builder()
38 | .orderId(UUID.fromString(messageObject.getString("id")))
39 | .paymentStatus(isValidPaymentType(paymentType) ? PaymentStatusEnum.APPROVED.name() : PaymentStatusEnum.RECUSED.name())
40 | .build();
41 |
42 | awsSnsService.publish(paymentHistoricLog.toString());
43 | }
44 |
45 | private boolean isValidPaymentType(String paymentType){
46 | List validPaymentTypes = Arrays.stream(ValidPaymentTypeEnum.values())
47 | .map(ValidPaymentTypeEnum::name)
48 | .map(String::toUpperCase)
49 | .toList();
50 |
51 | return validPaymentTypes.contains(paymentType.toUpperCase());
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/payments-historic-lambda/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.2.2
9 |
10 |
11 | br.com.souza
12 | payments-historic-lambda
13 | 0.0.1-SNAPSHOT
14 | payments-historic-lambda
15 | Lambda Function to store payments JSON into Bucket S3
16 |
17 | 17
18 | 17
19 | 17
20 |
21 |
22 |
23 |
24 | com.amazonaws
25 | aws-lambda-java-core
26 | 1.2.3
27 |
28 |
29 |
30 | com.amazonaws
31 | aws-java-sdk-lambda
32 | 1.12.661
33 |
34 |
35 | com.amazonaws
36 | aws-lambda-java-events
37 | 3.11.4
38 |
39 |
40 |
41 | com.amazonaws
42 | aws-java-sdk-s3
43 | 1.12.661
44 |
45 |
46 | org.json
47 | json
48 | 20231013
49 |
50 |
51 |
52 |
53 | payments-historic-lambda
54 |
55 |
56 | org.apache.maven.plugins
57 | maven-shade-plugin
58 | 3.5.1
59 |
60 | false
61 |
62 |
63 |
64 | package
65 |
66 | shade
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/payments-historic-lambda/src/main/java/br/com/souza/paymentshistoriclambda/PaymentsHistoricFunction.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.paymentshistoriclambda;
2 |
3 | import com.amazonaws.auth.AWSStaticCredentialsProvider;
4 | import com.amazonaws.auth.BasicAWSCredentials;
5 | import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
6 | import com.amazonaws.regions.Regions;
7 | import com.amazonaws.services.lambda.runtime.Context;
8 | import com.amazonaws.services.lambda.runtime.RequestHandler;
9 | import com.amazonaws.services.lambda.runtime.events.SQSEvent;
10 | import com.amazonaws.services.s3.AmazonS3;
11 | import com.amazonaws.services.s3.AmazonS3ClientBuilder;
12 | import com.amazonaws.services.s3.model.PutObjectRequest;
13 | import java.io.File;
14 | import java.io.FileOutputStream;
15 | import java.io.IOException;
16 | import java.io.OutputStream;
17 | import org.json.JSONObject;
18 |
19 |
20 | public class PaymentsHistoricFunction implements RequestHandler {
21 |
22 | @Override
23 | public String handleRequest(SQSEvent event, Context context) {
24 |
25 | Regions clientRegion = Regions.fromName(System.getenv("REGION"));
26 |
27 | BasicAWSCredentials credentials = new BasicAWSCredentials(
28 | System.getenv("ACCESS_KEY"),
29 | System.getenv("SECRET_ACCESS_KEY"));
30 |
31 | AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
32 | .withRegion(clientRegion)
33 | .withCredentials(new AWSStaticCredentialsProvider(credentials))
34 | .build();
35 |
36 | String bucketName = System.getenv("BUCKET_NAME");
37 |
38 | for (SQSEvent.SQSMessage msg : event.getRecords()) {
39 | System.out.println("Received message: " + msg.getBody());
40 | JSONObject jsonObject = new JSONObject(msg.getBody());
41 |
42 | JSONObject paymentObject = new JSONObject(jsonObject.getString("Message"));
43 | String orderId = paymentObject.getString("orderId");
44 |
45 | File file = new File("/tmp/" + orderId + "-payment.json");
46 | try (OutputStream os = new FileOutputStream(file)) {
47 | os.write(paymentObject.toString().getBytes());
48 | } catch (IOException e) {
49 | throw new RuntimeException(e);
50 | }
51 |
52 | s3Client.putObject(new PutObjectRequest(bucketName, orderId + "-payment.json", file));
53 | System.out.println("Successfully saved into Bucket S3");
54 | file.delete();
55 | }
56 | return "Successfully saved into Bucket S3";
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/payments-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | br.com.souza
7 | payments-service
8 | 1.0.0
9 | payments-service
10 | EDA payments service project example with Java, Spring, SNS, SQS, S3 and Lambda
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 3.2.2
16 |
17 |
18 |
19 |
20 | 17
21 |
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-data-mongodb
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-web
31 |
32 |
33 |
34 | org.projectlombok
35 | lombok
36 | true
37 |
38 |
39 |
40 | org.json
41 | json
42 | 20231013
43 |
44 |
45 |
46 | com.amazonaws
47 | aws-java-sdk-sns
48 | 1.12.62
49 |
50 |
51 | io.awspring.cloud
52 | spring-cloud-aws-starter-sqs
53 |
54 |
55 |
56 |
57 |
58 |
59 | io.awspring.cloud
60 | spring-cloud-aws-dependencies
61 | 3.0.1
62 | pom
63 | import
64 |
65 |
66 |
67 |
68 |
69 | payments-service
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 |
76 |
77 |
78 | org.projectlombok
79 | lombok
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/controller/impl/ProductControllerImpl.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.controller.impl;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Product;
4 | import br.com.souza.eventsdrivenarchitecture.dto.ProductRequest;
5 | import br.com.souza.eventsdrivenarchitecture.service.product.ProductService;
6 | import java.util.List;
7 | import java.util.UUID;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.web.bind.annotation.DeleteMapping;
12 | import org.springframework.web.bind.annotation.GetMapping;
13 | import org.springframework.web.bind.annotation.PathVariable;
14 | import org.springframework.web.bind.annotation.PostMapping;
15 | import org.springframework.web.bind.annotation.PutMapping;
16 | import org.springframework.web.bind.annotation.RequestBody;
17 | import org.springframework.web.bind.annotation.RequestMapping;
18 | import org.springframework.web.bind.annotation.RestController;
19 |
20 | @RestController
21 | @RequestMapping(value = "/v1/product")
22 | public class ProductControllerImpl {
23 |
24 | private final ProductService productService;
25 |
26 | public ProductControllerImpl(ProductService productService) {
27 | this.productService = productService;
28 | }
29 |
30 | @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
31 | public ResponseEntity createNewProduct(@RequestBody ProductRequest request) throws Exception {
32 | productService.saveNewProduct(request);
33 | return new ResponseEntity<>(HttpStatus.CREATED);
34 | }
35 |
36 | @PutMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
37 | public ResponseEntity updateProduct(@RequestBody Product product) throws Exception {
38 | productService.updateProduct(product);
39 | return new ResponseEntity<>(HttpStatus.CREATED);
40 | }
41 |
42 | @GetMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
43 | public ResponseEntity getProductById(@PathVariable("id") UUID id) throws Exception {
44 | return new ResponseEntity<>(productService.getProductById(id), HttpStatus.OK);
45 | }
46 |
47 | @GetMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
48 | public ResponseEntity> getAllProducts(){
49 | return new ResponseEntity<>(productService.getAllProducts(), HttpStatus.OK);
50 | }
51 |
52 | @DeleteMapping(value = "/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
53 | public ResponseEntity deleteProduct(@PathVariable("id") UUID id) throws Exception {
54 | productService.deleteProduct(id);
55 | return new ResponseEntity<>(HttpStatus.OK);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/orders-service/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | br.com.souza
7 | orders-service
8 | 1.0.0
9 | orders-service
10 | EDA ecommerce project example with Java, Spring, SNS, SQS, S3 and Lambda
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 3.2.2
16 |
17 |
18 |
19 |
20 | 17
21 |
22 |
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-data-mongodb
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-web
31 |
32 |
33 |
34 | org.projectlombok
35 | lombok
36 | true
37 |
38 |
39 |
40 | org.json
41 | json
42 | 20231013
43 |
44 |
45 |
46 | com.amazonaws
47 | aws-java-sdk-sns
48 | 1.12.62
49 |
50 |
51 | io.awspring.cloud
52 | spring-cloud-aws-starter-sqs
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-starter-validation
57 | 3.2.2
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | io.awspring.cloud
67 | spring-cloud-aws-dependencies
68 | 3.0.1
69 | pom
70 | import
71 |
72 |
73 |
74 |
75 |
76 | orders-service
77 |
78 |
79 |
80 | org.springframework.boot
81 | spring-boot-maven-plugin
82 |
83 |
84 |
85 | org.projectlombok
86 | lombok
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/service/order/OrderService.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.service.order;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.database.model.Order;
4 | import br.com.souza.eventsdrivenarchitecture.database.model.Product;
5 | import br.com.souza.eventsdrivenarchitecture.database.repository.IOrderRepository;
6 | import br.com.souza.eventsdrivenarchitecture.database.repository.IProductRepository;
7 | import br.com.souza.eventsdrivenarchitecture.dto.OrderRequest;
8 | import br.com.souza.eventsdrivenarchitecture.dto.OrderResponse;
9 | import br.com.souza.eventsdrivenarchitecture.exceptions.InsufficientStockException;
10 | import br.com.souza.eventsdrivenarchitecture.exceptions.OrderNotFoundException;
11 | import br.com.souza.eventsdrivenarchitecture.service.sns.AwsSnsService;
12 | import br.com.souza.eventsdrivenarchitecture.service.product.ProductService;
13 | import java.util.Comparator;
14 | import java.util.List;
15 | import java.util.UUID;
16 | import org.springframework.stereotype.Service;
17 |
18 | @Service
19 | public class OrderService {
20 |
21 | private final IOrderRepository iOrderRepository;
22 | private final ProductService productService;
23 | private final IProductRepository iProductRepository;
24 | private final AwsSnsService awsSnsService;
25 |
26 | public OrderService(IOrderRepository iOrderRepository,
27 | ProductService productService,
28 | IProductRepository iProductRepository,
29 | AwsSnsService awsSnsService) {
30 | this.iOrderRepository = iOrderRepository;
31 | this.productService = productService;
32 | this.iProductRepository = iProductRepository;
33 | this.awsSnsService = awsSnsService;
34 | }
35 |
36 | public void saveNewOrder(OrderRequest request) throws Exception {
37 | Product product = productService.getProductById(request.getProductId());
38 |
39 | if(product.getQuantity() < request.getQuantity()) throw new InsufficientStockException();
40 |
41 | product.setQuantity(product.getQuantity() - request.getQuantity());
42 | productService.updateProduct(product);
43 |
44 | Order order = new Order(request, product);
45 | iOrderRepository.save(order);
46 |
47 | awsSnsService.publish(new OrderResponse(order, iProductRepository).toString());
48 | }
49 |
50 | public OrderResponse getOrderById(UUID id) throws Exception{
51 | Order order = iOrderRepository.findById(id)
52 | .orElseThrow(OrderNotFoundException::new);
53 |
54 | return new OrderResponse(order, iProductRepository);
55 | }
56 |
57 | public List getAllOrders() {
58 | return iOrderRepository.findAll().stream()
59 | .map(o -> new OrderResponse(o, iProductRepository))
60 | .sorted(Comparator.comparing(OrderResponse::getOrderTime).reversed())
61 | .toList();
62 | }
63 |
64 | public void updatePaymentStatus(UUID id, String status) throws Exception{
65 | Order order = iOrderRepository.findById(id)
66 | .orElseThrow(OrderNotFoundException::new);
67 |
68 | order.setPaymentStatus(status);
69 |
70 | iOrderRepository.save(order);
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/orders-service/src/main/java/br/com/souza/eventsdrivenarchitecture/handler/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package br.com.souza.eventsdrivenarchitecture.handler;
2 |
3 | import br.com.souza.eventsdrivenarchitecture.dto.CustomErrorResponse;
4 | import br.com.souza.eventsdrivenarchitecture.exceptions.InsufficientStockException;
5 | import br.com.souza.eventsdrivenarchitecture.exceptions.OrderNotFoundException;
6 | import br.com.souza.eventsdrivenarchitecture.exceptions.ProductNameAlreadyExistsException;
7 | import br.com.souza.eventsdrivenarchitecture.exceptions.ProductNotFoundException;
8 | import org.springframework.http.HttpHeaders;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.http.MediaType;
11 | import org.springframework.http.ResponseEntity;
12 | import org.springframework.web.bind.annotation.ControllerAdvice;
13 | import org.springframework.web.bind.annotation.ExceptionHandler;
14 | import org.springframework.web.context.request.WebRequest;
15 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
16 |
17 | @ControllerAdvice
18 | public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
19 |
20 | @ExceptionHandler(InsufficientStockException.class)
21 | public ResponseEntity