diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/Order.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/Order.java new file mode 100644 index 0000000000..a0ba6815bc --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/Order.java @@ -0,0 +1,12 @@ +package com.baeldung.springmodulith.application.events.orders; + +import java.time.Instant; +import java.util.List; + +record Order(String id, String customerId, List productIds, Instant timestamp) { + + public Order(String customerId, List productIds) { + this(null, customerId, productIds, Instant.now()); + } + +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderCompletedEvent.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderCompletedEvent.java new file mode 100644 index 0000000000..0f11468241 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderCompletedEvent.java @@ -0,0 +1,6 @@ +package com.baeldung.springmodulith.application.events.orders; + +import java.time.Instant; + +public record OrderCompletedEvent(String orderId, String customerId, Instant time) { +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderRepository.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderRepository.java new file mode 100644 index 0000000000..d02b00d2d0 --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderRepository.java @@ -0,0 +1,25 @@ +package com.baeldung.springmodulith.application.events.orders; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Component +class OrderRepository { + private final List orders = new ArrayList<>(); + + public Order save(Order order) { + order = new Order(UUID.randomUUID().toString(), order.customerId(), order.productIds(), order.timestamp()); + orders.add(order); + return order; + } + + public List ordersByCustomer(String customerId) { + return orders.stream() + .filter(it -> it.customerId().equals(customerId)) + .toList(); + } + +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderService.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderService.java new file mode 100644 index 0000000000..c3b52d478b --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/orders/OrderService.java @@ -0,0 +1,29 @@ +package com.baeldung.springmodulith.application.events.orders; + +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +@Service +public class OrderService { + + private final OrderRepository repository; + private final ApplicationEventPublisher eventPublisher; + + public OrderService(OrderRepository orders, ApplicationEventPublisher eventsPublisher) { + this.repository = orders; + this.eventPublisher = eventsPublisher; + } + + public void placeOrder(String customerId, String... productIds) { + Order order = new Order(customerId, Arrays.asList(productIds)); + // business logic to validate and place the order + + Order savedOrder = repository.save(order); + + OrderCompletedEvent event = new OrderCompletedEvent(savedOrder.id(), savedOrder.customerId(), savedOrder.timestamp()); + eventPublisher.publishEvent(event); + } + +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyalCustomersRepository.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyalCustomersRepository.java new file mode 100644 index 0000000000..764924232d --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyalCustomersRepository.java @@ -0,0 +1,41 @@ +package com.baeldung.springmodulith.application.events.rewards; + +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Component +public class LoyalCustomersRepository { + + private List customers = new ArrayList<>(); + + public Optional find(String customerId) { + return customers.stream() + .filter(it -> it.customerId().equals(customerId)) + .findFirst(); + } + + public void awardPoints(String customerId, int points) { + var customer = find(customerId).orElseThrow(); + customers.remove(customer); + customers.add(customer.addPoints(points)); + } + + public void save(String customerId) { + customers.add(new LoyalCustomer(customerId, 0)); + } + + public boolean isLoyalCustomer(String customerId) { + return find(customerId).isPresent(); + } + + public record LoyalCustomer(String customerId, int points) { + + LoyalCustomer addPoints(int points) { + return new LoyalCustomer(customerId, this.points() + points); + } + } + +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyaltyPointsService.java b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyaltyPointsService.java new file mode 100644 index 0000000000..20af0caa6f --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/main/java/com/baeldung/springmodulith/application/events/rewards/LoyaltyPointsService.java @@ -0,0 +1,28 @@ +package com.baeldung.springmodulith.application.events.rewards; + +import com.baeldung.springmodulith.application.events.orders.OrderCompletedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Service; + +@Service +public class LoyaltyPointsService { + + public static final int ORDER_COMPLETED_POINTS = 10; + public static final int SING_UP_POINTS = 50; + private final LoyalCustomersRepository loyalCustomers; + + public LoyaltyPointsService(LoyalCustomersRepository loyalCustomers) { + this.loyalCustomers = loyalCustomers; + } + + @EventListener + public void onOrderCompleted(OrderCompletedEvent event) { + if (loyalCustomers.find(event.customerId()).isEmpty()) { + loyalCustomers.save(event.customerId()); + loyalCustomers.awardPoints(event.customerId(), SING_UP_POINTS); + } + + loyalCustomers.awardPoints(event.customerId(), ORDER_COMPLETED_POINTS); + } + +} diff --git a/spring-boot-modules/spring-boot-libraries-3/src/test/java/com/baeldung/springmodulith/application/events/ApplicationEventsTest.java b/spring-boot-modules/spring-boot-libraries-3/src/test/java/com/baeldung/springmodulith/application/events/ApplicationEventsTest.java new file mode 100644 index 0000000000..82fd53d13e --- /dev/null +++ b/spring-boot-modules/spring-boot-libraries-3/src/test/java/com/baeldung/springmodulith/application/events/ApplicationEventsTest.java @@ -0,0 +1,38 @@ +package com.baeldung.springmodulith.application.events; + +import com.baeldung.springmodulith.application.events.orders.OrderService; +import com.baeldung.springmodulith.application.events.rewards.LoyalCustomersRepository; +import com.baeldung.springmodulith.application.events.rewards.LoyalCustomersRepository.LoyalCustomer; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.ComponentScan; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ComponentScan(basePackages = "com.baeldung.springmodulith.application.events") +public class ApplicationEventsTest { + + + @Autowired + OrderService orderService; + + @Autowired + LoyalCustomersRepository loyalCustomers; + + @Test + void whenNewCustomerCompletesAnOrder_thenHeReceivesSingUpPointsPlusOrderPoints() { + orderService.placeOrder("customer1", "product1", "product2"); + + Optional customer = loyalCustomers.find("customer1"); + + assertThat(customer).isPresent() + .get() + .extracting(LoyalCustomer::points) + .isEqualTo(50 + 10); + } + +}