├── Customer
├── .gitignore
├── README.md
├── pom.xml
├── prtsc
│ ├── Customer-1.1.png
│ ├── Customer-1.png
│ ├── Customer-2.png
│ ├── Customer-3.1.png
│ ├── Customer-3.2.png
│ ├── Customer-3.3.png
│ ├── Customer-3.png
│ └── Customer-4.png
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── jmendoza
│ │ │ └── swa
│ │ │ └── hexagonal
│ │ │ └── customer
│ │ │ ├── CustomerApplication.java
│ │ │ ├── application
│ │ │ ├── rest
│ │ │ │ ├── controller
│ │ │ │ │ └── CustomerController.java
│ │ │ │ ├── request
│ │ │ │ │ └── README.md
│ │ │ │ └── response
│ │ │ │ │ ├── CreateCustomerResponse.java
│ │ │ │ │ ├── CustomerLoginResponse.java
│ │ │ │ │ └── ResponseMapper.java
│ │ │ └── soap
│ │ │ │ └── README.md
│ │ │ ├── common
│ │ │ ├── config
│ │ │ │ └── CreateBean.java
│ │ │ ├── constants
│ │ │ │ └── CustomerConstanst.java
│ │ │ ├── customannotations
│ │ │ │ └── UseCase.java
│ │ │ └── exception
│ │ │ │ ├── CustomExceptionHandler.java
│ │ │ │ ├── ErrorDetails.java
│ │ │ │ ├── GlobalException.java
│ │ │ │ ├── ParameterNotFoundException.java
│ │ │ │ └── ResourceNotFoundException.java
│ │ │ ├── domain
│ │ │ ├── model
│ │ │ │ └── Customer.java
│ │ │ ├── ports
│ │ │ │ ├── inbound
│ │ │ │ │ ├── CreateCustomerUseCase.java
│ │ │ │ │ ├── CustomerLoginUseCase.java
│ │ │ │ │ ├── DeleteCustomerUseCase.java
│ │ │ │ │ └── UpdateCustomerUseCase.java
│ │ │ │ └── outbound
│ │ │ │ │ ├── CreateCustomerPort.java
│ │ │ │ │ ├── DeleteCustomerPort.java
│ │ │ │ │ ├── ExistsCustomerPort.java
│ │ │ │ │ ├── GetCustomerEmailPort.java
│ │ │ │ │ ├── GetCustomerIdPort.java
│ │ │ │ │ ├── PasswordEncodePort.java
│ │ │ │ │ ├── PasswordMatchesPort.java
│ │ │ │ │ └── UpdateCustomerPort.java
│ │ │ └── services
│ │ │ │ ├── CreateCustomerService.java
│ │ │ │ ├── CustomerLoginService.java
│ │ │ │ ├── DeleteCustomerService.java
│ │ │ │ └── UpdateCustomerService.java
│ │ │ └── infrastructure
│ │ │ ├── databases
│ │ │ ├── mongo
│ │ │ │ ├── CreateCustomerAdapter.java
│ │ │ │ ├── CustomerRepository.java
│ │ │ │ ├── DeleteCustomerAdapter.java
│ │ │ │ ├── ExistsCustomerAdapter.java
│ │ │ │ ├── GetCustomerEmailAdapter.java
│ │ │ │ ├── GetCustomerIdAdapter.java
│ │ │ │ └── UpdateCustomerAdapter.java
│ │ │ └── postgresql
│ │ │ │ └── README.md
│ │ │ ├── messagebroker
│ │ │ └── README.md
│ │ │ └── security
│ │ │ ├── PasswordEncodeAdapter.java
│ │ │ └── PasswordMatchesAdapter.java
│ └── resources
│ │ ├── application.properties
│ │ └── log4j2.xml
│ └── test
│ └── java
│ └── com
│ └── jmendoza
│ └── swa
│ └── hexagonal
│ └── customer
│ └── CustomerApplicationTests.java
├── Order
├── .gitignore
├── README.md
├── application
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── jmendoza
│ │ └── swa
│ │ └── hexagonal
│ │ └── application
│ │ ├── rest
│ │ ├── controller
│ │ │ └── OrderController.java
│ │ ├── request
│ │ │ └── README.md
│ │ └── response
│ │ │ └── CreateOrderResponse.java
│ │ └── soap
│ │ └── README.md
├── common
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── jmendoza
│ │ └── swa
│ │ └── hexagonal
│ │ └── common
│ │ ├── constants
│ │ └── OrderConstanst.java
│ │ ├── customannotations
│ │ └── UseCase.java
│ │ └── exception
│ │ ├── CustomExceptionHandler.java
│ │ ├── ErrorDetails.java
│ │ ├── GlobalException.java
│ │ ├── ParameterNotFoundException.java
│ │ └── ResourceNotFoundException.java
├── configuration
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── com
│ │ │ └── jmendoza
│ │ │ └── swa
│ │ │ └── hexagonal
│ │ │ └── configuration
│ │ │ ├── HexagonalArchitectureConfigurationApplication.java
│ │ │ └── db
│ │ │ └── DataSourceConfig.java
│ │ └── resources
│ │ ├── application.properties
│ │ └── log4j2.xml
├── domain
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── jmendoza
│ │ └── swa
│ │ └── hexagonal
│ │ └── domain
│ │ ├── model
│ │ ├── Order.java
│ │ └── OrderProduct.java
│ │ ├── ports
│ │ ├── inbound
│ │ │ ├── CreateOrderUseCase.java
│ │ │ └── GetOrderUseCase.java
│ │ └── outbound
│ │ │ ├── CreateOrderPort.java
│ │ │ └── GetOrderPort.java
│ │ └── services
│ │ ├── CreateOrderService.java
│ │ └── GetOrderService.java
├── infrastructure
│ ├── .gitignore
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ └── java
│ │ └── com
│ │ └── jmendoza
│ │ └── swa
│ │ └── hexagonal
│ │ └── infrastracture
│ │ ├── databases
│ │ ├── mongo
│ │ │ └── README.md
│ │ └── postgresql
│ │ │ ├── CreateOrderAdapter.java
│ │ │ └── GetOrderAdapter.java
│ │ └── messagebroker
│ │ └── README.md
├── logs
│ ├── Order-2020-06-05-1.log
│ └── Order.log
├── pom.xml
├── postgresql
│ ├── 1-create_table_orders.sql
│ ├── 2-create_sequence_order_id.sql
│ ├── 3-create_function_create_order.sql
│ ├── 4-create_table_order_product.sql
│ ├── 5-create_order_product_id_seq.sql
│ └── 6-create_function_get_order.sql
└── prtsc
│ ├── Order-1.png
│ ├── Order-10.png
│ ├── Order-11.png
│ ├── Order-12.png
│ ├── Order-2.png
│ ├── Order-3.png
│ ├── Order-4.png
│ ├── Order-5.png
│ ├── Order-6.png
│ ├── Order-7.png
│ ├── Order-8.png
│ └── Order-9.png
├── Product
├── .gitignore
├── README.md
├── pom.xml
├── prtsc
│ ├── Product-1.png
│ ├── Product-2.png
│ ├── Product-3.1.png
│ ├── Product-3.2.png
│ ├── Product-3.png
│ └── Product-4.png
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── jmendoza
│ │ │ └── swa
│ │ │ └── hexagonal
│ │ │ └── product
│ │ │ ├── ProductApplication.java
│ │ │ ├── application
│ │ │ ├── rest
│ │ │ │ ├── controller
│ │ │ │ │ └── ProductController.java
│ │ │ │ ├── request
│ │ │ │ │ └── README.md
│ │ │ │ └── response
│ │ │ │ │ └── CreateProductResponse.java
│ │ │ └── soap
│ │ │ │ └── README.md
│ │ │ ├── common
│ │ │ ├── config
│ │ │ │ └── README.md
│ │ │ ├── constants
│ │ │ │ └── ProductConstanst.java
│ │ │ ├── customannotations
│ │ │ │ └── UseCase.java
│ │ │ └── exception
│ │ │ │ ├── CustomExceptionHandler.java
│ │ │ │ ├── ErrorDetails.java
│ │ │ │ ├── GlobalException.java
│ │ │ │ ├── ParameterNotFoundException.java
│ │ │ │ └── ResourceNotFoundException.java
│ │ │ ├── domain
│ │ │ ├── model
│ │ │ │ └── Product.java
│ │ │ ├── ports
│ │ │ │ ├── inbound
│ │ │ │ │ ├── CreateProductUseCase.java
│ │ │ │ │ ├── DeleteProductUseCase.java
│ │ │ │ │ ├── GetProductUseCase.java
│ │ │ │ │ └── GetProductsUseCase.java
│ │ │ │ └── outbound
│ │ │ │ │ ├── CreateProductPort.java
│ │ │ │ │ ├── DeleteProductPort.java
│ │ │ │ │ ├── ExistsProductPort.java
│ │ │ │ │ ├── GetProductIdPort.java
│ │ │ │ │ └── GetProductsPort.java
│ │ │ └── services
│ │ │ │ ├── CreateProductService.java
│ │ │ │ ├── DeleteProductService.java
│ │ │ │ ├── GetProductService.java
│ │ │ │ └── GetProductsService.java
│ │ │ └── infrastructure
│ │ │ ├── databases
│ │ │ ├── mongo
│ │ │ │ ├── CreateProductAdapter.java
│ │ │ │ ├── DeleteProductAdapter.java
│ │ │ │ ├── ExistsProductAdapter.java
│ │ │ │ ├── GetProductIdAdapter.java
│ │ │ │ ├── GetProductsAdapter.java
│ │ │ │ └── ProductRepository.java
│ │ │ └── postgresql
│ │ │ │ └── README.md
│ │ │ └── messagebroker
│ │ │ └── README.md
│ └── resources
│ │ ├── application.properties
│ │ └── log4j2.xml
│ └── test
│ └── java
│ └── com
│ └── jmendoza
│ └── swa
│ └── hexagonal
│ └── product
│ └── ProductApplicationTests.java
├── README.md
├── logs
├── Customer.log
├── Order.log
└── Product.log
└── prtsc
├── Hexa-Arch-DDD-1.png
├── Hexa-Arch-DDD-2.png
├── Hexagonal-Architecture-Microservices.drawio
└── Hexagonal-Architecture-Microservices.jpg
/Customer/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Customer/README.md:
--------------------------------------------------------------------------------
1 | # Customer Microservice
2 |
3 | Example of Customer Microservice applying Hexagonal Architecture pattern, Domain Driven Design (DDD) and SOLID principles.
4 |
5 | This example was implemented with Spring Boot, MongoDB Atlas. The microservices are deployed locally and the DB in the cloud.
6 |
7 | ## MongoDB Atlas
8 | - Signup free at https://www.mongodb.com/cloud/atlas/signup
9 | - Create DATABASE and COLLECTION (Optional)
10 | - Create Database User
11 | - Add your IP Address (public) in IP Whitelist, Network Access
12 |
13 | 
14 |
15 | 
16 |
17 | ## Configure your application.properties
18 |
19 | 
20 |
21 | ## Create Customer
22 |
23 | **Postman**
24 |
25 | 
26 |
27 | 
28 |
29 | 
30 |
31 | **MongoDB Atlas**
32 |
33 | 
34 |
35 | ## Customer Login
36 |
37 | **Postman**
38 |
39 | 
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Customer/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.3.0.RELEASE
9 |
10 |
11 | com.jmendoza.swa.hexagonal
12 | customer
13 | 1.0
14 | customer
15 | Example of Hexagonal Architecture - Customers
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-web
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-log4j
33 |
34 |
35 |
36 |
37 | org.projectlombok
38 | lombok
39 | provided
40 |
41 |
42 | javax.validation
43 | validation-api
44 | 2.0.0.Final
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-data-mongodb
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-starter-security
53 |
54 |
55 | org.springframework.boot
56 | spring-boot-actuator-autoconfigure
57 |
58 |
59 | org.apache.commons
60 | commons-lang3
61 |
62 |
63 | org.modelmapper
64 | modelmapper
65 | 2.3.5
66 |
67 |
68 | org.springframework.boot
69 | spring-boot-starter-log4j2
70 | 2.2.6.RELEASE
71 |
72 |
73 | com.lmax
74 | disruptor
75 | 3.3.6
76 |
77 |
78 | org.zalando
79 | logbook-spring-boot-starter
80 | 2.1.0
81 |
82 |
83 |
84 | org.springframework.boot
85 | spring-boot-starter-test
86 | test
87 |
88 |
89 | org.junit.vintage
90 | junit-vintage-engine
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | org.springframework.boot
100 | spring-boot-maven-plugin
101 |
102 |
103 |
104 |
105 |
106 |
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-1.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-1.1.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-1.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-2.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-3.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-3.1.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-3.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-3.2.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-3.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-3.3.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-3.png
--------------------------------------------------------------------------------
/Customer/prtsc/Customer-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Customer/prtsc/Customer-4.png
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/CustomerApplication.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication(exclude = {
7 | org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
8 | org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class}
9 | )
10 | public class CustomerApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(CustomerApplication.class, args);
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/rest/controller/CustomerController.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.application.rest.controller;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.application.rest.response.CreateCustomerResponse;
4 | import com.jmendoza.swa.hexagonal.customer.application.rest.response.CustomerLoginResponse;
5 | import com.jmendoza.swa.hexagonal.customer.application.rest.response.ResponseMapper;
6 | import com.jmendoza.swa.hexagonal.customer.common.exception.GlobalException;
7 | import com.jmendoza.swa.hexagonal.customer.common.exception.ParameterNotFoundException;
8 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
9 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
10 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.CreateCustomerUseCase;
11 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.CustomerLoginUseCase;
12 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.DeleteCustomerUseCase;
13 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.UpdateCustomerUseCase;
14 | import lombok.AllArgsConstructor;
15 | import org.springframework.http.ResponseEntity;
16 | import org.springframework.web.bind.annotation.*;
17 |
18 | import javax.validation.Valid;
19 |
20 | @RestController
21 | @RequestMapping("/v1/customers")
22 | @AllArgsConstructor
23 | public class CustomerController {
24 |
25 | private final CreateCustomerUseCase createCustomerUseCase;
26 | private final CustomerLoginUseCase customerLoginUseCase;
27 | private final DeleteCustomerUseCase deleteCustomerUseCase;
28 | private final UpdateCustomerUseCase updateCustomerUseCase;
29 |
30 | private final ResponseMapper responseMapper;
31 |
32 | @PostMapping
33 | public ResponseEntity createCustomer(@Valid @RequestBody Customer customer) throws GlobalException, ParameterNotFoundException {
34 | createCustomerUseCase.createCustomer(customer);
35 | return ResponseEntity.ok().body(CreateCustomerResponse.builder().id(customer.getId()).build());
36 | }
37 |
38 | @PostMapping("/login")
39 | public ResponseEntity customerLogin(@Valid @RequestBody Customer customer) throws ResourceNotFoundException, GlobalException, ParameterNotFoundException {
40 | CustomerLoginResponse customerLoginResponse = responseMapper.convertCustomerToCustomerLoginResponse(customerLoginUseCase.customerLogin(customer.getEmail(), customer.getPassword()));
41 | return ResponseEntity.ok().body(customerLoginResponse);
42 | }
43 |
44 | @DeleteMapping("/{id}")
45 | public ResponseEntity deleteCustomer(@PathVariable(value = "id") String id) throws ResourceNotFoundException {
46 | deleteCustomerUseCase.deleteCustomer(id);
47 | return ResponseEntity.noContent().build();
48 | }
49 |
50 | @PutMapping("/{id}")
51 | public ResponseEntity updateCustomer(@PathVariable(value = "id") String id,
52 | @Valid @RequestBody Customer customer) throws ResourceNotFoundException {
53 | updateCustomerUseCase.updateCustomer(id, customer);
54 | return ResponseEntity.noContent().build();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/rest/request/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add specialized requests, to only request minimum data, for example CreateUserRequest.*
2 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/rest/response/CreateCustomerResponse.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.application.rest.response;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | @Getter
9 | @Setter
10 | @Builder
11 | @JsonInclude(JsonInclude.Include.NON_NULL)
12 | public class CreateCustomerResponse {
13 | private String id;
14 | }
15 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/rest/response/CustomerLoginResponse.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.application.rest.response;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Getter;
6 | import lombok.NoArgsConstructor;
7 | import lombok.Setter;
8 |
9 | @Getter
10 | @Setter
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | @JsonInclude(JsonInclude.Include.NON_NULL)
14 | public class CustomerLoginResponse {
15 | private String id;
16 | private String firstName;
17 | private String lastName;
18 | private String email;
19 | private String createdAt;
20 | private String updatedAt;
21 | }
22 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/rest/response/ResponseMapper.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.application.rest.response;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import org.modelmapper.ModelMapper;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class ResponseMapper {
10 |
11 | @Autowired
12 | ModelMapper modelMapper;
13 |
14 | public CustomerLoginResponse convertCustomerToCustomerLoginResponse(Customer customer) {
15 | return modelMapper.map(customer, CustomerLoginResponse.class);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/application/soap/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to access the domain, for example a CustomerController class to expose SOAP.*
2 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/config/CreateBean.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.config;
2 |
3 | import org.modelmapper.ModelMapper;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | @Configuration
8 | public class CreateBean {
9 | @Bean
10 | public ModelMapper modelMapper() {
11 | return new ModelMapper();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/constants/CustomerConstanst.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.constants;
2 |
3 | public class CustomerConstanst {
4 | public static final String CUSTOMER_NOT_FOUND = "Customer not found :: ";
5 | public static final String THIS_EMAIL_IS_ALREADY_REGISTERED = "This email is already registered ";
6 | public static final String THE_PASSWORD_IS_INCORRECT = "The password is incorrect ";
7 | public static final String REQUIRED_PARAMETER = "Required parameter ";
8 | public static final String IS_NOT_PRESENT = " is not present";
9 |
10 | private CustomerConstanst() {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/customannotations/UseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.customannotations;
2 |
3 | import org.springframework.core.annotation.AliasFor;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.lang.annotation.*;
7 |
8 | @Target({ElementType.TYPE})
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Documented
11 | @Component
12 | public @interface UseCase {
13 |
14 | @AliasFor(annotation = Component.class)
15 | String value() default "";
16 | }
17 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/exception/CustomExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.exception;
2 |
3 | import org.apache.logging.log4j.LogManager;
4 | import org.apache.logging.log4j.Logger;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 | import org.springframework.web.context.request.WebRequest;
10 |
11 | import java.util.Date;
12 |
13 | @ControllerAdvice
14 | public class CustomExceptionHandler {
15 |
16 | private static final Logger loggerException = LogManager.getLogger(CustomExceptionHandler.class);
17 |
18 | @ExceptionHandler(ResourceNotFoundException.class)
19 | public ResponseEntity resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
20 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
21 | loggerException.error(ex);
22 | return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
23 | }
24 |
25 | @ExceptionHandler({GlobalException.class})
26 | public ResponseEntity globalExceptionHandler(GlobalException ex, WebRequest request) {
27 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
28 | loggerException.error(ex);
29 | return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
30 | }
31 |
32 | @ExceptionHandler({ParameterNotFoundException.class})
33 | public ResponseEntity parameterNotFoundExceptionHandler(ParameterNotFoundException ex, WebRequest request) {
34 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
35 | loggerException.error(ex);
36 | return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/exception/ErrorDetails.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.exception;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | import java.util.Date;
7 |
8 | @Getter
9 | @AllArgsConstructor
10 | public class ErrorDetails {
11 | private Date timestamp;
12 | private String message;
13 | private String details;
14 | }
15 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/exception/GlobalException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
7 | public class GlobalException extends Exception {
8 | private static final long serialVersionUID = 1L;
9 |
10 | public GlobalException(String message) {
11 | super(message);
12 | }
13 |
14 | public GlobalException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/exception/ParameterNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.BAD_REQUEST)
7 | public class ParameterNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ParameterNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ParameterNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/common/exception/ResourceNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.NOT_FOUND)
7 | public class ResourceNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ResourceNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ResourceNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/model/Customer.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import lombok.ToString;
6 |
7 | @Getter
8 | @Setter
9 | @ToString
10 | public class Customer {
11 | private String id;
12 | private String firstName;
13 | private String lastName;
14 | private String email;
15 | private String password;
16 | private String createdAt;
17 | private String updatedAt;
18 | }
19 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/inbound/CreateCustomerUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.customer.common.exception.ParameterNotFoundException;
5 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
6 |
7 | public interface CreateCustomerUseCase {
8 | void createCustomer(Customer customer) throws GlobalException, ParameterNotFoundException;
9 | }
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/inbound/CustomerLoginUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.customer.common.exception.ParameterNotFoundException;
5 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
7 |
8 | public interface CustomerLoginUseCase {
9 | Customer customerLogin(String email, String password) throws ResourceNotFoundException, GlobalException, ParameterNotFoundException;
10 | }
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/inbound/DeleteCustomerUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
4 |
5 | public interface DeleteCustomerUseCase {
6 | void deleteCustomer(String id) throws ResourceNotFoundException;
7 | }
8 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/inbound/UpdateCustomerUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
4 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
5 |
6 | public interface UpdateCustomerUseCase {
7 | void updateCustomer(String id, Customer customer) throws ResourceNotFoundException;
8 | }
9 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/CreateCustomerPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 |
5 | public interface CreateCustomerPort {
6 | void createCustomer(Customer customer);
7 | }
8 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/DeleteCustomerPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 |
5 | public interface DeleteCustomerPort {
6 | void deleteCustomer(Customer customer);
7 | }
8 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/ExistsCustomerPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | public interface ExistsCustomerPort {
4 | boolean existsByEmail(String email);
5 | }
6 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/GetCustomerEmailPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 |
5 | import java.util.Optional;
6 |
7 | public interface GetCustomerEmailPort {
8 | Optional getCustomerByEmail(String email);
9 | }
10 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/GetCustomerIdPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 |
5 | import java.util.Optional;
6 |
7 | public interface GetCustomerIdPort {
8 | Optional getCustomerById(String id);
9 | }
10 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/PasswordEncodePort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | public interface PasswordEncodePort {
4 | String passwordEncoder(String password);
5 | }
6 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/PasswordMatchesPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | public interface PasswordMatchesPort {
4 |
5 | boolean passwordMatchesPort(CharSequence rawPassword, String encodedPassword);
6 | }
7 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/ports/outbound/UpdateCustomerPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 |
5 | public interface UpdateCustomerPort {
6 | void updateCustomer(Customer customer);
7 | }
8 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/services/CreateCustomerService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.constants.CustomerConstanst;
4 | import com.jmendoza.swa.hexagonal.customer.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.customer.common.exception.GlobalException;
6 | import com.jmendoza.swa.hexagonal.customer.common.exception.ParameterNotFoundException;
7 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
8 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.CreateCustomerUseCase;
9 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.CreateCustomerPort;
10 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.ExistsCustomerPort;
11 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.PasswordEncodePort;
12 | import lombok.AllArgsConstructor;
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | @AllArgsConstructor
16 | @UseCase
17 | public class CreateCustomerService implements CreateCustomerUseCase {
18 |
19 | private CreateCustomerPort createCustomerPort;
20 | private PasswordEncodePort passwordEncodePort;
21 | private ExistsCustomerPort existsCustomerPort;
22 |
23 | @Override
24 | public void createCustomer(Customer customer) throws GlobalException, ParameterNotFoundException {
25 |
26 | if (StringUtils.isBlank(customer.getFirstName()))
27 | getMessageParameterNotFoundException("firstName");
28 | if (StringUtils.isBlank(customer.getLastName()))
29 | getMessageParameterNotFoundException("lastName");
30 | if (StringUtils.isBlank(customer.getEmail()))
31 | getMessageParameterNotFoundException("email");
32 | if (StringUtils.isBlank(customer.getPassword()))
33 | getMessageParameterNotFoundException("password");
34 | if (StringUtils.isBlank(customer.getCreatedAt()))
35 | getMessageParameterNotFoundException("createdAt");
36 |
37 | if (existsCustomerPort.existsByEmail(customer.getEmail()))
38 | throw new GlobalException(CustomerConstanst.THIS_EMAIL_IS_ALREADY_REGISTERED);
39 |
40 | customer.setPassword(passwordEncodePort.passwordEncoder(customer.getPassword()));
41 | createCustomerPort.createCustomer(customer);
42 | }
43 |
44 | private void getMessageParameterNotFoundException(String parameter) throws ParameterNotFoundException {
45 | throw new ParameterNotFoundException(CustomerConstanst.REQUIRED_PARAMETER + "\"" + parameter + "\"" + CustomerConstanst.IS_NOT_PRESENT);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/services/CustomerLoginService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.constants.CustomerConstanst;
4 | import com.jmendoza.swa.hexagonal.customer.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.customer.common.exception.GlobalException;
6 | import com.jmendoza.swa.hexagonal.customer.common.exception.ParameterNotFoundException;
7 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
8 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
9 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.CustomerLoginUseCase;
10 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.GetCustomerEmailPort;
11 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.PasswordMatchesPort;
12 | import lombok.AllArgsConstructor;
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | import java.util.Optional;
16 |
17 | @AllArgsConstructor
18 | @UseCase
19 | public class CustomerLoginService implements CustomerLoginUseCase {
20 |
21 | private GetCustomerEmailPort getCustomerEmailPort;
22 | private PasswordMatchesPort passwordMatchesPort;
23 |
24 | @Override
25 | public Customer customerLogin(String email, String password) throws ResourceNotFoundException, GlobalException, ParameterNotFoundException {
26 |
27 | if (StringUtils.isBlank(email))
28 | getMessageParameterNotFoundException("email");
29 | if (StringUtils.isBlank(password))
30 | getMessageParameterNotFoundException("password");
31 |
32 | Optional customerOptional;
33 | Customer customer = null;
34 | customerOptional = Optional.ofNullable(getCustomerEmailPort.getCustomerByEmail(email).orElseThrow(() -> new ResourceNotFoundException(CustomerConstanst.CUSTOMER_NOT_FOUND + email)));
35 | if (customerOptional.isPresent()) {
36 | customer = customerOptional.get();
37 | if (!passwordMatchesPort.passwordMatchesPort(password, customer.getPassword()))
38 | throw new GlobalException(CustomerConstanst.THE_PASSWORD_IS_INCORRECT);
39 |
40 | customer.setPassword(StringUtils.EMPTY);
41 | }
42 | return customer;
43 | }
44 |
45 | private void getMessageParameterNotFoundException(String parameter) throws ParameterNotFoundException {
46 | throw new ParameterNotFoundException(CustomerConstanst.REQUIRED_PARAMETER + "\"" + parameter + "\"" + CustomerConstanst.IS_NOT_PRESENT);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/services/DeleteCustomerService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.constants.CustomerConstanst;
4 | import com.jmendoza.swa.hexagonal.customer.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
7 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.DeleteCustomerUseCase;
8 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.DeleteCustomerPort;
9 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.GetCustomerIdPort;
10 | import lombok.AllArgsConstructor;
11 |
12 | @AllArgsConstructor
13 | @UseCase
14 | public class DeleteCustomerService implements DeleteCustomerUseCase {
15 |
16 | private GetCustomerIdPort getCustomerIdPort;
17 | private DeleteCustomerPort deleteCustomerPort;
18 |
19 | @Override
20 | public void deleteCustomer(String id) throws ResourceNotFoundException {
21 | Customer customer = getCustomerIdPort.getCustomerById(id)
22 | .orElseThrow(() -> new ResourceNotFoundException(CustomerConstanst.CUSTOMER_NOT_FOUND + id));
23 | deleteCustomerPort.deleteCustomer(customer);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/domain/services/UpdateCustomerService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.common.constants.CustomerConstanst;
4 | import com.jmendoza.swa.hexagonal.customer.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.customer.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
7 | import com.jmendoza.swa.hexagonal.customer.domain.ports.inbound.UpdateCustomerUseCase;
8 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.GetCustomerIdPort;
9 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.PasswordEncodePort;
10 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.UpdateCustomerPort;
11 | import lombok.AllArgsConstructor;
12 | import org.apache.commons.lang3.StringUtils;
13 | import org.modelmapper.Conditions;
14 | import org.modelmapper.ModelMapper;
15 |
16 | @AllArgsConstructor
17 | @UseCase
18 | public class UpdateCustomerService implements UpdateCustomerUseCase {
19 |
20 | private GetCustomerIdPort getCustomerIdPort;
21 | private UpdateCustomerPort updateCustomerPort;
22 | private PasswordEncodePort passwordEncodePort;
23 |
24 | private ModelMapper modelMapper;
25 |
26 | @Override
27 | public void updateCustomer(String id, Customer customer) throws ResourceNotFoundException {
28 | Customer customer1 = getCustomerIdPort.getCustomerById(id)
29 | .orElseThrow(() -> new ResourceNotFoundException(CustomerConstanst.CUSTOMER_NOT_FOUND + id));
30 |
31 | if (!StringUtils.isBlank(customer.getPassword()))
32 | customer.setPassword(passwordEncodePort.passwordEncoder(customer.getPassword()));
33 |
34 | customer.setId(id);
35 | modelMapper.getConfiguration().setPropertyCondition(Conditions.isNotNull());
36 | modelMapper.map(customer, customer1);
37 | updateCustomerPort.updateCustomer(customer1);
38 | }
39 | }
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/CreateCustomerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.CreateCustomerPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class CreateCustomerAdapter implements CreateCustomerPort {
10 | @Autowired
11 | private CustomerRepository customerRepository;
12 |
13 | @Override
14 | public void createCustomer(Customer customer) {
15 | customerRepository.save(customer);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/CustomerRepository.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import org.springframework.data.mongodb.repository.MongoRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.Optional;
8 |
9 | @Repository
10 | public interface CustomerRepository extends MongoRepository {
11 |
12 | boolean existsByEmail(String email);
13 |
14 | Optional findByEmail(String email);
15 | }
16 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/DeleteCustomerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.DeleteCustomerPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class DeleteCustomerAdapter implements DeleteCustomerPort {
10 |
11 | @Autowired
12 | private CustomerRepository customerRepository;
13 |
14 | @Override
15 | public void deleteCustomer(Customer customer) {
16 | customerRepository.delete(customer);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/ExistsCustomerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.ExistsCustomerPort;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class ExistsCustomerAdapter implements ExistsCustomerPort {
9 | @Autowired
10 | private CustomerRepository customerRepository;
11 |
12 | @Override
13 | public boolean existsByEmail(String email) {
14 | return customerRepository.existsByEmail(email);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/GetCustomerEmailAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.GetCustomerEmailPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.Optional;
9 |
10 | @Component
11 | public class GetCustomerEmailAdapter implements GetCustomerEmailPort {
12 | @Autowired
13 | private CustomerRepository customerRepository;
14 |
15 | @Override
16 | public Optional getCustomerByEmail(String email) {
17 | return customerRepository.findByEmail(email);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/GetCustomerIdAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.GetCustomerIdPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.Optional;
9 |
10 | @Component
11 | public class GetCustomerIdAdapter implements GetCustomerIdPort {
12 |
13 | @Autowired
14 | private CustomerRepository customerRepository;
15 |
16 | @Override
17 | public Optional getCustomerById(String id) {
18 | return customerRepository.findById(id);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/mongo/UpdateCustomerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.model.Customer;
4 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.UpdateCustomerPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class UpdateCustomerAdapter implements UpdateCustomerPort {
10 |
11 | @Autowired
12 | private CustomerRepository customerRepository;
13 |
14 | @Override
15 | public void updateCustomer(Customer customer) {
16 | customerRepository.save(customer);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/databases/postgresql/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of DB adapter for example PostgreSQL.*
2 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/messagebroker/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to send messages in a message broker, for example Kafka, RabbitMQ.*
2 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/security/PasswordEncodeAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.security;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.PasswordEncodePort;
4 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class PasswordEncodeAdapter implements PasswordEncodePort {
9 |
10 | BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
11 |
12 | @Override
13 | public String passwordEncoder(String password) {
14 | return bCryptPasswordEncoder.encode(password);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Customer/src/main/java/com/jmendoza/swa/hexagonal/customer/infrastructure/security/PasswordMatchesAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer.infrastructure.security;
2 |
3 | import com.jmendoza.swa.hexagonal.customer.domain.ports.outbound.PasswordMatchesPort;
4 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class PasswordMatchesAdapter implements PasswordMatchesPort {
9 |
10 | BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
11 |
12 | @Override
13 | public boolean passwordMatchesPort(CharSequence rawPassword, String encodedPassword) {
14 | return bCryptPasswordEncoder.matches(rawPassword, encodedPassword);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Customer/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # Application Server
2 | server.port=3000
3 |
4 | # MongoDB Atlas
5 | spring.data.mongodb.uri=mongodb+srv://jmendoza:zuZYkSpMIpSGqgLD@cluster0-7rxkw.mongodb.net/customer?retryWrites=true&w=majority&connectTimeoutMS=60000
6 |
7 | # Logbook: HTTP request and response logging
8 | logging.level.org.zalando.logbook = TRACE
9 |
--------------------------------------------------------------------------------
/Customer/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
10 |
11 | [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%p] [${hostName}] [%t] [%c{3}] ==> %m%n
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 | ${LOG_PATTERN}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Customer/src/test/java/com/jmendoza/swa/hexagonal/customer/CustomerApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.customer;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class CustomerApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Order/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/README.md:
--------------------------------------------------------------------------------
1 | # Orders Microservice
2 |
3 | Example of Orders Microservice applying Hexagonal Architecture pattern, Domain Driven Design (DDD) and SOLID principles. I recommend using this Multiple Modules structure to decouple the code. In this way, part of the code can be migrated to another project in the future.
4 |
5 | This example was implemented with Spring Boot, PostgreSQL. The microservices and the DB are deployed locally.
6 |
7 | ### Start a PostgreSQL Server
8 |
9 | 1. Start a PostgreSQL server instance with Docker Hub
10 |
11 | ```shell
12 | jmendoza@jmendoza-ThinkPad-T420:~$ docker run -d --name postgres -e POSTGRES_PASSWORD=root.jmtizure.k201 postgres
13 | ```
14 |
15 | 2. Start pgAdmin 4 (Container), is a GUI client for PostgreSQL
16 | ```shell
17 | jmendoza@jmendoza-ThinkPad-T420:~$ docker run --name pgadmin4 -p 5050:80 -e "PGADMIN_DEFAULT_EMAIL=jmtizure@gmail.com" -e "PGADMIN_DEFAULT_PASSWORD=123456789" -d dpage/pgadmin4
18 | ```
19 |
20 | 
21 |
22 | 
23 |
24 | 3. Create a new "customers" database
25 |
26 | 
27 |
28 | 4. Execute the following scripts in the public schema.
29 |
30 | 
31 |
32 | ## Configure your application.properties
33 |
34 | Find the IP address of your postgres container
35 |
36 | ```shell
37 | jmendoza@jmendoza-ThinkPad-T420:~$ docker inspect postgres
38 | ```
39 |
40 | 
41 |
42 | 
43 |
44 | ## Create Order
45 |
46 | **Postman**
47 |
48 | 
49 |
50 | ```shell
51 | [2020-06-03 22:35:27.350] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] | {"origin":"remote","type":"request","correlation":"ab783ac9bce46b82","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"POST","uri":"http://localhost:3002/v1/orders","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"content-length":["304"],"content-type":["application/json"],"host":["localhost:3002"],"origin":["chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop"],"postman-token":["32678e26-1a2d-450e-865d-5ea8429540ac"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"]},"body":{"customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-06-03T22:34:12","orderProductList":[{"quantity":"2","productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"quantity":"1","productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}]}}
52 | [2020-06-03 22:35:27.513] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] | {"origin":"local","type":"response","correlation":"ab783ac9bce46b82","duration":255,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Thu, 04 Jun 2020 02:35:27 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"31"}}
53 | ```
54 |
55 | **PostgreSQL**
56 |
57 | 
58 |
59 | 
60 |
61 | ## Get Orders
62 |
63 | **Postman**
64 |
65 | 
66 |
67 | **PostgreSQL**
68 |
69 | 
70 |
71 | 
72 |
73 | ```shell
74 | [2020-06-04 21:52:50.882] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-7] [zalando.logbook.Logbook] | {"origin":"remote","type":"request","correlation":"91d731033f99fbed","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/33","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["8fe08c78-dcb0-9f1e-a0a8-62f731d232a4"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"]}}
75 | [2020-06-04 21:52:50.893] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-7] [zalando.logbook.Logbook] | {"origin":"local","type":"response","correlation":"91d731033f99fbed","duration":11,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 05 Jun 2020 01:52:50 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"33","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-06-03T22:34:12.000+00:00","orderProductList":[{"orderProductId":13,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":14,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
76 | ```
77 |
--------------------------------------------------------------------------------
/Order/application/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/application/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.jmendoza.swa.hexagonal
7 | order
8 | 1.0
9 |
10 |
11 | application
12 | 1.0
13 | jar
14 | hexagonal-architecture-application
15 | Example of Hexagonal Architecture - Application
16 |
17 |
18 |
19 | com.jmendoza.swa.hexagonal
20 | domain
21 | 1.0
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Order/application/src/main/java/com/jmendoza/swa/hexagonal/application/rest/controller/OrderController.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.application.rest.controller;
2 |
3 | import com.jmendoza.swa.hexagonal.application.rest.response.CreateOrderResponse;
4 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
5 | import com.jmendoza.swa.hexagonal.common.exception.ParameterNotFoundException;
6 | import com.jmendoza.swa.hexagonal.common.exception.ResourceNotFoundException;
7 | import com.jmendoza.swa.hexagonal.domain.model.Order;
8 | import com.jmendoza.swa.hexagonal.domain.ports.inbound.CreateOrderUseCase;
9 | import com.jmendoza.swa.hexagonal.domain.ports.inbound.GetOrderUseCase;
10 | import lombok.AllArgsConstructor;
11 | import org.springframework.http.ResponseEntity;
12 | import org.springframework.web.bind.annotation.*;
13 |
14 | import javax.validation.Valid;
15 |
16 | @RestController
17 | @RequestMapping("/v1/orders")
18 | @AllArgsConstructor
19 | public class OrderController {
20 |
21 | private final CreateOrderUseCase createOrderUseCase;
22 | private final GetOrderUseCase getOrderUseCase;
23 |
24 | @PostMapping
25 | public ResponseEntity createOrder(@Valid @RequestBody Order order) throws ParameterNotFoundException, GlobalException {
26 | createOrderUseCase.createOrder(order);
27 | return ResponseEntity.ok().body(CreateOrderResponse.builder().orderId(order.getOrderId()).build());
28 | }
29 |
30 | @GetMapping("/{id}")
31 | public ResponseEntity getOrder(@PathVariable(value = "id") String id) throws ResourceNotFoundException, GlobalException {
32 | return ResponseEntity.ok().body(getOrderUseCase.getOrder(id));
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Order/application/src/main/java/com/jmendoza/swa/hexagonal/application/rest/request/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add specialized requests, to only request minimum data, for example CreateOrderRequest.*
2 |
--------------------------------------------------------------------------------
/Order/application/src/main/java/com/jmendoza/swa/hexagonal/application/rest/response/CreateOrderResponse.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.application.rest.response;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | @Getter
9 | @Setter
10 | @Builder
11 | @JsonInclude(JsonInclude.Include.NON_NULL)
12 | public class CreateOrderResponse {
13 | private String orderId;
14 | }
15 |
--------------------------------------------------------------------------------
/Order/application/src/main/java/com/jmendoza/swa/hexagonal/application/soap/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to access the domain, for example a OrderController class to expose SOAP.*
2 |
--------------------------------------------------------------------------------
/Order/common/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.jmendoza.swa.hexagonal
7 | order
8 | 1.0
9 |
10 |
11 | common
12 | 1.0
13 | jar
14 | hexagonal-architecture-common
15 | Example of Hexagonal Architecture - Common
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/constants/OrderConstanst.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.constants;
2 |
3 | public class OrderConstanst {
4 | public static final String ORDER_NOT_FOUND = "Order not found :: ";
5 | public static final String REQUIRED_PARAMETER = "Required parameter ";
6 | public static final String IS_NOT_PRESENT = " is not present";
7 | public static final String ORDERS_NOT_FOUND = "Orders not found";
8 |
9 | private OrderConstanst() {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/customannotations/UseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.customannotations;
2 |
3 | import org.springframework.core.annotation.AliasFor;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.lang.annotation.*;
7 |
8 | @Target({ElementType.TYPE})
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Documented
11 | @Component
12 | public @interface UseCase {
13 |
14 | @AliasFor(annotation = Component.class)
15 | String value() default "";
16 | }
17 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/exception/CustomExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.exception;
2 |
3 | import org.apache.logging.log4j.LogManager;
4 | import org.apache.logging.log4j.Logger;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 | import org.springframework.web.context.request.WebRequest;
10 |
11 | import java.util.Date;
12 |
13 | @ControllerAdvice
14 | public class CustomExceptionHandler {
15 |
16 | private static final Logger loggerException = LogManager.getLogger(CustomExceptionHandler.class);
17 |
18 | @ExceptionHandler(ResourceNotFoundException.class)
19 | public ResponseEntity resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
20 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
21 | loggerException.error(ex);
22 | return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
23 | }
24 |
25 | @ExceptionHandler({GlobalException.class})
26 | public ResponseEntity globalExceptionHandler(GlobalException ex, WebRequest request) {
27 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
28 | loggerException.error(ex);
29 | return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
30 | }
31 |
32 | @ExceptionHandler({ParameterNotFoundException.class})
33 | public ResponseEntity parameterNotFoundExceptionHandler(ParameterNotFoundException ex, WebRequest request) {
34 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
35 | loggerException.error(ex);
36 | return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/exception/ErrorDetails.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.exception;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | import java.util.Date;
7 |
8 | @Getter
9 | @AllArgsConstructor
10 | public class ErrorDetails {
11 | private Date timestamp;
12 | private String message;
13 | private String details;
14 | }
15 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/exception/GlobalException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
7 | public class GlobalException extends Exception {
8 | private static final long serialVersionUID = 1L;
9 |
10 | public GlobalException(String message) {
11 | super(message);
12 | }
13 |
14 | public GlobalException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/exception/ParameterNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.BAD_REQUEST)
7 | public class ParameterNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ParameterNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ParameterNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Order/common/src/main/java/com/jmendoza/swa/hexagonal/common/exception/ResourceNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.NOT_FOUND)
7 | public class ResourceNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ResourceNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ResourceNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Order/configuration/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/configuration/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.jmendoza.swa.hexagonal
7 | order
8 | 1.0
9 |
10 |
11 | configuration
12 | 1.0
13 | hexagonal-architecture-configuration
14 | Example of Hexagonal Architecture - Configuration
15 |
16 |
17 |
18 | com.jmendoza.swa.hexagonal
19 | application
20 | 1.0
21 |
22 |
23 | com.jmendoza.swa.hexagonal
24 | infrastructure
25 | 1.0
26 |
27 |
28 | org.zalando
29 | logbook-spring-boot-starter
30 | 2.1.0
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Order/configuration/src/main/java/com/jmendoza/swa/hexagonal/configuration/HexagonalArchitectureConfigurationApplication.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.configuration;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication(scanBasePackages = {"com.jmendoza.swa.hexagonal.*"})
7 | public class HexagonalArchitectureConfigurationApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(HexagonalArchitectureConfigurationApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Order/configuration/src/main/java/com/jmendoza/swa/hexagonal/configuration/db/DataSourceConfig.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.configuration.db;
2 |
3 | import org.springframework.boot.context.properties.ConfigurationProperties;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.context.annotation.Primary;
7 | import org.springframework.core.env.Environment;
8 | import org.springframework.jdbc.datasource.DriverManagerDataSource;
9 |
10 | import javax.sql.DataSource;
11 | import java.util.Properties;
12 |
13 | @Configuration
14 | public class DataSourceConfig {
15 |
16 | @Bean
17 | @Primary
18 | @ConfigurationProperties("spring.datasource.tomcat")
19 | public DataSource getDataSource(Environment env) {
20 | final DriverManagerDataSource dataSource = new DriverManagerDataSource();
21 | final Properties properties = new Properties();
22 |
23 | dataSource.setDriverClassName(env.getProperty("spring.datasource.driverClassName"));
24 | dataSource.setUrl(env.getProperty("spring.datasource.url"));
25 | dataSource.setUsername(env.getProperty("spring.datasource.username"));
26 | dataSource.setPassword(env.getProperty("spring.datasource.password"));
27 |
28 | properties.setProperty("initialSize", env.getProperty("spring.datasource.tomcat.initial-size"));
29 | properties.setProperty("minIdle", env.getProperty("spring.datasource.tomcat.min-idle"));
30 | properties.setProperty("maxActive", env.getProperty("spring.datasource.tomcat.max-active"));
31 | properties.setProperty("maxIdle", env.getProperty("spring.datasource.tomcat.max-idle"));
32 | properties.setProperty("minEvictableIdleTimeMillis", env.getProperty("spring.datasource.tomcat.min-evictable-idle-time-millis"));
33 | properties.setProperty("maxWait", env.getProperty("spring.datasource.tomcat.max-idle"));
34 |
35 | dataSource.setConnectionProperties(properties);
36 |
37 | return dataSource;
38 | }
39 | }
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Order/configuration/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | ## Server
2 | server.port=3002
3 |
4 | ## Spring DATASOURCE
5 | spring.datasource.driverClassName=org.postgresql.Driver
6 | spring.datasource.url=jdbc:postgresql://172.17.0.2:5432/customers
7 | spring.datasource.username=postgres
8 | spring.datasource.password=root.jmtizure.k201
9 |
10 | spring.datasource.tomcat.initial-size=15
11 | spring.datasource.tomcat.min-idle=15
12 | spring.datasource.tomcat.max-active=50
13 | spring.datasource.tomcat.max-idle=50
14 | spring.datasource.tomcat.min-evictable-idle-time-millis=60000
15 | spring.datasource.tomcat.max-wait=20000
16 |
17 | # Logbook: HTTP request and response logging
18 | logging.level.org.zalando.logbook = TRACE
19 |
--------------------------------------------------------------------------------
/Order/configuration/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
10 |
11 | [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%p] [${hostName}] [%t] [%c{3}] ===> %m%n
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 | ${LOG_PATTERN}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Order/domain/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/domain/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.jmendoza.swa.hexagonal
7 | order
8 | 1.0
9 |
10 |
11 | domain
12 | 1.0
13 | jar
14 | hexagonal-architecture-domain
15 | Example of Hexagonal Architecture - Domain
16 |
17 |
18 |
19 |
20 | com.jmendoza.swa.hexagonal
21 | common
22 | 1.0
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/model/Order.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import lombok.ToString;
6 |
7 | import java.util.Date;
8 | import java.util.List;
9 |
10 | @Getter
11 | @Setter
12 | @ToString
13 | public class Order {
14 | private String orderId;
15 | private String customerId;
16 | private Date createdAt;
17 | private List orderProductList;
18 | private Double amountOrder;
19 |
20 | public Double getAmountOrder() {
21 | return orderProductList.stream().mapToDouble(OrderProduct::getAmount).sum();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/model/OrderProduct.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import lombok.ToString;
7 |
8 | import java.io.Serializable;
9 |
10 | @Getter
11 | @Setter
12 | @ToString
13 | @AllArgsConstructor
14 | public class OrderProduct implements Serializable {
15 |
16 | private static final long serialVersionUID = 1L;
17 |
18 | private int orderProductId;
19 | private int quantity;
20 | private String productId;
21 | private Double productPrice;
22 |
23 | Double getAmount() {
24 | return productPrice.doubleValue() * this.getQuantity();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/ports/inbound/CreateOrderUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.common.exception.ParameterNotFoundException;
5 | import com.jmendoza.swa.hexagonal.domain.model.Order;
6 |
7 | public interface CreateOrderUseCase {
8 | void createOrder(Order order) throws ParameterNotFoundException, GlobalException;
9 | }
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/ports/inbound/GetOrderUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.common.exception.ResourceNotFoundException;
5 | import com.jmendoza.swa.hexagonal.domain.model.Order;
6 |
7 | public interface GetOrderUseCase {
8 | Order getOrder(String orderId) throws ResourceNotFoundException, GlobalException;
9 | }
10 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/ports/outbound/CreateOrderPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.domain.model.Order;
5 |
6 | public interface CreateOrderPort {
7 | void createOrder(Order order) throws GlobalException;
8 | }
9 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/ports/outbound/GetOrderPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.domain.model.Order;
5 |
6 | public interface GetOrderPort {
7 | Order getOrder(String orderId) throws GlobalException;
8 | }
9 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/services/CreateOrderService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.common.constants.OrderConstanst;
4 | import com.jmendoza.swa.hexagonal.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
6 | import com.jmendoza.swa.hexagonal.common.exception.ParameterNotFoundException;
7 | import com.jmendoza.swa.hexagonal.domain.model.Order;
8 | import com.jmendoza.swa.hexagonal.domain.ports.inbound.CreateOrderUseCase;
9 | import com.jmendoza.swa.hexagonal.domain.ports.outbound.CreateOrderPort;
10 | import lombok.AllArgsConstructor;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | @AllArgsConstructor
14 | @UseCase
15 | public class CreateOrderService implements CreateOrderUseCase {
16 |
17 | private CreateOrderPort createOrderPort;
18 |
19 | @Override
20 | public void createOrder(Order order) throws ParameterNotFoundException, GlobalException {
21 | try {
22 | if (StringUtils.isBlank(order.getCustomerId()))
23 | getMessageParameterNotFoundException("customerId");
24 | if (order.getCreatedAt() == null)
25 | getMessageParameterNotFoundException("createdAt");
26 | if (order.getOrderProductList() == null || order.getOrderProductList().isEmpty())
27 | getMessageParameterNotFoundException("orderProductList");
28 |
29 | //TODO: pending validate orderProductList
30 |
31 | createOrderPort.createOrder(order);
32 | } catch (Exception e) {
33 | throw new GlobalException("createOrder: " + e.getMessage());
34 | }
35 | }
36 |
37 | private void getMessageParameterNotFoundException(String parameter) throws ParameterNotFoundException {
38 | throw new ParameterNotFoundException(OrderConstanst.REQUIRED_PARAMETER + "\"" + parameter + "\"" + OrderConstanst.IS_NOT_PRESENT);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Order/domain/src/main/java/com/jmendoza/swa/hexagonal/domain/services/GetOrderService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.common.constants.OrderConstanst;
4 | import com.jmendoza.swa.hexagonal.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
6 | import com.jmendoza.swa.hexagonal.common.exception.ResourceNotFoundException;
7 | import com.jmendoza.swa.hexagonal.domain.model.Order;
8 | import com.jmendoza.swa.hexagonal.domain.ports.inbound.GetOrderUseCase;
9 | import com.jmendoza.swa.hexagonal.domain.ports.outbound.GetOrderPort;
10 | import lombok.AllArgsConstructor;
11 |
12 | @AllArgsConstructor
13 | @UseCase
14 | public class GetOrderService implements GetOrderUseCase {
15 |
16 | private GetOrderPort getOrderPort;
17 |
18 | @Override
19 | public Order getOrder(String orderId) throws ResourceNotFoundException, GlobalException {
20 | try {
21 | final Order order = getOrderPort.getOrder(orderId);
22 | if (order == null)
23 | throw new ResourceNotFoundException(OrderConstanst.ORDER_NOT_FOUND + orderId);
24 |
25 | return order;
26 | } catch (Exception e) {
27 | throw new GlobalException("getOrder: " + e.getMessage());
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Order/infrastructure/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Order/infrastructure/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.jmendoza.swa.hexagonal
7 | order
8 | 1.0
9 |
10 |
11 | infrastructure
12 | 1.0
13 | jar
14 | hexagonal-architecture-infrastructure
15 | Example of Hexagonal Architecture - Infrastructure
16 |
17 |
18 |
19 | com.jmendoza.swa.hexagonal
20 | domain
21 | 1.0
22 |
23 |
24 | org.springframework.boot
25 | spring-boot-starter-data-jdbc
26 |
27 |
28 | com.zaxxer
29 | HikariCP
30 |
31 |
32 |
33 |
34 | org.postgresql
35 | postgresql
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Order/infrastructure/src/main/java/com/jmendoza/swa/hexagonal/infrastracture/databases/mongo/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of DB adapter for example Mongo.*
2 |
--------------------------------------------------------------------------------
/Order/infrastructure/src/main/java/com/jmendoza/swa/hexagonal/infrastracture/databases/postgresql/CreateOrderAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.infrastracture.databases.postgresql;
2 |
3 | import com.google.gson.Gson;
4 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
5 | import com.jmendoza.swa.hexagonal.domain.model.Order;
6 | import com.jmendoza.swa.hexagonal.domain.ports.outbound.CreateOrderPort;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.jdbc.core.JdbcTemplate;
9 | import org.springframework.stereotype.Component;
10 |
11 | import javax.sql.DataSource;
12 | import java.sql.CallableStatement;
13 | import java.sql.Connection;
14 | import java.sql.Types;
15 |
16 | @Component
17 | public class CreateOrderAdapter implements CreateOrderPort {
18 |
19 | private JdbcTemplate jdbcTemplate;
20 |
21 | @Autowired
22 | public CreateOrderAdapter(final DataSource dataSource) {
23 | jdbcTemplate = new JdbcTemplate(dataSource);
24 | }
25 |
26 | @Override
27 | public void createOrder(Order order) throws GlobalException {
28 |
29 | final String procedureCall = "{ ? = call create_order(?, ?, ?, ?)}";
30 |
31 | try (Connection connection = jdbcTemplate.getDataSource().getConnection();
32 | CallableStatement callableStatement = connection.prepareCall(procedureCall)
33 | ) {
34 | Gson gson = new Gson();
35 | String json = gson.toJson(order.getOrderProductList());
36 |
37 | callableStatement.registerOutParameter(1, Types.BIGINT);
38 | callableStatement.setString(2, order.getCustomerId());
39 | callableStatement.setTimestamp(3, new java.sql.Timestamp(order.getCreatedAt().getTime()));
40 | callableStatement.setDouble(4, order.getAmountOrder());
41 | callableStatement.setString(5, json);
42 |
43 | callableStatement.execute();
44 |
45 | order.setOrderId(Long.toString(callableStatement.getLong(1)));
46 | } catch (Exception e) {
47 | throw new GlobalException("Exception createOrder: " + e.getMessage());
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Order/infrastructure/src/main/java/com/jmendoza/swa/hexagonal/infrastracture/databases/postgresql/GetOrderAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.infrastracture.databases.postgresql;
2 |
3 | import com.google.gson.Gson;
4 | import com.jmendoza.swa.hexagonal.common.exception.GlobalException;
5 | import com.jmendoza.swa.hexagonal.domain.model.Order;
6 | import com.jmendoza.swa.hexagonal.domain.ports.outbound.GetOrderPort;
7 | import org.postgresql.util.PGobject;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.jdbc.core.JdbcTemplate;
10 | import org.springframework.stereotype.Component;
11 |
12 | import javax.sql.DataSource;
13 | import java.sql.CallableStatement;
14 | import java.sql.Connection;
15 | import java.sql.Types;
16 |
17 | @Component
18 | public class GetOrderAdapter implements GetOrderPort {
19 |
20 | private JdbcTemplate jdbcTemplate;
21 |
22 | @Autowired
23 | public GetOrderAdapter(final DataSource dataSource) {
24 | jdbcTemplate = new JdbcTemplate(dataSource);
25 | }
26 |
27 | @Override
28 | public Order getOrder(String orderId) throws GlobalException {
29 |
30 | final String procedureCall = "{ ? = call get_order(?)}";
31 | Order order = null;
32 |
33 | try (Connection connection = jdbcTemplate.getDataSource().getConnection();
34 | CallableStatement callableStatement = connection.prepareCall(procedureCall)
35 | ) {
36 | PGobject pGobject;
37 |
38 | callableStatement.registerOutParameter(1, Types.OTHER);
39 | callableStatement.setLong(2, Long.parseLong(orderId));
40 | callableStatement.execute();
41 |
42 | pGobject = (PGobject) callableStatement.getObject(1);
43 | if (pGobject != null) {
44 | Gson gson = new Gson();
45 | order = gson.fromJson(pGobject.toString(), Order.class);
46 | }
47 |
48 | } catch (Exception e) {
49 | throw new GlobalException("Exception getOrder: " + e.getMessage());
50 | }
51 | return order;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Order/infrastructure/src/main/java/com/jmendoza/swa/hexagonal/infrastracture/messagebroker/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to send messages in a message broker, for example Kafka, RabbitMQ.*
2 |
--------------------------------------------------------------------------------
/Order/logs/Order-2020-06-05-1.log:
--------------------------------------------------------------------------------
1 | [2020-06-05 23:59:49.755] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | Starting HexagonalArchitectureConfigurationApplication on jmendoza-ThinkPad-T420 with PID 12245 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/configuration/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order)
2 | [2020-06-05 23:59:49.773] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | No active profile set, falling back to default profiles: default
3 | [2020-06-05 23:59:50.885] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
4 | [2020-06-05 23:59:50.905] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Finished Spring Data repository scanning in 16ms. Found 0 JDBC repository interfaces.
5 | [2020-06-05 23:59:51.469] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat initialized with port(s): 3002 (http)
6 | [2020-06-05 23:59:51.479] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Initializing ProtocolHandler ["http-nio-3002"]
7 | [2020-06-05 23:59:51.480] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Starting service [Tomcat]
8 | [2020-06-05 23:59:51.481] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] | Starting Servlet engine: [Apache Tomcat/9.0.35]
9 | [2020-06-05 23:59:51.592] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] | Initializing Spring embedded WebApplicationContext
10 | [2020-06-05 23:59:51.593] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] | Root WebApplicationContext: initialization completed in 1550 ms
11 | [2020-06-05 23:59:51.938] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] | Initializing ExecutorService 'applicationTaskExecutor'
12 | [2020-06-05 23:59:52.237] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Starting...
13 | [2020-06-05 23:59:52.439] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Start completed.
14 | [2020-06-05 23:59:52.615] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Starting ProtocolHandler ["http-nio-3002"]
15 | [2020-06-05 23:59:52.692] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat started on port(s): 3002 (http) with context path ''
16 | [2020-06-05 23:59:52.712] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | Started HexagonalArchitectureConfigurationApplication in 3.799 seconds (JVM running for 5.472)
17 |
--------------------------------------------------------------------------------
/Order/logs/Order.log:
--------------------------------------------------------------------------------
1 | [2020-09-18 18:46:56.843] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | Starting HexagonalArchitectureConfigurationApplication on jmendoza-ThinkPad-T420 with PID 31880 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/configuration/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order)
2 | [2020-09-18 18:46:57.023] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | No active profile set, falling back to default profiles: default
3 | [2020-09-18 18:46:58.392] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
4 | [2020-09-18 18:46:58.425] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Finished Spring Data repository scanning in 26ms. Found 0 JDBC repository interfaces.
5 | [2020-09-18 18:46:59.341] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat initialized with port(s): 3002 (http)
6 | [2020-09-18 18:46:59.366] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Initializing ProtocolHandler ["http-nio-3002"]
7 | [2020-09-18 18:46:59.367] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Starting service [Tomcat]
8 | [2020-09-18 18:46:59.368] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] | Starting Servlet engine: [Apache Tomcat/9.0.35]
9 | [2020-09-18 18:46:59.564] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] | Initializing Spring embedded WebApplicationContext
10 | [2020-09-18 18:46:59.565] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] | Root WebApplicationContext: initialization completed in 2475 ms
11 | [2020-09-18 18:46:59.889] [WARN] [jmendoza-ThinkPad-T420] [main] [servlet.context.AnnotationConfigServletWebServerApplicationContext] | Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController' defined in file [/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/application/target/classes/com/jmendoza/swa/hexagonal/application/rest/controller/OrderController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'createOrderService' defined in file [/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/domain/target/classes/com/jmendoza/swa/hexagonal/domain/services/CreateOrderService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.jmendoza.swa.hexagonal.domain.ports.outbound.CreateOrderPort' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
12 | [2020-09-18 18:46:59.895] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Stopping service [Tomcat]
13 | [2020-09-18 18:46:59.929] [INFO] [jmendoza-ThinkPad-T420] [main] [autoconfigure.logging.ConditionEvaluationReportLoggingListener] |
14 |
15 | Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
16 | [2020-09-18 18:47:00.165] [ERROR] [jmendoza-ThinkPad-T420] [main] [boot.diagnostics.LoggingFailureAnalysisReporter] |
17 |
18 | ***************************
19 | APPLICATION FAILED TO START
20 | ***************************
21 |
22 | Description:
23 |
24 | Parameter 0 of constructor in com.jmendoza.swa.hexagonal.domain.services.CreateOrderService required a bean of type 'com.jmendoza.swa.hexagonal.domain.ports.outbound.CreateOrderPort' that could not be found.
25 |
26 |
27 | Action:
28 |
29 | Consider defining a bean of type 'com.jmendoza.swa.hexagonal.domain.ports.outbound.CreateOrderPort' in your configuration.
30 |
31 | [2020-09-18 18:47:00.168] [WARN] [jmendoza-ThinkPad-T420] [main] [springframework.boot.SpringApplication] | Unable to close ApplicationContext
32 | org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration': Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Initialization of bean failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available
33 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
34 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
35 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
36 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
37 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
38 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
39 | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:409) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
40 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
41 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
42 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
43 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
44 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
45 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
46 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
47 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
48 | at org.springframework.context.event.AbstractApplicationEventMulticaster.retrieveApplicationListeners(AbstractApplicationEventMulticaster.java:245) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
49 | at org.springframework.context.event.AbstractApplicationEventMulticaster.getApplicationListeners(AbstractApplicationEventMulticaster.java:197) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
50 | at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:134) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
51 | at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:403) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
52 | at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:360) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
53 | at org.springframework.boot.availability.AvailabilityChangeEvent.publish(AvailabilityChangeEvent.java:81) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
54 | at org.springframework.boot.availability.AvailabilityChangeEvent.publish(AvailabilityChangeEvent.java:67) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
55 | at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.doClose(ServletWebServerApplicationContext.java:167) ~[spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
56 | at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:978) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
57 | at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:814) [spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
58 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:325) [spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
59 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) [spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
60 | at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.3.0.RELEASE.jar:2.3.0.RELEASE]
61 | at com.jmendoza.swa.hexagonal.configuration.HexagonalArchitectureConfigurationApplication.main(HexagonalArchitectureConfigurationApplication.java:10) [classes/:?]
62 | Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration': Initialization of bean failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available
63 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:603) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
64 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
65 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
66 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
67 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
68 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
69 | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:409) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
70 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
71 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
72 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
73 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
74 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
75 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
76 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
77 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
78 | at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:91) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
79 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:109) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
80 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:94) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
81 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:76) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
82 | at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
83 | at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
84 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:431) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
85 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
86 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
87 | ... 28 more
88 | Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available
89 | at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:814) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
90 | at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1282) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
91 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:297) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
92 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
93 | at org.springframework.context.annotation.ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor.postProcessBeforeInitialization(ConfigurationClassPostProcessor.java:456) ~[spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
94 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:416) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
95 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
96 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
97 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
98 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
99 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
100 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
101 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
102 | at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:409) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
103 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
104 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
105 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
106 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
107 | at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
108 | at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
109 | at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
110 | at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
111 | at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:91) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
112 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:109) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
113 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:94) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
114 | at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:76) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
115 | at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
116 | at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299) ~[spring-aop-5.2.6.RELEASE.jar:5.2.6.RELEASE]
117 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:431) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
118 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
119 | at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595) ~[spring-beans-5.2.6.RELEASE.jar:5.2.6.RELEASE]
120 | ... 28 more
121 | [2020-09-18 18:48:24.419] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | Starting HexagonalArchitectureConfigurationApplication on jmendoza-ThinkPad-T420 with PID 32302 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/configuration/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order)
122 | [2020-09-18 18:48:24.437] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | No active profile set, falling back to default profiles: default
123 | [2020-09-18 18:48:25.832] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
124 | [2020-09-18 18:48:25.859] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Finished Spring Data repository scanning in 21ms. Found 0 JDBC repository interfaces.
125 | [2020-09-18 18:48:26.638] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat initialized with port(s): 3002 (http)
126 | [2020-09-18 18:48:26.652] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Initializing ProtocolHandler ["http-nio-3002"]
127 | [2020-09-18 18:48:26.653] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Starting service [Tomcat]
128 | [2020-09-18 18:48:26.669] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] | Starting Servlet engine: [Apache Tomcat/9.0.35]
129 | [2020-09-18 18:48:26.773] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] | Initializing Spring embedded WebApplicationContext
130 | [2020-09-18 18:48:26.774] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] | Root WebApplicationContext: initialization completed in 2003 ms
131 | [2020-09-18 18:48:27.296] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] | Initializing ExecutorService 'applicationTaskExecutor'
132 | [2020-09-18 18:48:27.655] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Starting...
133 | [2020-09-18 18:48:27.963] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Start completed.
134 | [2020-09-18 18:48:28.195] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Starting ProtocolHandler ["http-nio-3002"]
135 | [2020-09-18 18:48:28.279] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat started on port(s): 3002 (http) with context path ''
136 | [2020-09-18 18:48:28.293] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] | Started HexagonalArchitectureConfigurationApplication in 4.93 seconds (JVM running for 6.902)
137 | [2020-09-18 18:53:33.328] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [scheduling.concurrent.ThreadPoolTaskExecutor] | Shutting down ExecutorService 'applicationTaskExecutor'
138 | [2020-09-18 18:53:33.330] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Shutdown initiated...
139 | [2020-09-18 18:53:33.343] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [zaxxer.hikari.HikariDataSource] | HikariPool-1 - Shutdown completed.
140 | [2020-09-18 18:53:59.925] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> Starting HexagonalArchitectureConfigurationApplication on jmendoza-ThinkPad-T420 with PID 32731 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/configuration/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order)
141 | [2020-09-18 18:53:59.973] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> No active profile set, falling back to default profiles: default
142 | [2020-09-18 18:54:01.235] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] ===> Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
143 | [2020-09-18 18:54:01.262] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] ===> Finished Spring Data repository scanning in 22ms. Found 0 JDBC repository interfaces.
144 | [2020-09-18 18:54:02.009] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] ===> Tomcat initialized with port(s): 3002 (http)
145 | [2020-09-18 18:54:02.022] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] ===> Initializing ProtocolHandler ["http-nio-3002"]
146 | [2020-09-18 18:54:02.023] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] ===> Starting service [Tomcat]
147 | [2020-09-18 18:54:02.023] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] ===> Starting Servlet engine: [Apache Tomcat/9.0.35]
148 | [2020-09-18 18:54:02.115] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] ===> Initializing Spring embedded WebApplicationContext
149 | [2020-09-18 18:54:02.115] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] ===> Root WebApplicationContext: initialization completed in 1863 ms
150 | [2020-09-18 18:54:02.541] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] ===> Initializing ExecutorService 'applicationTaskExecutor'
151 | [2020-09-18 18:54:02.780] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] ===> HikariPool-1 - Starting...
152 | [2020-09-18 18:54:02.994] [INFO] [jmendoza-ThinkPad-T420] [main] [zaxxer.hikari.HikariDataSource] ===> HikariPool-1 - Start completed.
153 | [2020-09-18 18:54:03.139] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] ===> Starting ProtocolHandler ["http-nio-3002"]
154 | [2020-09-18 18:54:03.174] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] ===> Tomcat started on port(s): 3002 (http) with context path ''
155 | [2020-09-18 18:54:03.189] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> Started HexagonalArchitectureConfigurationApplication in 3.973 seconds (JVM running for 5.737)
156 | [2020-09-18 18:55:19.058] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [[Tomcat].[localhost].[/]] ===> Initializing Spring DispatcherServlet 'dispatcherServlet'
157 | [2020-09-18 18:55:19.059] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [web.servlet.DispatcherServlet] ===> Initializing Servlet 'dispatcherServlet'
158 | [2020-09-18 18:55:19.109] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [web.servlet.DispatcherServlet] ===> Completed initialization in 49 ms
159 | [2020-09-18 18:55:19.415] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"e7f998e53c885f2d","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"POST","uri":"http://localhost:3002/v1/orders","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"content-length":["304"],"content-type":["application/json"],"host":["localhost:3002"],"origin":["chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop"],"postman-token":["ac8ea573-8463-712c-1cd5-8c575789dbc3"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]},"body":{"customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:10:12","orderProductList":[{"quantity":"2","productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"quantity":"1","productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}]}}
160 | [2020-09-18 18:55:19.876] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"e7f998e53c885f2d","duration":682,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 22:55:19 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"36"}}
161 | [2020-09-18 18:55:43.478] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-2] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"90a2cd79829db3ea","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/36","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["31da7306-62b6-22f8-37e0-2a251f892506"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
162 | [2020-09-18 18:55:43.526] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-2] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"90a2cd79829db3ea","duration":48,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 22:55:43 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"36","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:10:12.000+00:00","orderProductList":[{"orderProductId":19,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":20,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
163 | [2020-09-18 18:55:49.901] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-3] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"9e2e64d736239f87","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/37","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["f9b7108d-6dd7-a3a8-acf5-57fed7be75f8"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
164 | [2020-09-18 18:55:49.924] [ERROR] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-3] [common.exception.CustomExceptionHandler] ===> com.jmendoza.swa.hexagonal.common.exception.GlobalException: getOrder: Order not found :: 37
165 | [2020-09-18 18:55:49.930] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-3] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"9e2e64d736239f87","duration":30,"protocol":"HTTP/1.1","status":500,"headers":{"Connection":["close"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 22:55:49 GMT"],"Transfer-Encoding":["chunked"]},"body":{"timestamp":"2020-09-18T22:55:49.924+00:00","message":"getOrder: Order not found :: 37","details":"uri=/v1/orders/37"}}
166 | [2020-09-18 18:55:57.137] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-4] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"8646799f85278cc7","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/36","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["676e731d-bfde-122b-485a-c0d11ebfca11"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
167 | [2020-09-18 18:55:57.145] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-4] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"8646799f85278cc7","duration":9,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 22:55:57 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"36","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:10:12.000+00:00","orderProductList":[{"orderProductId":19,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":20,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
168 | [2020-09-18 18:57:04.151] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [scheduling.concurrent.ThreadPoolTaskExecutor] ===> Shutting down ExecutorService 'applicationTaskExecutor'
169 | [2020-09-18 18:57:04.153] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [zaxxer.hikari.HikariDataSource] ===> HikariPool-1 - Shutdown initiated...
170 | [2020-09-18 18:57:04.179] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [zaxxer.hikari.HikariDataSource] ===> HikariPool-1 - Shutdown completed.
171 | [2020-09-18 19:12:00.790] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> Starting HexagonalArchitectureConfigurationApplication on jmendoza-ThinkPad-T420 with PID 1942 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order/configuration/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Order)
172 | [2020-09-18 19:12:00.804] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> No active profile set, falling back to default profiles: default
173 | [2020-09-18 19:12:01.880] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] ===> Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
174 | [2020-09-18 19:12:01.899] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] ===> Finished Spring Data repository scanning in 14ms. Found 0 JDBC repository interfaces.
175 | [2020-09-18 19:12:02.490] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] ===> Tomcat initialized with port(s): 3002 (http)
176 | [2020-09-18 19:12:02.501] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] ===> Initializing ProtocolHandler ["http-nio-3002"]
177 | [2020-09-18 19:12:02.502] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] ===> Starting service [Tomcat]
178 | [2020-09-18 19:12:02.502] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] ===> Starting Servlet engine: [Apache Tomcat/9.0.35]
179 | [2020-09-18 19:12:02.601] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] ===> Initializing Spring embedded WebApplicationContext
180 | [2020-09-18 19:12:02.601] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] ===> Root WebApplicationContext: initialization completed in 1564 ms
181 | [2020-09-18 19:12:02.948] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] ===> Initializing ExecutorService 'applicationTaskExecutor'
182 | [2020-09-18 19:12:03.469] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] ===> Starting ProtocolHandler ["http-nio-3002"]
183 | [2020-09-18 19:12:03.488] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] ===> Tomcat started on port(s): 3002 (http) with context path ''
184 | [2020-09-18 19:12:03.500] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.configuration.HexagonalArchitectureConfigurationApplication] ===> Started HexagonalArchitectureConfigurationApplication in 3.643 seconds (JVM running for 5.417)
185 | [2020-09-18 19:12:41.175] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [[Tomcat].[localhost].[/]] ===> Initializing Spring DispatcherServlet 'dispatcherServlet'
186 | [2020-09-18 19:12:41.176] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [web.servlet.DispatcherServlet] ===> Initializing Servlet 'dispatcherServlet'
187 | [2020-09-18 19:12:41.192] [INFO] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [web.servlet.DispatcherServlet] ===> Completed initialization in 16 ms
188 | [2020-09-18 19:12:41.344] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"808a493284b4f071","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/36","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["169d375b-96ac-4c72-0fc0-6b9afe8dfc58"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
189 | [2020-09-18 19:12:41.495] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-1] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"808a493284b4f071","duration":259,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 23:12:41 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"36","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:10:12.000+00:00","orderProductList":[{"orderProductId":19,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":20,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
190 | [2020-09-18 19:12:56.461] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-2] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"b611a2d00884de84","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"POST","uri":"http://localhost:3002/v1/orders","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"content-length":["304"],"content-type":["application/json"],"host":["localhost:3002"],"origin":["chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop"],"postman-token":["d55bc226-c078-a37b-cad2-19222f8bc47b"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]},"body":{"customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:30:12","orderProductList":[{"quantity":"2","productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"quantity":"1","productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}]}}
191 | [2020-09-18 19:12:56.552] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-2] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"b611a2d00884de84","duration":93,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 23:12:56 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"37"}}
192 | [2020-09-18 19:13:03.370] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-3] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"88a9e0808f9cc457","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/37","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["cefcfe7f-4d3a-b730-02c7-851e5b2ba822"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
193 | [2020-09-18 19:13:03.388] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-3] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"88a9e0808f9cc457","duration":18,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 23:13:03 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"37","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:30:12.000+00:00","orderProductList":[{"orderProductId":21,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":22,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
194 | [2020-09-18 19:13:06.905] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-4] [zalando.logbook.Logbook] ===> {"origin":"remote","type":"request","correlation":"820cbaa656edc6c7","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3002/v1/orders/37","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3002"],"postman-token":["ab49a767-8eba-61f4-557a-e999b2b4c07d"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36"]}}
195 | [2020-09-18 19:13:06.923] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3002-exec-4] [zalando.logbook.Logbook] ===> {"origin":"local","type":"response","correlation":"820cbaa656edc6c7","duration":19,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 18 Sep 2020 23:13:06 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"orderId":"37","customerId":"5ed047dda2923f1ac2c64463","createdAt":"2020-09-18T00:30:12.000+00:00","orderProductList":[{"orderProductId":21,"quantity":2,"productId":"5ed31ddb669529409edc2fd0","productPrice":1099.51},{"orderProductId":22,"quantity":1,"productId":"5ed31cb5669529409edc2fcf","productPrice":2199.99}],"amountOrder":4399.01}}
196 | [2020-09-18 19:13:11.071] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [scheduling.concurrent.ThreadPoolTaskExecutor] ===> Shutting down ExecutorService 'applicationTaskExecutor'
197 |
--------------------------------------------------------------------------------
/Order/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.3.0.RELEASE
9 |
10 |
11 |
12 | com.jmendoza.swa.hexagonal
13 | order
14 | 1.0
15 | pom
16 | hexagonal-architecture-order
17 | Example of Hexagonal Architecture - Orders
18 |
19 |
20 | 1.8
21 |
22 |
23 |
24 | application
25 | common
26 | configuration
27 | domain
28 | infrastructure
29 |
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-logging
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-log4j
43 |
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-log4j2
49 | 2.2.6.RELEASE
50 |
51 |
52 | com.lmax
53 | disruptor
54 | 3.3.6
55 |
56 |
57 | org.projectlombok
58 | lombok
59 | 1.18.12
60 | provided
61 |
62 |
63 | javax.validation
64 | validation-api
65 | 2.0.0.Final
66 |
67 |
68 | org.apache.commons
69 | commons-lang3
70 | 3.10
71 |
72 |
73 | org.modelmapper
74 | modelmapper
75 | 2.3.5
76 |
77 |
78 | com.google.code.gson
79 | gson
80 | 2.8.9
81 |
82 |
83 |
84 | org.springframework.boot
85 | spring-boot-starter-test
86 | test
87 |
88 |
89 | org.junit.vintage
90 | junit-vintage-engine
91 |
92 |
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Order/postgresql/1-create_table_orders.sql:
--------------------------------------------------------------------------------
1 | -- Table: public.ORDERS
2 |
3 | -- DROP TABLE public."ORDERS";
4 |
5 | CREATE TABLE public."ORDERS"
6 | (
7 | order_id bigint NOT NULL,
8 | customer_id character varying COLLATE pg_catalog."default" NOT NULL,
9 | created_at timestamp with time zone NOT NULL,
10 | amount_order double precision NOT NULL,
11 | CONSTRAINT "ORDERS_pkey" PRIMARY KEY (order_id)
12 | )
13 |
14 | TABLESPACE pg_default;
15 |
16 | ALTER TABLE public."ORDERS"
17 | OWNER to postgres;
18 |
19 | GRANT ALL ON TABLE public."ORDERS" TO postgres;
--------------------------------------------------------------------------------
/Order/postgresql/2-create_sequence_order_id.sql:
--------------------------------------------------------------------------------
1 | -- SEQUENCE: public.order_id_seq
2 |
3 | -- DROP SEQUENCE public.order_id_seq;
4 |
5 | CREATE SEQUENCE public.order_id_seq
6 | INCREMENT 1
7 | START 1
8 | MINVALUE 1
9 | MAXVALUE 9223372036854775807
10 | CACHE 1;
11 |
12 | ALTER SEQUENCE public.order_id_seq
13 | OWNER TO postgres;
14 |
15 | GRANT ALL ON SEQUENCE public.order_id_seq TO postgres;
--------------------------------------------------------------------------------
/Order/postgresql/3-create_function_create_order.sql:
--------------------------------------------------------------------------------
1 | -- FUNCTION: public.create_order(character varying, timestamp with time zone, double precision, text)
2 |
3 | -- DROP FUNCTION public.create_order(character varying, timestamp with time zone, double precision, text);
4 |
5 | CREATE OR REPLACE FUNCTION public.create_order(
6 | p_customer_id character varying,
7 | p_created_at timestamp with time zone,
8 | p_amount_order double precision,
9 | p_order_product text)
10 | RETURNS bigint
11 | LANGUAGE 'plpgsql'
12 |
13 | COST 100
14 | VOLATILE
15 |
16 | AS $BODY$
17 | DECLARE
18 | p_order_id bigint;
19 | p_order_product_id bigint;
20 | p_json json;
21 | BEGIN
22 | p_order_id := nextval('order_id_seq');
23 | INSERT INTO public."ORDERS"(
24 | order_id, customer_id, created_at, amount_order)
25 | VALUES (p_order_id, p_customer_id, p_created_at, p_amount_order);
26 |
27 | FOR p_json IN SELECT * FROM json_array_elements(p_order_product::json)
28 | LOOP
29 | p_order_product_id := nextval('order_product_id_seq');
30 | INSERT INTO public."ORDERS_PRODUCTS"(
31 | order_product_id, quantity, product_id, product_price, order_id)
32 | VALUES (p_order_product_id, CAST (p_json->>'quantity' AS bigint) , p_json->>'productId', CAST(p_json->>'productPrice' AS double precision), p_order_id);
33 | END LOOP;
34 |
35 | RETURN p_order_id;
36 |
37 | END;
38 | $BODY$;
39 |
40 | ALTER FUNCTION public.create_order(character varying, timestamp with time zone, double precision, text)
41 | OWNER TO postgres;
42 |
--------------------------------------------------------------------------------
/Order/postgresql/4-create_table_order_product.sql:
--------------------------------------------------------------------------------
1 | -- Table: public.ORDERS_PRODUCTS
2 |
3 | -- DROP TABLE public."ORDERS_PRODUCTS";
4 |
5 | CREATE TABLE public."ORDERS_PRODUCTS"
6 | (
7 | order_product_id bigint NOT NULL,
8 | quantity bigint NOT NULL,
9 | product_id character varying COLLATE pg_catalog."default" NOT NULL,
10 | product_price double precision NOT NULL,
11 | order_id bigint NOT NULL,
12 | CONSTRAINT "ORDERS_PRODUCTS_pkey" PRIMARY KEY (order_product_id),
13 | CONSTRAINT order_id_fk FOREIGN KEY (order_id)
14 | REFERENCES public."ORDERS" (order_id) MATCH SIMPLE
15 | ON UPDATE NO ACTION
16 | ON DELETE NO ACTION
17 | NOT VALID
18 | )
19 |
20 | TABLESPACE pg_default;
21 |
22 | ALTER TABLE public."ORDERS_PRODUCTS"
23 | OWNER to postgres;
24 |
25 | GRANT ALL ON TABLE public."ORDERS_PRODUCTS" TO postgres;
--------------------------------------------------------------------------------
/Order/postgresql/5-create_order_product_id_seq.sql:
--------------------------------------------------------------------------------
1 | -- SEQUENCE: public.order_product_id_seq
2 |
3 | -- DROP SEQUENCE public.order_product_id_seq;
4 |
5 | CREATE SEQUENCE public.order_product_id_seq
6 | INCREMENT 1
7 | START 1
8 | MINVALUE 1
9 | MAXVALUE 9223372036854775807
10 | CACHE 1;
11 |
12 | ALTER SEQUENCE public.order_product_id_seq
13 | OWNER TO postgres;
14 |
15 | GRANT ALL ON SEQUENCE public.order_product_id_seq TO postgres;
--------------------------------------------------------------------------------
/Order/postgresql/6-create_function_get_order.sql:
--------------------------------------------------------------------------------
1 | -- FUNCTION: public.get_order(bigint)
2 |
3 | -- DROP FUNCTION public.get_order(bigint);
4 |
5 | CREATE OR REPLACE FUNCTION public.get_order(
6 | p_order_id bigint)
7 | RETURNS json
8 | LANGUAGE 'plpgsql'
9 |
10 | COST 100
11 | VOLATILE
12 |
13 | AS $BODY$
14 | DECLARE
15 | json_op json;
16 | json_result json;
17 | BEGIN
18 |
19 | json_op:= (SELECT
20 | json_agg(
21 | json_build_object(
22 | 'orderProductId',OP.order_product_id,
23 | 'quantity', OP.quantity,
24 | 'productId',OP.product_id,
25 | 'productPrice',OP.product_price))
26 | FROM public."ORDERS_PRODUCTS" AS OP
27 | WHERE OP.order_id = p_order_id);
28 |
29 | json_result:= (SELECT
30 | json_build_object(
31 | 'orderId', O.order_id,
32 | 'customerId', O.customer_id,
33 | 'createdAt', O.created_at,
34 | 'orderProductList',json_op,
35 | 'amountOrder', O.amount_order)
36 | FROM public."ORDERS" AS O
37 | WHERE O.order_id = p_order_id);
38 |
39 | RETURN json_result;
40 |
41 | END;
42 | $BODY$;
43 |
44 | ALTER FUNCTION public.get_order(bigint)
45 | OWNER TO postgres;
46 |
47 | GRANT EXECUTE ON FUNCTION public.get_order(bigint) TO postgres;
48 |
49 | GRANT EXECUTE ON FUNCTION public.get_order(bigint) TO PUBLIC;
50 |
51 |
--------------------------------------------------------------------------------
/Order/prtsc/Order-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-1.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-10.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-11.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-12.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-2.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-3.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-4.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-5.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-6.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-7.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-8.png
--------------------------------------------------------------------------------
/Order/prtsc/Order-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Order/prtsc/Order-9.png
--------------------------------------------------------------------------------
/Product/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
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 |
30 | ### VS Code ###
31 | .vscode/
32 |
--------------------------------------------------------------------------------
/Product/README.md:
--------------------------------------------------------------------------------
1 | # Products Microservice
2 |
3 | Example of Products Microservice applying Hexagonal Architecture pattern, Domain Driven Design (DDD) and SOLID principles.
4 |
5 | This example was implemented with Spring Boot, MongoDB Atlas. The microservices are deployed locally and the DB in the cloud.
6 |
7 | ## MongoDB Atlas
8 | - Signup free at https://www.mongodb.com/cloud/atlas/signup
9 | - Create DATABASE and COLLECTION (Optional)
10 | - Create Database User
11 | - Add your IP Address (public) in IP Whitelist, Network Access
12 |
13 | 
14 |
15 | ## Configure your application.properties
16 |
17 | 
18 |
19 | ## Create Products
20 |
21 | **Postman**
22 |
23 | 
24 |
25 | 
26 |
27 |
28 | **MongoDB Atlas**
29 |
30 | 
31 |
32 | ## Get Products
33 |
34 | **Postman**
35 |
36 | 
37 |
38 |
--------------------------------------------------------------------------------
/Product/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 2.3.0.RELEASE
9 |
10 |
11 | com.jmendoza.swa.hexagonal
12 | product
13 | 1.0
14 | product
15 | Example of Hexagonal Architecture - Products
16 |
17 |
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-web
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-starter-logging
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter-log4j
33 |
34 |
35 |
36 |
37 | org.projectlombok
38 | lombok
39 | provided
40 |
41 |
42 | javax.validation
43 | validation-api
44 | 2.0.0.Final
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-data-mongodb
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-actuator-autoconfigure
53 |
54 |
55 | org.apache.commons
56 | commons-lang3
57 |
58 |
59 | org.modelmapper
60 | modelmapper
61 | 2.3.5
62 |
63 |
64 | org.springframework.boot
65 | spring-boot-starter-log4j2
66 | 2.2.6.RELEASE
67 |
68 |
69 | com.lmax
70 | disruptor
71 | 3.3.6
72 |
73 |
74 | org.zalando
75 | logbook-spring-boot-starter
76 | 2.1.0
77 |
78 |
79 |
80 | org.springframework.boot
81 | spring-boot-starter-test
82 | test
83 |
84 |
85 | org.junit.vintage
86 | junit-vintage-engine
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | org.springframework.boot
96 | spring-boot-maven-plugin
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Product/prtsc/Product-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-1.png
--------------------------------------------------------------------------------
/Product/prtsc/Product-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-2.png
--------------------------------------------------------------------------------
/Product/prtsc/Product-3.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-3.1.png
--------------------------------------------------------------------------------
/Product/prtsc/Product-3.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-3.2.png
--------------------------------------------------------------------------------
/Product/prtsc/Product-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-3.png
--------------------------------------------------------------------------------
/Product/prtsc/Product-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/Product/prtsc/Product-4.png
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/ProductApplication.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ProductApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ProductApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/application/rest/controller/ProductController.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.application.rest.controller;
2 |
3 | import com.jmendoza.swa.hexagonal.product.application.rest.response.CreateProductResponse;
4 | import com.jmendoza.swa.hexagonal.product.common.exception.GlobalException;
5 | import com.jmendoza.swa.hexagonal.product.common.exception.ParameterNotFoundException;
6 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
7 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
8 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.CreateProductUseCase;
9 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.DeleteProductUseCase;
10 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.GetProductUseCase;
11 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.GetProductsUseCase;
12 | import lombok.AllArgsConstructor;
13 | import org.springframework.http.ResponseEntity;
14 | import org.springframework.web.bind.annotation.*;
15 |
16 | import javax.validation.Valid;
17 | import java.util.List;
18 |
19 | @RestController
20 | @RequestMapping("/v1/products")
21 | @AllArgsConstructor
22 | public class ProductController {
23 |
24 | private final CreateProductUseCase createProductUseCase;
25 | private final DeleteProductUseCase deleteProductUseCase;
26 | private final GetProductsUseCase getProductsUseCase;
27 | private final GetProductUseCase getProductUseCase;
28 |
29 | @PostMapping
30 | public ResponseEntity createProduct(@Valid @RequestBody Product product) throws GlobalException, ParameterNotFoundException {
31 | createProductUseCase.createProduct(product);
32 | return ResponseEntity.ok().body(CreateProductResponse.builder().id(product.getId()).build());
33 | }
34 |
35 | @DeleteMapping("/{id}")
36 | public ResponseEntity deleteCustomer(@PathVariable(value = "id") String id) throws ResourceNotFoundException {
37 | deleteProductUseCase.deleteProduct(id);
38 | return ResponseEntity.noContent().build();
39 | }
40 |
41 | @GetMapping
42 | public ResponseEntity> getProducts() throws ResourceNotFoundException {
43 | List productList = getProductsUseCase.getProducts();
44 | return ResponseEntity.ok().body(productList);
45 | }
46 |
47 | @GetMapping("/{id}")
48 | public ResponseEntity getProduct(@PathVariable(value = "id") String id) throws ResourceNotFoundException {
49 | Product product = getProductUseCase.getProduct(id);
50 | return ResponseEntity.ok().body(product);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/application/rest/request/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add specialized requests, to only request minimum data, for example CreateProductRequest.*
2 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/application/rest/response/CreateProductResponse.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.application.rest.response;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import lombok.Builder;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | @Getter
9 | @Setter
10 | @Builder
11 | @JsonInclude(JsonInclude.Include.NON_NULL)
12 | public class CreateProductResponse {
13 | private String id;
14 | }
15 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/application/soap/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to access the domain, for example a ProductController class to expose SOAP.*
2 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/config/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add settings for the infrastructure layer or the application layer.*
2 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/constants/ProductConstanst.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.constants;
2 |
3 | public class ProductConstanst {
4 | public static final String PRODUCT_NOT_FOUND = "Product not found :: ";
5 | public static final String REQUIRED_PARAMETER = "Required parameter ";
6 | public static final String IS_NOT_PRESENT = " is not present";
7 | public static final double D_2 = 0.0;
8 | public static final int INT = 0;
9 | public static final String THIS_PRODUCT_IS_ALREADY_REGISTERED = "This Product is already registered ";
10 | public static final String PRODUCTS_NOT_FOUND = "Products not found";
11 |
12 | private ProductConstanst() {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/customannotations/UseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.customannotations;
2 |
3 | import org.springframework.core.annotation.AliasFor;
4 | import org.springframework.stereotype.Component;
5 |
6 | import java.lang.annotation.*;
7 |
8 | @Target({ElementType.TYPE})
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Documented
11 | @Component
12 | public @interface UseCase {
13 |
14 | @AliasFor(annotation = Component.class)
15 | String value() default "";
16 | }
17 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/exception/CustomExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.exception;
2 |
3 | import org.apache.logging.log4j.LogManager;
4 | import org.apache.logging.log4j.Logger;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.web.bind.annotation.ControllerAdvice;
8 | import org.springframework.web.bind.annotation.ExceptionHandler;
9 | import org.springframework.web.context.request.WebRequest;
10 |
11 | import java.util.Date;
12 |
13 | @ControllerAdvice
14 | public class CustomExceptionHandler {
15 |
16 | private static final Logger loggerException = LogManager.getLogger(CustomExceptionHandler.class);
17 |
18 | @ExceptionHandler(ResourceNotFoundException.class)
19 | public ResponseEntity resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
20 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
21 | loggerException.error(ex);
22 | return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
23 | }
24 |
25 | @ExceptionHandler({GlobalException.class})
26 | public ResponseEntity globalExceptionHandler(GlobalException ex, WebRequest request) {
27 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
28 | loggerException.error(ex);
29 | return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
30 | }
31 |
32 | @ExceptionHandler({ParameterNotFoundException.class})
33 | public ResponseEntity parameterNotFoundExceptionHandler(ParameterNotFoundException ex, WebRequest request) {
34 | ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
35 | loggerException.error(ex);
36 | return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/exception/ErrorDetails.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.exception;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 |
6 | import java.util.Date;
7 |
8 | @Getter
9 | @AllArgsConstructor
10 | public class ErrorDetails {
11 | private Date timestamp;
12 | private String message;
13 | private String details;
14 | }
15 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/exception/GlobalException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
7 | public class GlobalException extends Exception {
8 | private static final long serialVersionUID = 1L;
9 |
10 | public GlobalException(String message) {
11 | super(message);
12 | }
13 |
14 | public GlobalException(String message, Throwable cause) {
15 | super(message, cause);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/exception/ParameterNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.BAD_REQUEST)
7 | public class ParameterNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ParameterNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ParameterNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/common/exception/ResourceNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.common.exception;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.bind.annotation.ResponseStatus;
5 |
6 | @ResponseStatus(value = HttpStatus.NOT_FOUND)
7 | public class ResourceNotFoundException extends Exception {
8 |
9 | private static final long serialVersionUID = 1L;
10 |
11 | public ResourceNotFoundException(String message) {
12 | super(message);
13 | }
14 |
15 | public ResourceNotFoundException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/model/Product.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.model;
2 |
3 | import lombok.Getter;
4 | import lombok.Setter;
5 | import lombok.ToString;
6 |
7 | @Getter
8 | @Setter
9 | @ToString
10 | public class Product {
11 | private String id;
12 | private String productName;
13 | private String productDescription;
14 | private Double price;
15 | private String createdAt;
16 | private String serialNumber;
17 | }
18 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/inbound/CreateProductUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.exception.GlobalException;
4 | import com.jmendoza.swa.hexagonal.product.common.exception.ParameterNotFoundException;
5 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
6 |
7 | public interface CreateProductUseCase {
8 | void createProduct(Product product) throws ParameterNotFoundException, GlobalException;
9 | }
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/inbound/DeleteProductUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
4 |
5 | public interface DeleteProductUseCase {
6 | void deleteProduct(String id) throws ResourceNotFoundException;
7 | }
8 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/inbound/GetProductUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
4 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
5 |
6 | public interface GetProductUseCase {
7 |
8 | Product getProduct(String id) throws ResourceNotFoundException;
9 | }
10 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/inbound/GetProductsUseCase.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.inbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
4 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
5 |
6 | import java.util.List;
7 |
8 | public interface GetProductsUseCase {
9 | List getProducts() throws ResourceNotFoundException;
10 | }
11 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/outbound/CreateProductPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 |
5 | public interface CreateProductPort {
6 | void createProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/outbound/DeleteProductPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 |
5 | public interface DeleteProductPort {
6 | void deleteProduct(Product product);
7 | }
8 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/outbound/ExistsProductPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.outbound;
2 |
3 | public interface ExistsProductPort {
4 | boolean existsBySerialNumber(String serialNumber);
5 | }
6 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/outbound/GetProductIdPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 |
5 | import java.util.Optional;
6 |
7 | public interface GetProductIdPort {
8 | Optional getProductById(String id);
9 | }
10 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/ports/outbound/GetProductsPort.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.ports.outbound;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 |
5 | import java.util.List;
6 |
7 | public interface GetProductsPort {
8 | List getProducts();
9 | }
10 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/services/CreateProductService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.constants.ProductConstanst;
4 | import com.jmendoza.swa.hexagonal.product.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.product.common.exception.GlobalException;
6 | import com.jmendoza.swa.hexagonal.product.common.exception.ParameterNotFoundException;
7 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
8 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.CreateProductUseCase;
9 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.CreateProductPort;
10 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.ExistsProductPort;
11 | import lombok.AllArgsConstructor;
12 | import org.apache.commons.lang3.StringUtils;
13 |
14 | @AllArgsConstructor
15 | @UseCase
16 | public class CreateProductService implements CreateProductUseCase {
17 |
18 | private CreateProductPort createProductPort;
19 | private ExistsProductPort existsProductPort;
20 |
21 | @Override
22 | public void createProduct(Product product) throws ParameterNotFoundException, GlobalException {
23 |
24 | if (StringUtils.isBlank(product.getProductName()))
25 | getMessageParameterNotFoundException("productName");
26 | if (StringUtils.isBlank(product.getProductDescription()))
27 | getMessageParameterNotFoundException("productDescription");
28 | if (product.getPrice() == null || Double.compare(product.getPrice(), ProductConstanst.D_2) <= ProductConstanst.INT)
29 | getMessageParameterNotFoundException("price");
30 | if (StringUtils.isBlank(product.getCreatedAt()))
31 | getMessageParameterNotFoundException("createdAt");
32 | if (StringUtils.isBlank(product.getSerialNumber()))
33 | getMessageParameterNotFoundException("serialNumber");
34 |
35 | if (existsProductPort.existsBySerialNumber(product.getSerialNumber()))
36 | throw new GlobalException(ProductConstanst.THIS_PRODUCT_IS_ALREADY_REGISTERED);
37 |
38 | createProductPort.createProduct(product);
39 | }
40 |
41 | private void getMessageParameterNotFoundException(String parameter) throws ParameterNotFoundException {
42 | throw new ParameterNotFoundException(ProductConstanst.REQUIRED_PARAMETER + "\"" + parameter + "\"" + ProductConstanst.IS_NOT_PRESENT);
43 | }
44 | }
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/services/DeleteProductService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.constants.ProductConstanst;
4 | import com.jmendoza.swa.hexagonal.product.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
7 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.DeleteProductUseCase;
8 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.DeleteProductPort;
9 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.GetProductIdPort;
10 | import lombok.AllArgsConstructor;
11 |
12 | @AllArgsConstructor
13 | @UseCase
14 | public class DeleteProductService implements DeleteProductUseCase {
15 |
16 | private GetProductIdPort getProductIdPort;
17 | private DeleteProductPort deleteProductPort;
18 |
19 | @Override
20 | public void deleteProduct(String id) throws ResourceNotFoundException {
21 | Product product = getProductIdPort.getProductById(id)
22 | .orElseThrow(() -> new ResourceNotFoundException(ProductConstanst.PRODUCT_NOT_FOUND + id));
23 | deleteProductPort.deleteProduct(product);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/services/GetProductService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.constants.ProductConstanst;
4 | import com.jmendoza.swa.hexagonal.product.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
7 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.GetProductUseCase;
8 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.GetProductIdPort;
9 | import lombok.AllArgsConstructor;
10 |
11 | @AllArgsConstructor
12 | @UseCase
13 | public class GetProductService implements GetProductUseCase {
14 |
15 | private GetProductIdPort getProductIdPort;
16 |
17 | @Override
18 | public Product getProduct(String id) throws ResourceNotFoundException {
19 | return getProductIdPort.getProductById(id)
20 | .orElseThrow(() -> new ResourceNotFoundException(ProductConstanst.PRODUCT_NOT_FOUND + id));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/domain/services/GetProductsService.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.domain.services;
2 |
3 | import com.jmendoza.swa.hexagonal.product.common.constants.ProductConstanst;
4 | import com.jmendoza.swa.hexagonal.product.common.customannotations.UseCase;
5 | import com.jmendoza.swa.hexagonal.product.common.exception.ResourceNotFoundException;
6 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
7 | import com.jmendoza.swa.hexagonal.product.domain.ports.inbound.GetProductsUseCase;
8 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.GetProductsPort;
9 | import lombok.AllArgsConstructor;
10 |
11 | import java.util.List;
12 |
13 | @AllArgsConstructor
14 | @UseCase
15 | public class GetProductsService implements GetProductsUseCase {
16 |
17 | private GetProductsPort getProductsPort;
18 |
19 | @Override
20 | public List getProducts() throws ResourceNotFoundException {
21 |
22 | List productList = getProductsPort.getProducts();
23 | if (productList.isEmpty())
24 | throw new ResourceNotFoundException(ProductConstanst.PRODUCTS_NOT_FOUND);
25 |
26 | return productList;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/CreateProductAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.CreateProductPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class CreateProductAdapter implements CreateProductPort {
10 | @Autowired
11 | private ProductRepository productRepository;
12 |
13 | @Override
14 | public void createProduct(Product product) {
15 | productRepository.save(product);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/DeleteProductAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.DeleteProductPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | @Component
9 | public class DeleteProductAdapter implements DeleteProductPort {
10 | @Autowired
11 | private ProductRepository productRepository;
12 |
13 | @Override
14 | public void deleteProduct(Product product) {
15 | productRepository.delete(product);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/ExistsProductAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.ExistsProductPort;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class ExistsProductAdapter implements ExistsProductPort {
9 |
10 | @Autowired
11 | private ProductRepository productRepository;
12 |
13 | @Override
14 | public boolean existsBySerialNumber(String serialNumber) {
15 | return productRepository.existsBySerialNumber(serialNumber);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/GetProductIdAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.GetProductIdPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.Optional;
9 |
10 | @Component
11 | public class GetProductIdAdapter implements GetProductIdPort {
12 |
13 | @Autowired
14 | private ProductRepository productRepository;
15 |
16 | @Override
17 | public Optional getProductById(String id) {
18 | return productRepository.findById(id);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/GetProductsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 | import com.jmendoza.swa.hexagonal.product.domain.ports.outbound.GetProductsPort;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Component;
7 |
8 | import java.util.List;
9 |
10 | @Component
11 | public class GetProductsAdapter implements GetProductsPort {
12 |
13 | @Autowired
14 | private ProductRepository productRepository;
15 |
16 | @Override
17 | public List getProducts() {
18 | return productRepository.findAll();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/mongo/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product.infrastructure.databases.mongo;
2 |
3 | import com.jmendoza.swa.hexagonal.product.domain.model.Product;
4 | import org.springframework.data.mongodb.repository.MongoRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | @Repository
8 | public interface ProductRepository extends MongoRepository {
9 | boolean existsBySerialNumber(String serialNumber);
10 | }
11 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/databases/postgresql/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of DB adapter for example PostgreSQL.*
2 |
--------------------------------------------------------------------------------
/Product/src/main/java/com/jmendoza/swa/hexagonal/product/infrastructure/messagebroker/README.md:
--------------------------------------------------------------------------------
1 | *In this directory you can add another type of adapter to send messages in a message broker, for example Kafka, RabbitMQ.*
2 |
--------------------------------------------------------------------------------
/Product/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | # Application Server
2 | server.port=3001
3 |
4 | # MongoDB Atlas
5 | spring.data.mongodb.uri=mongodb+srv://jmendoza:zuZYkSpMIpSGqgLD@cluster0-7rxkw.mongodb.net/product?retryWrites=true&w=majority&maxIdleTimeMS=600000&connectTimeoutMS=60000
6 |
7 | # Logbook: HTTP request and response logging
8 | logging.level.org.zalando.logbook = TRACE
9 |
--------------------------------------------------------------------------------
/Product/src/main/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
7 |
8 |
9 |
10 |
11 | [%d{yyyy-MM-dd HH:mm:ss.SSS}] [%p] [${hostName}] [%t] [%c{3}] ==> %m%n
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
22 | ${LOG_PATTERN}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Product/src/test/java/com/jmendoza/swa/hexagonal/product/ProductApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.jmendoza.swa.hexagonal.product;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class ProductApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hexagonal-Architecture-DDD
2 |
3 | Ports and Adapters or also known as Hexagonal Architecture, is a popular architecture invented by Alistair Cockburn in 2005.
4 |
5 | Example of how to use Hexagonal Architecture and the basic of Domain Driven Design (DDD)
6 |
7 | This example is made with Spring Boot, MongoDB, PostgreSQL
8 |
9 | ## Domain Driven Design (DDD)
10 |
11 | Domain-Driven Design is an approach to software development that centers the development on programming a domain model that has a rich understanding of the processes and rules of a domain.
12 |
13 | Bounded Context is a central pattern in Domain-Driven Design. It is the focus of DDD's strategic design section which is all about dealing with large models and teams. DDD deals with large models by dividing them into different Bounded Contexts and being explicit about their interrelationships.
14 |
15 | 
16 |
17 | *Reference:*
18 | - https://martinfowler.com/tags/domain%20driven%20design.html
19 |
20 | ## Hexagonal Architecture
21 |
22 | The hexagonal architecture, or ports and adapters architecture, is an architectural pattern used in software design. It aims at creating loosely coupled application components that can be easily connected to their software environment by means of ports and adapters. This makes components exchangeable at any level and facilitates test automation.
23 |
24 | The business logic interacts with other components through ports and adapters. This way, we can change the underlying technologies without having to modify the application core.
25 |
26 | **The hexagonal architecture is based on three principles and techniques:**
27 |
28 | 1. Explicitly separate Application, Domain, and Infrastructure
29 | 2. Dependencies are going from Application and Infrastructure to the Domain
30 | 3. We isolate the boundaries by using Ports and Adapters
31 |
32 | Note: The words Application, Domain and Infrastructure do not come from the original article but from the frequent use of hexagonal architecture by Domain-Driven Design practitioners.
33 |
34 | 
35 |
36 | **Note: A port in Java is an interface. An adapter is one implementation of that interface.**
37 |
38 | ### Domain Layer, in the center
39 |
40 | - The domain layer represents the inside of the application and provides ports to interact with application use cases (business logic).
41 |
42 | - This is the part that we want to isolate from both left and right sides. It contains all the code that concerns and implements business logic (use cases).
43 |
44 | - Because domain objects have no dependencies on other layers of the application, changes in other layers don’t affect them.
45 |
46 | ### Application Layer, on the left
47 |
48 | - The application layer provides different adapters for outside entities to interact with the domain through the port.
49 |
50 | - This is the side through which the user or external programs will interact with the application. It contains the code that allows these interactions. Typically, your user interface code, your HTTP routes for an API, your JSON serializations to programs that consume your application are here.
51 |
52 | ### Infrastructure Layer, on the right
53 |
54 | - Provide adapters and server-side logic to interact with the application from the right side. Server-side entities, such as a database or other run-time devices, use these adapters to interact with the domain.
55 |
56 | - It contains essential infrastructure details such as the code that interacts with your database, makes calls to the file system, or code that handles HTTP calls to other applications on which you depend for example.
57 |
58 | *Reference:*
59 | - https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)
60 | - https://dzone.com/articles/hexagonal-architecture-in-java-2
61 | - https://blog.octo.com/en/hexagonal-architecture-three-principles-and-an-implementation-example/#principles
62 |
63 | ## Microservices Architecture
64 |
65 | 
66 |
67 | In our example we will use the basic architecture above without API Gateway. Customer, Product, Order do not necessarily have to be in different databases, it depends on the bounded context. The main objective is to highlight the use of Hexagonal Architecture in the microservices code.
68 |
69 | All microservices are implemented with Spring Boot, however microservices can be implemented with different technologies.
70 |
--------------------------------------------------------------------------------
/logs/Customer.log:
--------------------------------------------------------------------------------
1 | [2020-06-05 19:35:13.967] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.customer.CustomerApplication] | Starting CustomerApplication on jmendoza-ThinkPad-T420 with PID 21851 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Customer/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD)
2 | [2020-06-05 19:35:13.985] [DEBUG] [jmendoza-ThinkPad-T420] [main] [hexagonal.customer.CustomerApplication] | Running with Spring Boot v2.3.0.RELEASE, Spring v5.2.6.RELEASE
3 | [2020-06-05 19:35:13.987] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.customer.CustomerApplication] | No active profile set, falling back to default profiles: default
4 | [2020-06-05 19:35:16.606] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Bootstrapping Spring Data MongoDB repositories in DEFAULT mode.
5 | [2020-06-05 19:35:16.751] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Finished Spring Data repository scanning in 138ms. Found 1 MongoDB repository interfaces.
6 | [2020-06-05 19:35:19.121] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat initialized with port(s): 3000 (http)
7 | [2020-06-05 19:35:19.135] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Initializing ProtocolHandler ["http-nio-3000"]
8 | [2020-06-05 19:35:19.135] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Starting service [Tomcat]
9 | [2020-06-05 19:35:19.136] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] | Starting Servlet engine: [Apache Tomcat/9.0.35]
10 | [2020-06-05 19:35:19.312] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] | Initializing Spring embedded WebApplicationContext
11 | [2020-06-05 19:35:19.312] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] | Root WebApplicationContext: initialization completed in 5088 ms
12 | [2020-06-05 19:35:20.056] [INFO] [jmendoza-ThinkPad-T420] [main] [mongodb.driver.cluster] | Cluster created with settings {hosts=[127.0.0.1:27017], srvHost=cluster0-7rxkw.mongodb.net, mode=MULTIPLE, requiredClusterType=REPLICA_SET, serverSelectionTimeout='30000 ms', requiredReplicaSetName='Cluster0-shard-0'}
13 | [2020-06-05 19:35:20.156] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-00-7rxkw.mongodb.net:27017 to client view of cluster
14 | [2020-06-05 19:35:20.207] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-01-7rxkw.mongodb.net:27017 to client view of cluster
15 | [2020-06-05 19:35:20.209] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-02-7rxkw.mongodb.net:27017 to client view of cluster
16 | [2020-06-05 19:35:21.354] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] | Initializing ExecutorService 'applicationTaskExecutor'
17 | [2020-06-05 19:35:21.686] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-02-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:3, serverValue:117268}] to cluster0-shard-00-02-7rxkw.mongodb.net:27017
18 | [2020-06-05 19:35:21.732] [INFO] [jmendoza-ThinkPad-T420] [main] [endpoint.web.EndpointLinksResolver] | Exposing 2 endpoint(s) beneath base path '/actuator'
19 | [2020-06-05 19:35:21.770] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Starting ProtocolHandler ["http-nio-3000"]
20 | [2020-06-05 19:35:21.810] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat started on port(s): 3000 (http) with context path ''
21 | [2020-06-05 19:35:21.827] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.customer.CustomerApplication] | Started CustomerApplication in 8.835 seconds (JVM running for 12.734)
22 | [2020-06-05 19:35:21.881] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-02-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-02-7rxkw.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=192045575, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-02-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=null, setVersion=4, lastWriteDate=Fri Jun 05 19:35:02 VET 2020, lastUpdateTimeNanos=16852466771751}
23 | [2020-06-05 19:35:22.285] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(5)-127.0.0.1] [[Tomcat].[localhost].[/]] | Initializing Spring DispatcherServlet 'dispatcherServlet'
24 | [2020-06-05 19:35:22.286] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(5)-127.0.0.1] [web.servlet.DispatcherServlet] | Initializing Servlet 'dispatcherServlet'
25 | [2020-06-05 19:35:22.294] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(5)-127.0.0.1] [web.servlet.DispatcherServlet] | Completed initialization in 8 ms
26 | [2020-06-05 19:35:22.386] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(4)-127.0.0.1] [mongodb.driver.cluster] | No server chosen by ReadPreferenceServerSelector{readPreference=primary} from cluster description ClusterDescription{type=REPLICA_SET, connectionMode=MULTIPLE, serverDescriptions=[ServerDescription{address=cluster0-shard-00-00-7rxkw.mongodb.net:27017, type=UNKNOWN, state=CONNECTING}, ServerDescription{address=cluster0-shard-00-01-7rxkw.mongodb.net:27017, type=UNKNOWN, state=CONNECTING}, ServerDescription{address=cluster0-shard-00-02-7rxkw.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=192045575, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-02-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=null, setVersion=4, lastWriteDate=Fri Jun 05 19:35:02 VET 2020, lastUpdateTimeNanos=16852466771751}]}. Waiting for 30000 ms before timing out
27 | [2020-06-05 19:35:22.552] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:2, serverValue:137759}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017
28 | [2020-06-05 19:35:22.699] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-00-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:1, serverValue:112761}] to cluster0-shard-00-00-7rxkw.mongodb.net:27017
29 | [2020-06-05 19:35:22.735] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-01-7rxkw.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=182361086, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-01-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=7fffffff0000000000000027, setVersion=4, lastWriteDate=Fri Jun 05 19:35:03 VET 2020, lastUpdateTimeNanos=16853322260844}
30 | [2020-06-05 19:35:22.736] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Setting max election id to 7fffffff0000000000000027 from replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
31 | [2020-06-05 19:35:22.736] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Setting max set version to 4 from replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
32 | [2020-06-05 19:35:22.736] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Discovered replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
33 | [2020-06-05 19:35:22.881] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad6b8dfc52759bdfbc2af', description='null'}-cluster0-shard-00-00-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-00-7rxkw.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=181270372, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-00-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=null, setVersion=4, lastWriteDate=Fri Jun 05 19:35:04 VET 2020, lastUpdateTimeNanos=16853467593939}
34 | [2020-06-05 19:35:24.120] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(4)-127.0.0.1] [mongodb.driver.connection] | Opened connection [connectionId{localValue:4, serverValue:137759}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017
35 | [2020-06-05 19:35:42.449] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3000-exec-1] [zalando.logbook.Logbook] | {"origin":"remote","type":"request","correlation":"ed06e08d93d52b31","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"POST","uri":"http://localhost:3000/v1/customers/login","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"content-length":["65"],"content-type":["application/json"],"host":["localhost:3000"],"origin":["chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop"],"postman-token":["6b0758a1-1971-c17a-0e71-452421211679"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"]},"body":{"email":"jmendoza@gmail.com","password":"123456789"}}
36 | [2020-06-05 19:35:43.389] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3000-exec-1] [zalando.logbook.Logbook] | {"origin":"local","type":"response","correlation":"ed06e08d93d52b31","duration":1012,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 05 Jun 2020 23:35:43 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":{"id":"5ed047dda2923f1ac2c64463","firstName":"Jonathan","lastName":"Mendoza","email":"jmendoza@gmail.com","createdAt":"2020-05-28T19:15:07"}}
37 | [2020-06-05 19:35:53.372] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [scheduling.concurrent.ThreadPoolTaskExecutor] | Shutting down ExecutorService 'applicationTaskExecutor'
38 | [2020-06-05 19:35:53.566] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [mongodb.driver.connection] | Closed connection [connectionId{localValue:4, serverValue:137759}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017 because the pool has been closed.
39 |
--------------------------------------------------------------------------------
/logs/Product.log:
--------------------------------------------------------------------------------
1 | [2020-06-05 19:40:06.294] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.product.ProductApplication] | Starting ProductApplication on jmendoza-ThinkPad-T420 with PID 22911 (/home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD/Product/target/classes started by jmendoza in /home/jmendoza/IdeaProjects/JonathanM2ndoza/Hexagonal-Architecture-DDD)
2 | [2020-06-05 19:40:06.310] [DEBUG] [jmendoza-ThinkPad-T420] [main] [hexagonal.product.ProductApplication] | Running with Spring Boot v2.3.0.RELEASE, Spring v5.2.6.RELEASE
3 | [2020-06-05 19:40:06.311] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.product.ProductApplication] | No active profile set, falling back to default profiles: default
4 | [2020-06-05 19:40:08.568] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Bootstrapping Spring Data MongoDB repositories in DEFAULT mode.
5 | [2020-06-05 19:40:08.670] [INFO] [jmendoza-ThinkPad-T420] [main] [repository.config.RepositoryConfigurationDelegate] | Finished Spring Data repository scanning in 96ms. Found 1 MongoDB repository interfaces.
6 | [2020-06-05 19:40:09.163] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat initialized with port(s): 3001 (http)
7 | [2020-06-05 19:40:09.171] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Initializing ProtocolHandler ["http-nio-3001"]
8 | [2020-06-05 19:40:09.171] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardService] | Starting service [Tomcat]
9 | [2020-06-05 19:40:09.171] [INFO] [jmendoza-ThinkPad-T420] [main] [catalina.core.StandardEngine] | Starting Servlet engine: [Apache Tomcat/9.0.35]
10 | [2020-06-05 19:40:09.254] [INFO] [jmendoza-ThinkPad-T420] [main] [[Tomcat].[localhost].[/]] | Initializing Spring embedded WebApplicationContext
11 | [2020-06-05 19:40:09.255] [INFO] [jmendoza-ThinkPad-T420] [main] [web.context.ContextLoader] | Root WebApplicationContext: initialization completed in 2567 ms
12 | [2020-06-05 19:40:09.736] [INFO] [jmendoza-ThinkPad-T420] [main] [mongodb.driver.cluster] | Cluster created with settings {hosts=[127.0.0.1:27017], srvHost=cluster0-7rxkw.mongodb.net, mode=MULTIPLE, requiredClusterType=REPLICA_SET, serverSelectionTimeout='30000 ms', requiredReplicaSetName='Cluster0-shard-0'}
13 | [2020-06-05 19:40:09.837] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-00-7rxkw.mongodb.net:27017 to client view of cluster
14 | [2020-06-05 19:40:10.030] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-01-7rxkw.mongodb.net:27017 to client view of cluster
15 | [2020-06-05 19:40:10.035] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-srv-cluster0-7rxkw.mongodb.net] [mongodb.driver.cluster] | Adding discovered server cluster0-shard-00-02-7rxkw.mongodb.net:27017 to client view of cluster
16 | [2020-06-05 19:40:10.579] [INFO] [jmendoza-ThinkPad-T420] [main] [scheduling.concurrent.ThreadPoolTaskExecutor] | Initializing ExecutorService 'applicationTaskExecutor'
17 | [2020-06-05 19:40:10.966] [INFO] [jmendoza-ThinkPad-T420] [main] [endpoint.web.EndpointLinksResolver] | Exposing 2 endpoint(s) beneath base path '/actuator'
18 | [2020-06-05 19:40:11.009] [INFO] [jmendoza-ThinkPad-T420] [main] [coyote.http11.Http11NioProtocol] | Starting ProtocolHandler ["http-nio-3001"]
19 | [2020-06-05 19:40:11.030] [INFO] [jmendoza-ThinkPad-T420] [main] [embedded.tomcat.TomcatWebServer] | Tomcat started on port(s): 3001 (http) with context path ''
20 | [2020-06-05 19:40:11.054] [INFO] [jmendoza-ThinkPad-T420] [main] [hexagonal.product.ProductApplication] | Started ProductApplication in 5.781 seconds (JVM running for 7.746)
21 | [2020-06-05 19:40:11.065] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:2, serverValue:137760}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017
22 | [2020-06-05 19:40:11.210] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-01-7rxkw.mongodb.net:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=139818719, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-01-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=7fffffff0000000000000027, setVersion=4, lastWriteDate=Fri Jun 05 19:39:52 VET 2020, lastUpdateTimeNanos=17141793745012}
23 | [2020-06-05 19:40:11.213] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Setting max election id to 7fffffff0000000000000027 from replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
24 | [2020-06-05 19:40:11.213] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Setting max set version to 4 from replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
25 | [2020-06-05 19:40:11.214] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-01-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Discovered replica set primary cluster0-shard-00-01-7rxkw.mongodb.net:27017
26 | [2020-06-05 19:40:11.330] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-00-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:1, serverValue:98416}] to cluster0-shard-00-00-7rxkw.mongodb.net:27017
27 | [2020-06-05 19:40:11.335] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-02-7rxkw.mongodb.net:27017] [mongodb.driver.connection] | Opened connection [connectionId{localValue:3, serverValue:117268}] to cluster0-shard-00-02-7rxkw.mongodb.net:27017
28 | [2020-06-05 19:40:11.479] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(3)-127.0.0.1] [[Tomcat].[localhost].[/]] | Initializing Spring DispatcherServlet 'dispatcherServlet'
29 | [2020-06-05 19:40:11.480] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(3)-127.0.0.1] [web.servlet.DispatcherServlet] | Initializing Servlet 'dispatcherServlet'
30 | [2020-06-05 19:40:11.487] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(3)-127.0.0.1] [web.servlet.DispatcherServlet] | Completed initialization in 7 ms
31 | [2020-06-05 19:40:11.575] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-00-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-00-7rxkw.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=244808340, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-00-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=null, setVersion=4, lastWriteDate=Fri Jun 05 19:39:52 VET 2020, lastUpdateTimeNanos=17142162143540}
32 | [2020-06-05 19:40:11.581] [INFO] [jmendoza-ThinkPad-T420] [cluster-ClusterId{value='5edad7d9117cf45695f7866b', description='null'}-cluster0-shard-00-02-7rxkw.mongodb.net:27017] [mongodb.driver.cluster] | Monitor thread successfully connected to server with description ServerDescription{address=cluster0-shard-00-02-7rxkw.mongodb.net:27017, type=REPLICA_SET_SECONDARY, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=8, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=245578472, setName='Cluster0-shard-0', canonicalAddress=cluster0-shard-00-02-7rxkw.mongodb.net:27017, hosts=[cluster0-shard-00-02-7rxkw.mongodb.net:27017, cluster0-shard-00-01-7rxkw.mongodb.net:27017, cluster0-shard-00-00-7rxkw.mongodb.net:27017], passives=[], arbiters=[], primary='cluster0-shard-00-01-7rxkw.mongodb.net:27017', tagSet=TagSet{[Tag{name='nodeType', value='ELECTABLE'}, Tag{name='provider', value='AWS'}, Tag{name='region', value='US_EAST_1'}]}, electionId=null, setVersion=4, lastWriteDate=Fri Jun 05 19:39:52 VET 2020, lastUpdateTimeNanos=17142167993915}
33 | [2020-06-05 19:40:14.595] [INFO] [jmendoza-ThinkPad-T420] [RMI TCP Connection(2)-127.0.0.1] [mongodb.driver.connection] | Opened connection [connectionId{localValue:4, serverValue:137760}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017
34 | [2020-06-05 19:40:40.644] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3001-exec-1] [zalando.logbook.Logbook] | {"origin":"remote","type":"request","correlation":"eb39353f3075a2a6","protocol":"HTTP/1.1","remote":"0:0:0:0:0:0:0:1","method":"GET","uri":"http://localhost:3001/v1/products","headers":{"accept":["*/*"],"accept-encoding":["gzip, deflate, br"],"accept-language":["es-419,es-US;q=0.9,es;q=0.8,en-US;q=0.7,en;q=0.6"],"cache-control":["no-cache"],"connection":["keep-alive"],"host":["localhost:3001"],"postman-token":["eb5c9aba-dd9d-e6b6-46f2-1bbb338e8424"],"sec-fetch-dest":["empty"],"sec-fetch-mode":["cors"],"sec-fetch-site":["none"],"user-agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36"]}}
35 | [2020-06-05 19:40:40.982] [TRACE] [jmendoza-ThinkPad-T420] [http-nio-3001-exec-1] [zalando.logbook.Logbook] | {"origin":"local","type":"response","correlation":"eb39353f3075a2a6","duration":383,"protocol":"HTTP/1.1","status":200,"headers":{"Connection":["keep-alive"],"Content-Type":["application/json"],"Date":["Fri, 05 Jun 2020 23:40:40 GMT"],"Keep-Alive":["timeout=60"],"Transfer-Encoding":["chunked"]},"body":[{"id":"5ed31cb5669529409edc2fcf","productName":"Apple MacBook Pro","productDescription":"New Apple MacBook Pro (16-Inch, 16GB RAM, 512GB Storage) - Space Gray","price":2199.99,"createdAt":"2020-05-30T22:55:15","serialNumber":"4548FFSDFDF5665"},{"id":"5ed31ddb669529409edc2fd0","productName":"Apple iPhone 11 Pro","productDescription":"Apple iPhone 11 Pro (64GB, Midnight Green)","price":1099.99,"createdAt":"2020-05-30T23:01:07","serialNumber":"SDFGHGH3456768FG"}]}
36 | [2020-06-05 19:40:46.294] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [scheduling.concurrent.ThreadPoolTaskExecutor] | Shutting down ExecutorService 'applicationTaskExecutor'
37 | [2020-06-05 19:40:46.497] [INFO] [jmendoza-ThinkPad-T420] [SpringContextShutdownHook] [mongodb.driver.connection] | Closed connection [connectionId{localValue:4, serverValue:137760}] to cluster0-shard-00-01-7rxkw.mongodb.net:27017 because the pool has been closed.
38 |
--------------------------------------------------------------------------------
/prtsc/Hexa-Arch-DDD-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/prtsc/Hexa-Arch-DDD-1.png
--------------------------------------------------------------------------------
/prtsc/Hexa-Arch-DDD-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/prtsc/Hexa-Arch-DDD-2.png
--------------------------------------------------------------------------------
/prtsc/Hexagonal-Architecture-Microservices.drawio:
--------------------------------------------------------------------------------
1 | 7VtZd9o4FP41OWf6YI53zCOBpMsk07SZpZ2XHmELo9a2PLJIIb9+riwJvBHIlKWZQx4AXV2t33cXyc6FM0oXrxnKZ7c0wsmFbUaLC2d8YduBacGnECylwB24UhAzEkmRtRbck0eshKaSzkmEi5oipzThJK8LQ5plOOQ1GWKMfq+rTWlSHzVHMW4J7kOUtKV/kYjPlNTyB+uKN5jEMzV0YPdlRYq0slpJMUMR/V4ROVcXzohRyuWvdDHCidg7vS+y3fWG2tXEGM74Lg3675IPSfbbzdTO/Dn//HHy6TE3AjU3vtQLxhGsXxUp4zMa0wwlV2vpJaPzLMKiVxNKa50bSnMQWiD8ijlfKjDRnFMQzXiaqFo5phho41KUqKBzFiqt4k/LNcIvv3+d82BKDJzn90zOX633NaYp5mwJ7RhOECcP9f6RokK80ls1vaMERrZNxVrPUZgp0tqmV++CIxZjrlqt93zIGFpW1HKhUGwexzUHtXFc069DuEVfz0vpww85A12q7MlaVNLiGRQZnCmyA0U0dPumiON1j7OJIlv0D0MR7ax/To4cHHtfr38L9q2O7H7L/nuN2Uh6n9zT6CXui0abLdU2H1AyV9C0aPWAGScQnW/QBCd3tCCc0AyqJpRzmgIpUJHLNGBKFoJcVcLoxsOExKIRF0S7LDij3/CIJpSBLKOZICdSKiFQCTPBzzlPSAZqOs0QpIWQnouJpYtYJD+9kHBGFj1IWL7Jvjd6LTEVvHiSpLp2UCeb4/k9V4Wj7+uMRGvNKrnIYNBkU5XbFSyfD9WgAyo/4WK/LZGNJaiQQ/r/zEWCcwn7QUJOOAC5kq0H0ZKCpHmCjZSEjBaYPZAQFwZi4Yxw2PU5wwbNDAQ5XbWPNT20MAX7IwDfEGodhlP4MvMFfFqyINtNacaNKUpJspSq0AFKJWyO4woWpOgR6AVOJp0AC5rVZZNRV8MZTh6w4BpUZniOn9GUUeAyfUYDxAhKNusXKCsM2EsyXS08lFwXS2bx5JcSSalse6ufjvVq1SBHUUSyWDaROykrhEkYmnKi0uqBr6js8QSF3+LS0xvNUT2vMmzt96sqvH6svkt2Ccw6IS/BLMpQUc4jELNs9nJf0guqb6sEg/KwQjE9FNiFHK0+AxALimthwz+BUfO602EYZoUmpYLYFBHH5DzL6pajaTqplERRGS+Vi4dhvMsLbyzWTJKk4bc6nVk90opFqZhqefvxUf1mutxyT47V4Z+sZtzcm3ty+6dISGAD2fITFAyzZ7qelnwWPfac/kowXqgxZGlZLd2BpcIeCCo8D62tebClj89lcvKEooavkVn9QBr1Q1jqeT+VFnRG5wgVsxWcWxOH7uSgZZ4VuJvRH+KS00NZxKhYT806wStfXbl9ewhyUI4IdNcw0j2YoecEPa9miZbXNkXLcrTWkYzRP4Ux7tFwnH3bQ3fOHZiNo9uOx4p9pd96nS/c0ILRyHevD2tort3IybvMrCvi2QczMu+FG5l7GiPb9ey+NyNz/xdG5g39wdA9sJG5NaS8LiMzg2MameV1gCePBRF56DyXiAOBofZdHEwSPOWbjzcwq7IjKW2cUqTKhOnq0bwAsDErWgR6AacQqaIfqTgNX+Lui0JBPR0yuyjU4afdgzHIbzFoC8p3jEbzkJ9B3hVk5/Qg958L8nsWne34CYi9er7lnRxiHWKeCuM6opK0fMa8/SZ6a1RPRMXl6kqtEo+n5R+olIMN9SV4SZHmjbiaz3jGuXiIPhQ7YV+HUeb0SEizKQF4WS+EESEaIY7gS8iBntciLRE/jSnD2HiAfikzykojh2mBhmOrVoZlB71cXBoehyOBVU/srL7d4kjQkS1o2f4p0r630BH7bOgbQbTqIHbkfEGHnR8s49Nmfbbzn8bO9YN2He79U9t5+9pE5WxnM99o5vWny47bNnP/qGa+w6n8bObHNfN6OPf8jkhwVDNvn/3LrP1s5Dsauec4LQS9Yxq5236/5I9CAGi+FRs/RSE+g7npLZSg8Wwi2PEEtg8088W7/OOv7x8D4+7zlw9vkfW3dW+0z9j6WF3kKOu8i2u+IyDeZCjv3jbcxv1wR3WXHBM+m0+UJ35HM8RnKLu1s4g+Cqf8Bi9QeftuVN9GMMbjceV2UE6pdWlYF788DlcZuyqrFZh7oG+/8cZev+MCofMVhX3Qt/uVyRZ9b2kW0/GLhG9XF9QCbKe3NVfxpP48wO7KCI4JYftoeIbweRC6Rzzed0LYcXSjBY8Zvv9wc0ZxY2pev6TxO1Dseh31P6AIxfU/yMhHsOv/MnKu/gU=
--------------------------------------------------------------------------------
/prtsc/Hexagonal-Architecture-Microservices.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JonathanM2ndoza/Hexagonal-Architecture-DDD/e194c6ca377cb4d66acff6bb11111e5dff65261f/prtsc/Hexagonal-Architecture-Microservices.jpg
--------------------------------------------------------------------------------