From 688095a4c7c1831631d23a1136ec26a477bf410c Mon Sep 17 00:00:00 2001 From: Hattori Henzo Date: Sun, 16 Aug 2026 13:30:42 -0400 Subject: [PATCH 01/17] feat: Add the implementation of Onion-Architecture (#3532) * Add the implementation of Onion-Architecture * Execute maven command: mvn spotless:apply --- onion-architecture/README.md | 292 +++++++++++++++ onion-architecture/application/pom.xml | 66 ++++ .../onion/application/dto/PersonResponse.java | 37 ++ .../application/dto/SavePersonCommand.java | 37 ++ .../application/usecase/GetPersonUseCase.java | 75 ++++ .../usecase/SavePersonUseCase.java | 67 ++++ .../usecase/GetPersonUseCaseTest.java | 193 ++++++++++ .../usecase/SavePersonUseCaseTest.java | 253 +++++++++++++ onion-architecture/domain/pom.xml | 47 +++ .../domain/exception/DomainException.java | 34 ++ .../iluwatar/onion/domain/model/Category.java | 51 +++ .../iluwatar/onion/domain/model/Person.java | 121 ++++++ .../domain/repository/PersonRepository.java | 45 +++ .../onion/domain/model/CategoryTest.java | 75 ++++ .../onion/domain/model/PersonTest.java | 179 +++++++++ onion-architecture/etc/onion-architecture.png | Bin 0 -> 258593 bytes .../etc/onion-architecture.puml | 237 ++++++++++++ ...onion-architecture.postman_collection.json | 83 +++++ onion-architecture/infrastructure/pom.xml | 87 +++++ .../onion/infrastructure/Application.java | 38 ++ .../config/ApplicationConfig.java | 47 +++ .../persistence/JpaCategoryEntity.java | 55 +++ .../persistence/JpaPersonEntity.java | 93 +++++ .../persistence/PersonRepositoryAdapter.java | 102 +++++ .../SpringDataPersonRepository.java | 37 ++ .../infrastructure/web/PersonController.java | 72 ++++ .../src/main/resources/application.properties | 19 + .../src/main/resources/data.sql | 4 + .../PersonRepositoryAdapterTest.java | 332 +++++++++++++++++ .../web/PersonControllerTest.java | 348 ++++++++++++++++++ onion-architecture/pom.xml | 49 +++ pom.xml | 8 +- 32 files changed, 3182 insertions(+), 1 deletion(-) create mode 100644 onion-architecture/README.md create mode 100644 onion-architecture/application/pom.xml create mode 100644 onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/PersonResponse.java create mode 100644 onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/SavePersonCommand.java create mode 100644 onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/GetPersonUseCase.java create mode 100644 onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/SavePersonUseCase.java create mode 100644 onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/GetPersonUseCaseTest.java create mode 100644 onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/SavePersonUseCaseTest.java create mode 100644 onion-architecture/domain/pom.xml create mode 100644 onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/exception/DomainException.java create mode 100644 onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Category.java create mode 100644 onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Person.java create mode 100644 onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/repository/PersonRepository.java create mode 100644 onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/CategoryTest.java create mode 100644 onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/PersonTest.java create mode 100644 onion-architecture/etc/onion-architecture.png create mode 100644 onion-architecture/etc/onion-architecture.puml create mode 100644 onion-architecture/etc/postman/onion-architecture.postman_collection.json create mode 100644 onion-architecture/infrastructure/pom.xml create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/Application.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/config/ApplicationConfig.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaCategoryEntity.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaPersonEntity.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapter.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/SpringDataPersonRepository.java create mode 100644 onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/web/PersonController.java create mode 100644 onion-architecture/infrastructure/src/main/resources/application.properties create mode 100644 onion-architecture/infrastructure/src/main/resources/data.sql create mode 100644 onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapterTest.java create mode 100644 onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/web/PersonControllerTest.java create mode 100644 onion-architecture/pom.xml diff --git a/onion-architecture/README.md b/onion-architecture/README.md new file mode 100644 index 000000000000..1a7fc394638d --- /dev/null +++ b/onion-architecture/README.md @@ -0,0 +1,292 @@ +--- +title: "Onion Architecture in Java: A Layered Approach to Building Maintainable and Testable Applications" +shortTitle: Onion Architecture +description: "Learn how the Onion Architecture pattern promotes maintainability, testability, and separation of concerns in Java applications. Explore examples, benefits, and best practices." +category: Architectural +language: en +tag: + - Decoupling + - Enterprise patterns + - Integration + - Microservices + - Scalability + - Security +--- +## Intent of Microservices API Gateway Design Pattern + +In this project, the implementation demonstrates **Onion Architecture** with clear dependency direction: infrastructure and application depend on domain, but domain is independent. + +The central intent is to keep business rules in `domain`, orchestrate use cases in `application`, and isolate delivery/persistence/API details in `infrastructure`. + +Current implementation highlights: + +* `domain`: `Person`, `Category`, `PersonRepository`, `DomainException` +* `application`: `SavePersonUseCase`, `GetPersonUseCase`, DTO records +* `infrastructure`: Spring Boot REST controller, JPA entities, repository adapter, bean wiring + +## Also known as + +* Ports and Adapters Architecture +* Hexagonal-style layering (conceptually related) +* Dependency-rule-first architecture + +## Detailed Explanation of Onion Architecture Pattern with Real-World Examples + +Real-world example + +> Imagine a people-management service where business validation must stay consistent no matter how data is stored or exposed. In this codebase, `Person` and `Category` enforce invariants (e.g., age >= 18, required email/category), use cases coordinate behavior, and infrastructure adapts HTTP + JPA concerns. This allows the persistence or web layer to evolve without changing core domain rules. + +In plain words + +> The project keeps business logic in the center and treats frameworks as replaceable details around it. + +Wikipedia says + +> Onion Architecture is a software architecture pattern that emphasizes separation of concerns and dependency inversion by organizing code in concentric layers, with the domain model at the center. + +Sequence diagram + +![Onion Architecture class diagram](./etc/onion-architecture.png) + +Request flow in this implementation: + +1. Client calls REST endpoint in `PersonController` (`/api/persons`, `/api/persons/{id}`) +2. Controller delegates to `SavePersonUseCase` or `GetPersonUseCase` +3. Use case interacts with `PersonRepository` abstraction from `domain` +4. `PersonRepositoryAdapter` maps domain <-> JPA and delegates to `SpringDataPersonRepository` +5. Response DTO (`PersonResponse`) is returned to the client + +## Programmatic Example of Onion Architecture in Java + +This repository exposes a simple person API backed by use cases and domain models. + +Controller (infrastructure layer): + +```java +@RestController +@RequestMapping("/api") +public class PersonController { + + @GetMapping("/persons/{id}") + public ResponseEntity getPerson(@PathVariable Long id) { + var person = getPersonUseCase.execute(id); + return ResponseEntity.ok(person); + } + + @GetMapping("/persons") + public ResponseEntity> getAllPersons() { + var persons = getPersonUseCase.executeAll(); + return ResponseEntity.ok(persons); + } + + @PostMapping("/persons") + public ResponseEntity savePerson(@RequestBody SavePersonCommand command) { + try { + var savedPerson = savePersonUseCase.execute(command); + return ResponseEntity.status(HttpStatus.OK).body(savedPerson); + } catch (DomainException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } +} +``` + +Use case (application layer): + +```java +public class SavePersonUseCase { + + private final PersonRepository repository; + + public PersonResponse execute(SavePersonCommand command) { + var category = new Category(command.categoryId(), command.categoryType()); + var person = new Person( + null, + command.firstName(), + command.lastName(), + command.age(), + command.phoneNumber(), + command.email(), + category); + + var savedPerson = repository.save(person); + return new PersonResponse( + savedPerson.getId(), + savedPerson.getFirstName(), + savedPerson.getLastName(), + savedPerson.getAge(), + savedPerson.getPhoneNumber(), + savedPerson.getEmail(), + savedPerson.getCategory().getId(), + savedPerson.getCategory().getType() + ); + } +} +``` + +Domain validation (domain layer): + +```java +public class Person { + public Person(Long id, String firstName, String lastName, int age, + String phoneNumber, String email, Category category) { + validateNames(firstName, lastName); + validateAge(age); + validatePhone(phoneNumber); + validateEmail(email); + validateCategory(category); + // assign fields... + } +} +``` + +Repository adapter (infrastructure -> domain port): + +```java +@Repository +public class PersonRepositoryAdapter implements PersonRepository { + + private final SpringDataPersonRepository repository; + + @Override + public Optional findById(Long id) { + return repository.findById(id).map(this::mapToDomain); + } + + @Override + public Person save(Person person) { + JpaPersonEntity savedEntity = repository.save(mapToEntity(person)); + return mapToDomain(savedEntity); + } +} +``` + +- **Maven 3.6.0** or higher + +### Build Steps + +1. **Navigate to the onion-architecture module directory:** + ```bash + cd java-design-patterns/onion-architecture + ``` + +2. **Build all modules:** + ```bash + mvn clean package + ``` + This will compile the `domain`, `application`, and `infrastructure` modules and package them into a Spring Boot executable JAR. + +3. **Run the Spring Boot application:** + ```bash + mvn -pl infrastructure spring-boot:run + ``` + Alternatively, after building, run the JAR directly: + ```bash + java -jar infrastructure/target/infrastructure-1.26.0-SNAPSHOT.jar + ``` + +### Accessing the API + +The application exposes REST endpoints at `http://localhost:8080/api`: +There is a Postman collection available in the `etc/postman` folder for testing the API. + +- **Get all persons:** + ```bash + GET http://localhost:8080/api/persons + ``` + +- **Get person by ID:** + ```bash + GET http://localhost:8080/api/persons/{id} + ``` + +- **Create a new person:** + ```bash + POST http://localhost:8080/api/persons + Content-Type: application/json + + { + "firstName": "John", + "lastName": "Doe", + "age": 30, + "phoneNumber": "555-1234", + "email": "john.doe@example.com", + "address": "123 Main St", + "categoryId": 1, + "categoryType": "individual" + } + ``` + +### Run Tests + +To execute unit tests across all modules: + +```bash +mvn clean test +``` + +To run tests for a specific module: + +```bash +mvn -pl domain test +mvn -pl application test +mvn -pl infrastructure test +``` + +### Database + +The application uses an **H2 in-memory database** for demonstration purposes. Configuration is in `infrastructure/src/main/resources/application.properties`: + +- **JDBC URL:** `jdbc:h2:mem:testdb` +- **Username:** `sa` +- **Password:** `password` + +Sample data is initialized from `infrastructure/src/main/resources/data.sql` on application startup. + +## When to Use the Onion Architecture Pattern in Java + +* When domain rules must be stable and independent from frameworks. +* When you want use cases to be testable without HTTP or database setup. +* When infrastructure details (web, JPA, database) should be replaceable. +* When dependency direction must be enforced from outer layers toward the domain core. + +## Onion Architecture Pattern Java Tutorials + +* [Clean Architecture with Spring Boot (Baeldung)](https://www.baeldung.com/spring-boot-clean-architecture) +* [Hexagonal Architecture Explained (Cockburn)](https://alistair.cockburn.us/hexagonal-architecture) +* [Spring Data JPA Reference](https://docs.spring.io/spring-data/jpa/reference/) + +## Benefits and Trade-offs of Microservices API Gateway Pattern + +Benefits: + +* Business validations are centralized in domain constructors (`Person`, `Category`). +* Use cases stay independent from Spring, JPA, and transport concerns. +* Repository abstraction (`PersonRepository`) keeps application logic persistence-agnostic. +* Testability is strong across layers (domain, use case, adapter, controller tests). + +Trade-offs: + +* Additional mapping code between domain models, DTOs, and JPA entities. +* More classes and modules than a simple CRUD-by-controller approach. +* Requires discipline to avoid leaking infrastructure concerns into domain/application. + +## Real-World Applications of Microservices API Gateway Pattern in Java + +* People/contact management services with strict data validation. +* Internal platforms where multiple delivery mechanisms (REST, batch, messaging) can share the same core domain. +* Systems that need incremental infrastructure evolution while preserving business logic. + +## Related Java Design Patterns + +* [Repository](https://martinfowler.com/eaaCatalog/repository.html) - `PersonRepository` defines the domain-facing persistence contract. +* [Adapter](https://refactoring.guru/design-patterns/adapter) - `PersonRepositoryAdapter` bridges domain model and Spring Data JPA. +* [Dependency Injection](https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html) - `ApplicationConfig` wires use case beans with repository implementations. + +## References and Credits + +* Project modules: `domain`, `application`, `infrastructure` +* Java 21 + Maven multi-module setup +* Spring Boot 3.3 (`spring-boot-starter-web`, `spring-boot-starter-data-jpa`, H2) +* Layer-focused tests in each module validating domain invariants and use case behavior + diff --git a/onion-architecture/application/pom.xml b/onion-architecture/application/pom.xml new file mode 100644 index 000000000000..eccdaae2869a --- /dev/null +++ b/onion-architecture/application/pom.xml @@ -0,0 +1,66 @@ + + + + 4.0.0 + + com.iluwatar + onion-architecture + 1.26.0-SNAPSHOT + + application + Application + + + + com.iluwatar + domain + ${project.version} + + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + org.mockito + mockito-core + test + + + + org.mockito + mockito-junit-jupiter + test + + + diff --git a/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/PersonResponse.java b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/PersonResponse.java new file mode 100644 index 000000000000..1586f30e48a1 --- /dev/null +++ b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/PersonResponse.java @@ -0,0 +1,37 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.dto; + +public record PersonResponse( + Long id, + String firstName, + String lastName, + int age, + String phoneNumber, + String email, + Long categoryId, + String categoryType) {} diff --git a/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/SavePersonCommand.java b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/SavePersonCommand.java new file mode 100644 index 000000000000..649db88a4ab5 --- /dev/null +++ b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/dto/SavePersonCommand.java @@ -0,0 +1,37 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.dto; + +public record SavePersonCommand( + String firstName, + String lastName, + int age, + String phoneNumber, + String email, + String address, + Long categoryId, + String categoryType) {} diff --git a/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/GetPersonUseCase.java b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/GetPersonUseCase.java new file mode 100644 index 000000000000..abae6a32196a --- /dev/null +++ b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/GetPersonUseCase.java @@ -0,0 +1,75 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.usecase; + +import com.iluwatar.onion.application.dto.PersonResponse; +import com.iluwatar.onion.domain.repository.PersonRepository; +import java.util.Collection; +import java.util.List; + +public class GetPersonUseCase { + + private final PersonRepository repository; + + public GetPersonUseCase(PersonRepository repository) { + this.repository = repository; + } + + public PersonResponse execute(Long id) { + var person = + repository + .findById(id) + .orElseThrow(() -> new RuntimeException("Person not found with id: " + id)); + + return new PersonResponse( + person.getId(), + person.getFirstName(), + person.getLastName(), + person.getAge(), + person.getPhoneNumber(), + person.getEmail(), + person.getCategory().getId(), + person.getCategory().getType()); + } + + public List executeAll() { + return repository.findAll().stream() + .flatMap(Collection::stream) + .map( + person -> + new PersonResponse( + person.getId(), + person.getFirstName(), + person.getLastName(), + person.getAge(), + person.getPhoneNumber(), + person.getEmail(), + person.getCategory().getId(), + person.getCategory().getType())) + .toList(); + } +} diff --git a/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/SavePersonUseCase.java b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/SavePersonUseCase.java new file mode 100644 index 000000000000..8d63e2612fab --- /dev/null +++ b/onion-architecture/application/src/main/java/com/iluwatar/onion/application/usecase/SavePersonUseCase.java @@ -0,0 +1,67 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.usecase; + +import com.iluwatar.onion.application.dto.PersonResponse; +import com.iluwatar.onion.application.dto.SavePersonCommand; +import com.iluwatar.onion.domain.model.Category; +import com.iluwatar.onion.domain.model.Person; +import com.iluwatar.onion.domain.repository.PersonRepository; + +public class SavePersonUseCase { + + private final PersonRepository repository; + + public SavePersonUseCase(PersonRepository repository) { + this.repository = repository; + } + + public PersonResponse execute(SavePersonCommand command) { + var category = new Category(command.categoryId(), command.categoryType()); + var person = + new Person( + null, + command.firstName(), + command.lastName(), + command.age(), + command.phoneNumber(), + command.email(), + category); + + var savedPerson = repository.save(person); + + return new PersonResponse( + savedPerson.getId(), + savedPerson.getFirstName(), + savedPerson.getLastName(), + savedPerson.getAge(), + savedPerson.getPhoneNumber(), + savedPerson.getEmail(), + savedPerson.getCategory().getId(), + savedPerson.getCategory().getType()); + } +} diff --git a/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/GetPersonUseCaseTest.java b/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/GetPersonUseCaseTest.java new file mode 100644 index 000000000000..f9de119c2309 --- /dev/null +++ b/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/GetPersonUseCaseTest.java @@ -0,0 +1,193 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.usecase; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import com.iluwatar.onion.application.dto.PersonResponse; +import com.iluwatar.onion.domain.model.Category; +import com.iluwatar.onion.domain.model.Person; +import com.iluwatar.onion.domain.repository.PersonRepository; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class GetPersonUseCaseTest { + + @Mock private PersonRepository personRepository; + + private GetPersonUseCase getPersonUseCase; + + @BeforeEach + void setUp() { + getPersonUseCase = new GetPersonUseCase(personRepository); + } + + @Nested + @DisplayName("Execute by ID - Happy Path") + class ExecuteByIdHappyPath { + + @Test + @DisplayName("Should return PersonResponse when person exists") + void shouldReturnPersonResponseWhenPersonExists() { + // Arrange + var person = + new Person( + 1L, + "John", + "Doe", + 25, + "+1234567890", + "john.doe@example.com", + new Category(1L, "Professional")); + + when(personRepository.findById(1L)).thenReturn(Optional.of(person)); + + // Act + var response = getPersonUseCase.execute(1L); + + // Assert + assertNotNull(response); + assertEquals(1L, response.id()); + assertEquals("John", response.firstName()); + assertEquals("Doe", response.lastName()); + assertEquals(25, response.age()); + assertEquals("+1234567890", response.phoneNumber()); + assertEquals("john.doe@example.com", response.email()); + assertEquals(1L, response.categoryId()); + assertEquals("Professional", response.categoryType()); + + verify(personRepository, times(1)).findById(1L); + } + } + + @Nested + @DisplayName("Execute by ID - Error Cases") + class ExecuteByIdErrorCases { + + @Test + @DisplayName("Should throw RuntimeException when person not found") + void shouldThrowExceptionWhenPersonNotFound() { + // Arrange + when(personRepository.findById(999L)).thenReturn(Optional.empty()); + + // Act & Assert + var exception = assertThrows(RuntimeException.class, () -> getPersonUseCase.execute(999L)); + assertTrue(exception.getMessage().contains("Person not found with id: 999")); + + verify(personRepository, times(1)).findById(999L); + } + + @Test + @DisplayName("Should propagate exception when repository throws exception") + void shouldPropagateExceptionWhenRepositoryFails() { + // Arrange + when(personRepository.findById(anyLong())).thenThrow(new RuntimeException("Database error")); + + // Act & Assert + var exception = assertThrows(RuntimeException.class, () -> getPersonUseCase.execute(1L)); + assertTrue(exception.getMessage().contains("Database error")); + + verify(personRepository, times(1)).findById(1L); + } + } + + @Nested + @DisplayName("Execute All - Happy Path") + class ExecuteAllHappyPath { + + @Test + @DisplayName("Should return list of PersonResponses") + void shouldReturnListOfPersonResponses() { + // Arrange + var person1 = + new Person( + 1L, + "John", + "Doe", + 30, + "+9876543255", + "john.doe@example.com", + new Category(2L, "Personal")); + + var person2 = + new Person( + 2L, + "Jane", + "Smith", + 25, + "+9876543210", + "jane.smith@example.com", + new Category(2L, "Personal")); + + when(personRepository.findAll()).thenReturn(Optional.of(List.of(person1, person2))); + + // Act + var responses = getPersonUseCase.executeAll(); + + // Assert + assertNotNull(responses); + assertEquals(2, responses.size()); + + PersonResponse response1 = responses.get(0); + assertEquals(1L, response1.id()); + assertEquals("John", response1.firstName()); + assertEquals("Doe", response1.lastName()); + + PersonResponse response2 = responses.get(1); + assertEquals(2L, response2.id()); + assertEquals("Jane", response2.firstName()); + assertEquals("Smith", response2.lastName()); + + verify(personRepository, times(1)).findAll(); + } + + @Test + @DisplayName("Should return empty list when no persons found") + void shouldReturnEmptyListWhenNoPersonsFound() { + // Arrange + when(personRepository.findAll()).thenReturn(Optional.of(List.of())); + + // Act + List responses = getPersonUseCase.executeAll(); + + // Assert + assertNotNull(responses); + assertTrue(responses.isEmpty()); + + verify(personRepository, times(1)).findAll(); + } + } +} diff --git a/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/SavePersonUseCaseTest.java b/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/SavePersonUseCaseTest.java new file mode 100644 index 000000000000..434147ae6495 --- /dev/null +++ b/onion-architecture/application/src/test/java/com/iluwatar/onion/application/usecase/SavePersonUseCaseTest.java @@ -0,0 +1,253 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.application.usecase; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import com.iluwatar.onion.application.dto.SavePersonCommand; +import com.iluwatar.onion.domain.exception.DomainException; +import com.iluwatar.onion.domain.model.Category; +import com.iluwatar.onion.domain.model.Person; +import com.iluwatar.onion.domain.repository.PersonRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class SavePersonUseCaseTest { + + @Mock private PersonRepository personRepository; + + @Captor private ArgumentCaptor personCaptor; + + private SavePersonUseCase savePersonUseCase; + + @BeforeEach + void setUp() { + savePersonUseCase = new SavePersonUseCase(personRepository); + } + + @Nested + @DisplayName("Execute - Happy Path") + class ExecuteHappyPath { + + @Test + @DisplayName("Should save person and return PersonResponse") + void shouldSavePersonAndReturnResponse() { + // Arrange + var command = + new SavePersonCommand( + "John", + "Doe", + 25, + "+1234567890", + "john.doe@example.com", + "123 Main St", + 1L, + "Professional"); + + var category = new Category(1L, "Professional"); + var savedPerson = + new Person( + 100L, // ID generated by database + "John", + "Doe", + 25, + "+1234567890", + "john.doe@example.com", + category); + + when(personRepository.save(any(Person.class))).thenReturn(savedPerson); + + // Act + var response = savePersonUseCase.execute(command); + + // Assert + assertNotNull(response); + assertEquals(100L, response.id()); + assertEquals("John", response.firstName()); + assertEquals("Doe", response.lastName()); + assertEquals(25, response.age()); + assertEquals("+1234567890", response.phoneNumber()); + assertEquals("john.doe@example.com", response.email()); + assertEquals(1L, response.categoryId()); + assertEquals("Professional", response.categoryType()); + + // Verify repository interaction + verify(personRepository, times(1)).save(any(Person.class)); + } + + @Test + @DisplayName("Should pass correct Person object to repository") + void shouldPassCorrectPersonToRepository() { + // Arrange + var command = + new SavePersonCommand( + "Jane", + "Smith", + 30, + "+9876543210", + "jane.smith@example.com", + "456 Oak Ave", + 2L, + "Personal"); + + var category = new Category(2L, "Personal"); + var savedPerson = + new Person(200L, "Jane", "Smith", 30, "+9876543210", "jane.smith@example.com", category); + + when(personRepository.save(any(Person.class))).thenReturn(savedPerson); + + // Act + savePersonUseCase.execute(command); + + // Assert - Verify what was passed to repository + verify(personRepository).save(personCaptor.capture()); + var capturedPerson = personCaptor.getValue(); + + assertNull(capturedPerson.getId()); // New person should have null ID + assertEquals("Jane", capturedPerson.getFirstName()); + assertEquals("Smith", capturedPerson.getLastName()); + assertEquals(30, capturedPerson.getAge()); + assertEquals("+9876543210", capturedPerson.getPhoneNumber()); + assertEquals("jane.smith@example.com", capturedPerson.getEmail()); + assertEquals("Personal", capturedPerson.getCategory().getType()); + } + } + + @Nested + @DisplayName("Execute - Validation Failures") + class ExecuteValidationFailures { + + @Test + @DisplayName("Should throw DomainException when age is less than 18") + void shouldThrowExceptionWhenAgeIsInvalid() { + // Arrange + var command = + new SavePersonCommand( + "Young", + "Person", + 17, // Invalid age + "+1234567890", + "young@example.com", + "123 Main St", + 1L, + "Student"); + + // Act & Assert + var exception = assertThrows(DomainException.class, () -> savePersonUseCase.execute(command)); + assertTrue(exception.getMessage().contains("Age cannot be less than 18")); + + // Verify repository was never called + verify(personRepository, never()).save(any(Person.class)); + } + + @Test + @DisplayName("Should throw DomainException when email is empty") + void shouldThrowExceptionWhenEmailIsEmpty() { + // Arrange + var command = + new SavePersonCommand( + "John", + "Doe", + 25, + "+1234567890", + "", // Empty email + "123 Main St", + 1L, + "Professional"); + + // Act & Assert + var exception = assertThrows(DomainException.class, () -> savePersonUseCase.execute(command)); + assertTrue(exception.getMessage().contains("Email cannot be null or empty")); + + verify(personRepository, never()).save(any(Person.class)); + } + + @Test + @DisplayName("Should throw DomainException when category type is invalid") + void shouldThrowExceptionWhenCategoryTypeIsInvalid() { + // Arrange + var command = + new SavePersonCommand( + "John", + "Doe", + 25, + "+1234567890", + "john@example.com", + "123 Main St", + 1L, + "" // Empty category type + ); + + // Act & Assert + var exception = assertThrows(DomainException.class, () -> savePersonUseCase.execute(command)); + assertTrue(exception.getMessage().contains("Type is null or empty")); + + verify(personRepository, never()).save(any(Person.class)); + } + } + + @Nested + @DisplayName("Execute - Repository Exceptions") + class ExecuteRepositoryExceptions { + + @Test + @DisplayName("Should propagate exception when repository fails") + void shouldPropagateExceptionWhenRepositoryFails() { + // Arrange + var command = + new SavePersonCommand( + "John", + "Doe", + 25, + "+1234567890", + "john.doe@example.com", + "123 Main St", + 1L, + "Professional"); + + when(personRepository.save(any(Person.class))) + .thenThrow(new RuntimeException("Database connection failed")); + + // Act & Assert + var exception = + assertThrows(RuntimeException.class, () -> savePersonUseCase.execute(command)); + assertTrue(exception.getMessage().contains("Database connection failed")); + + verify(personRepository, times(1)).save(any(Person.class)); + } + } +} diff --git a/onion-architecture/domain/pom.xml b/onion-architecture/domain/pom.xml new file mode 100644 index 000000000000..d1efc50def12 --- /dev/null +++ b/onion-architecture/domain/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + com.iluwatar + onion-architecture + 1.26.0-SNAPSHOT + + domain + Domain + + + + + org.junit.jupiter + junit-jupiter-engine + test + + + diff --git a/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/exception/DomainException.java b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/exception/DomainException.java new file mode 100644 index 000000000000..5e0831a57c02 --- /dev/null +++ b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/exception/DomainException.java @@ -0,0 +1,34 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.exception; + +public class DomainException extends RuntimeException { + + public DomainException(String message) { + super(message); + } +} diff --git a/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Category.java b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Category.java new file mode 100644 index 000000000000..8380f4e849ee --- /dev/null +++ b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Category.java @@ -0,0 +1,51 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.model; + +import com.iluwatar.onion.domain.exception.DomainException; + +public class Category { + + private final Long id; + private final String type; + + public Category(Long id, String type) { + if (type == null || type.isEmpty()) { + throw new DomainException("Type is null or empty. Category type is required."); + } + this.id = id; + this.type = type; + } + + public Long getId() { + return id; + } + + public String getType() { + return type; + } +} diff --git a/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Person.java b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Person.java new file mode 100644 index 000000000000..55eced0be29a --- /dev/null +++ b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/model/Person.java @@ -0,0 +1,121 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.model; + +import com.iluwatar.onion.domain.exception.DomainException; + +public class Person { + + private final Long id; + private final String firstName; + private final String lastName; + private final int age; + private final String phoneNumber; + private final String email; + private final Category category; + + public Person( + Long id, + String firstName, + String lastName, + int age, + String phoneNumber, + String email, + Category category) { + validateNames(firstName, lastName); + validateAge(age); + validatePhone(phoneNumber); + validateEmail(email); + validateCategory(category); + + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.phoneNumber = phoneNumber; + this.email = email; + this.category = category; + } + + private void validateNames(String firstName, String lastName) { + if (firstName == null || lastName == null) { + throw new DomainException("First name and last name cannot be null."); + } + } + + private void validateAge(int age) { + if (age < 18) { + throw new DomainException("Age cannot be less than 18."); + } + } + + private void validatePhone(String phone) { + if (phone == null || phone.isEmpty()) { + throw new DomainException("Phone number cannot be null or empty."); + } + } + + private void validateEmail(String email) { + if (email == null || email.isEmpty()) { + throw new DomainException("Email cannot be null or empty."); + } + } + + private void validateCategory(Category category) { + if (category == null || category.getType().isEmpty()) { + throw new DomainException("Category cannot be null or empty."); + } + } + + public Long getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public int getAge() { + return age; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getEmail() { + return email; + } + + public Category getCategory() { + return category; + } +} diff --git a/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/repository/PersonRepository.java b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/repository/PersonRepository.java new file mode 100644 index 000000000000..c14aa24a8ef6 --- /dev/null +++ b/onion-architecture/domain/src/main/java/com/iluwatar/onion/domain/repository/PersonRepository.java @@ -0,0 +1,45 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.repository; + +import com.iluwatar.onion.domain.model.Person; +import java.util.List; +import java.util.Optional; + +public interface PersonRepository { + Optional findById(Long id); + + Optional findByFirstName(String firstName); + + Optional findByLastName(String lastName); + + Optional> findAll(); + + Person save(Person person); + + boolean deleteById(Long id); +} diff --git a/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/CategoryTest.java b/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/CategoryTest.java new file mode 100644 index 000000000000..82e88285c35b --- /dev/null +++ b/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/CategoryTest.java @@ -0,0 +1,75 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.model; + +import static org.junit.jupiter.api.Assertions.*; + +import com.iluwatar.onion.domain.exception.DomainException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CategoryTest { + + @Test + @DisplayName("Should create category with valid data") + void shouldCreateCategoryWithValidData() { + // Arrange & Act + var category = new Category(1L, "Professional"); + + // Assert + assertNotNull(category); + assertEquals(1L, category.getId()); + assertEquals("Professional", category.getType()); + } + + @Test + @DisplayName("Should create category with null id") + void shouldCreateCategoryWithNullId() { + // Arrange & Act + var category = new Category(null, "Personal"); + + // Assert + assertNull(category.getId()); + assertEquals("Personal", category.getType()); + } + + @Test + @DisplayName("Should throw exception when type is null") + void shouldThrowExceptionWhenTypeIsNull() { + // Act & Assert + var exception = assertThrows(DomainException.class, () -> new Category(1L, null)); + assertTrue(exception.getMessage().contains("Type is null or empty")); + } + + @Test + @DisplayName("Should throw exception when type is empty") + void shouldThrowExceptionWhenTypeIsEmpty() { + // Act & Assert + var exception = assertThrows(DomainException.class, () -> new Category(1L, "")); + assertTrue(exception.getMessage().contains("Type is null or empty")); + } +} diff --git a/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/PersonTest.java b/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/PersonTest.java new file mode 100644 index 000000000000..8f5bef0da1a6 --- /dev/null +++ b/onion-architecture/domain/src/test/java/com/iluwatar/onion/domain/model/PersonTest.java @@ -0,0 +1,179 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.domain.model; + +import static org.junit.jupiter.api.Assertions.*; + +import com.iluwatar.onion.domain.exception.DomainException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +class PersonTest { + + private final Category validCategory = new Category(1L, "Professional"); + + @Nested + @DisplayName("Person Creation - Valid Cases") + class ValidPersonCreation { + + @Test + @DisplayName("Should create person with valid data") + void shouldCreatePersonWithValidData() { + // Arrange & Act + var person = + new Person(1L, "John", "Doe", 25, "+1234567890", "john.doe@example.com", validCategory); + + // Assert + assertNotNull(person); + assertEquals(1L, person.getId()); + assertEquals("John", person.getFirstName()); + assertEquals("Doe", person.getLastName()); + assertEquals(25, person.getAge()); + assertEquals("+1234567890", person.getPhoneNumber()); + assertEquals("john.doe@example.com", person.getEmail()); + assertEquals(validCategory, person.getCategory()); + } + + @Test + @DisplayName("Should create person with minimum valid age (18)") + void shouldCreatePersonWithMinimumValidAge() { + // Arrange & Act + var person = + new Person( + null, + "Jane", + "Smith", + 18, // minimum valid age + "+9876543210", + "jane@example.com", + validCategory); + + // Assert + assertEquals(18, person.getAge()); + } + } + + @Nested + @DisplayName("Person Creation - Invalid Cases") + class InvalidPersonCreation { + + @Test + @DisplayName("Should throw exception when first name is null") + void shouldThrowExceptionWhenFirstNameIsNull() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> + new Person( + 1L, null, "Doe", 25, "+1234567890", "john@example.com", validCategory)); + assertTrue(exception.getMessage().contains("First name and last name cannot be null")); + } + + @Test + @DisplayName("Should throw exception when last name is null") + void shouldThrowExceptionWhenLastNameIsNull() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> + new Person( + 1L, "John", null, 25, "+1234567890", "john@example.com", validCategory)); + assertTrue(exception.getMessage().contains("First name and last name cannot be null")); + } + + @Test + @DisplayName("Should throw exception when age is less than 18") + void shouldThrowExceptionWhenAgeIsLessThan18() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> + new Person( + 1L, "John", "Doe", 17, "+1234567890", "john@example.com", validCategory)); + assertTrue(exception.getMessage().contains("Age cannot be less than 18")); + } + + @Test + @DisplayName("Should throw exception when phone number is null") + void shouldThrowExceptionWhenPhoneIsNull() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> new Person(1L, "John", "Doe", 25, null, "john@example.com", validCategory)); + assertTrue(exception.getMessage().contains("Phone number cannot be null or empty")); + } + + @Test + @DisplayName("Should throw exception when phone number is empty") + void shouldThrowExceptionWhenPhoneIsEmpty() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> new Person(1L, "John", "Doe", 25, "", "john@example.com", validCategory)); + assertTrue(exception.getMessage().contains("Phone number cannot be null or empty")); + } + + @Test + @DisplayName("Should throw exception when email is null") + void shouldThrowExceptionWhenEmailIsNull() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> new Person(1L, "John", "Doe", 25, "+1234567890", null, validCategory)); + assertTrue(exception.getMessage().contains("Email cannot be null or empty")); + } + + @Test + @DisplayName("Should throw exception when email is empty") + void shouldThrowExceptionWhenEmailIsEmpty() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> new Person(1L, "John", "Doe", 25, "+1234567890", "", validCategory)); + assertTrue(exception.getMessage().contains("Email cannot be null or empty")); + } + + @Test + @DisplayName("Should throw exception when category is null") + void shouldThrowExceptionWhenCategoryIsNull() { + // Act & Assert + var exception = + assertThrows( + DomainException.class, + () -> new Person(1L, "John", "Doe", 25, "+1234567890", "john@example.com", null)); + assertTrue(exception.getMessage().contains("Category cannot be null or empty")); + } + } +} diff --git a/onion-architecture/etc/onion-architecture.png b/onion-architecture/etc/onion-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..82f34e3d7fd18dee5bc526226f74c1a633d5fe3e GIT binary patch literal 258593 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�a|MrvloacCFYpZ<1dwz#)`?93 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ƙ@3WcVA6#V+HQr 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 #FFF9C4 + BorderColor<> #F9A825 + FontColor<> #5D4037 + FontStyle<> bold +} + +skinparam package { + BackgroundColor<> #C8E6C9 + BorderColor<> #388E3C + FontColor<> #1B5E20 + FontStyle<> bold +} + +skinparam package { + BackgroundColor<> #BBDEFB + BorderColor<> #1976D2 + FontColor<> #0D47A1 + FontStyle<> bold +} + +' ───────────────────────────────────────────────────────────────────────────── +' DOMAIN LAYER (innermost) +' ───────────────────────────────────────────────────────────────────────────── +package "Domain Layer" <> { + + package "model" { + class Person { + - id : Long + - firstName : String + - lastName : String + - age : int + - phoneNumber : String + - email : String + - category : Category + + getId() : Long + + getFirstName() : String + + getLastName() : String + + getAge() : int + + getPhoneNumber() : String + + getEmail() : String + + getCategory() : Category + } + + class Category { + - id : Long + - type : String + + getId() : Long + + getType() : String + } + } + + package "repository" { + interface PersonRepository { + + findById(id : Long) : Optional + + findByFirstName(firstName : String) : Optional + + findByLastName(lastName : String) : Optional + + findAll() : Optional> + + save(person : Person) : Person + + deleteById(id : Long) : boolean + } + } + + package "exception" { + class DomainException { + + DomainException(message : String) + } + } +} + +' ───────────────────────────────────────────────────────────────────────────── +' APPLICATION LAYER +' ───────────────────────────────────────────────────────────────────────────── +package "Application Layer" <> { + + package "usecase" { + class SavePersonUseCase { + - repository : PersonRepository + + SavePersonUseCase(repository : PersonRepository) + + execute(command : SavePersonCommand) : PersonResponse + } + + class GetPersonUseCase { + - repository : PersonRepository + + GetPersonUseCase(repository : PersonRepository) + + execute(id : Long) : PersonResponse + + executeAll() : List + } + } + + package "dto" { + class SavePersonCommand <> { + firstName : String + lastName : String + age : int + phoneNumber : String + email : String + address : String + categoryId : Long + categoryType : String + } + + class PersonResponse <> { + id : Long + firstName : String + lastName : String + age : int + phoneNumber : String + email : String + categoryId : Long + categoryType : String + } + } +} + +' ───────────────────────────────────────────────────────────────────────────── +' INFRASTRUCTURE LAYER (outermost) +' ───────────────────────────────────────────────────────────────────────────── +package "Infrastructure Layer" <> { + + package "web" { + class PersonController { + - savePersonUseCase : SavePersonUseCase + - getPersonUseCase : GetPersonUseCase + + getPerson(id : Long) : ResponseEntity + + getAllPersons() : ResponseEntity> + + savePerson(command : SavePersonCommand) : ResponseEntity + } + } + + package "persistence" { + class PersonRepositoryAdapter { + - repository : SpringDataPersonRepository + + findById(id : Long) : Optional + + findByFirstName(firstName : String) : Optional + + findByLastName(lastName : String) : Optional + + findAll() : Optional> + + save(person : Person) : Person + + deleteById(id : Long) : boolean + } + + interface SpringDataPersonRepository { + + findByFirstName(firstName : String) : Optional + + findByLastName(lastName : String) : Optional + } + + class JpaPersonEntity { + - id : Long + - firstName : String + - lastName : String + - age : int + - phoneNumber : String + - email : String + - category : JpaCategoryEntity + } + + class JpaCategoryEntity { + - id : Long + - type : String + } + } + + package "config" { + class ApplicationConfig <<@Configuration>> { + + savePersonUseCase(repo : PersonRepository) : SavePersonUseCase + + getPersonUseCase(repo : PersonRepository) : GetPersonUseCase + } + + class Application <<@SpringBootApplication>> { + + main(args : String[]) + } + } +} + +' ───────────────────────────────────────────────────────────────────────────── +' DOMAIN: internal relationships +' ───────────────────────────────────────────────────────────────────────────── +Person "1" *-- "1" Category : has +Person ..> DomainException : <> +Category ..> DomainException : <> + +' ───────────────────────────────────────────────────────────────────────────── +' APPLICATION → DOMAIN +' ───────────────────────────────────────────────────────────────────────────── +SavePersonUseCase --> PersonRepository : uses +SavePersonUseCase ..> Person : creates +SavePersonUseCase ..> Category : creates +SavePersonUseCase ..> PersonResponse : returns +SavePersonUseCase ..> SavePersonCommand : receives + +GetPersonUseCase --> PersonRepository : uses +GetPersonUseCase ..> PersonResponse : returns + +' ───────────────────────────────────────────────────────────────────────────── +' INFRASTRUCTURE → APPLICATION / DOMAIN +' ───────────────────────────────────────────────────────────────────────────── +PersonController --> SavePersonUseCase : delegates to +PersonController --> GetPersonUseCase : delegates to +PersonController ..> DomainException : catches + +PersonRepositoryAdapter ..|> PersonRepository : implements +PersonRepositoryAdapter --> SpringDataPersonRepository : uses +PersonRepositoryAdapter ..> JpaPersonEntity : maps +PersonRepositoryAdapter ..> JpaCategoryEntity : maps +PersonRepositoryAdapter ..> Person : maps to / from +PersonRepositoryAdapter ..> Category : maps to / from + +SpringDataPersonRepository --> JpaPersonEntity : manages +JpaPersonEntity "1" *-- "1" JpaCategoryEntity : contains + +ApplicationConfig ..> SavePersonUseCase : <<@Bean>> +ApplicationConfig ..> GetPersonUseCase : <<@Bean>> +ApplicationConfig --> PersonRepository : injects + +legend right + Layer dependency rule + Infrastructure → Application → Domain + Outer layers depend on inner layers. + Domain has NO external dependencies. + ---- + ■ Domain Layer + ■ Application Layer + ■ Infrastructure Layer +endlegend + +@enduml + diff --git a/onion-architecture/etc/postman/onion-architecture.postman_collection.json b/onion-architecture/etc/postman/onion-architecture.postman_collection.json new file mode 100644 index 000000000000..ed0cbd5c58f5 --- /dev/null +++ b/onion-architecture/etc/postman/onion-architecture.postman_collection.json @@ -0,0 +1,83 @@ +{ + "info": { + "_postman_id": "79aca374-7080-46c1-938f-89b327a84d6a", + "name": "onion-architecture", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "51221021", + "_collection_link": "https://go.postman.co/collection/51221021-79aca374-7080-46c1-938f-89b327a84d6a?source=collection_link" + }, + "item": [ + { + "name": "savePerson", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"number1\": 5,\r\n \"number2\": 3,\r\n \"operation\": \"multiply\"\r\n }" + }, + "url": { + "raw": "http://localhost:8080/api/persons", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "api", + "persons" + ] + } + }, + "response": [] + }, + { + "name": "getPersons", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"number1\": 5,\r\n \"number2\": 3,\r\n \"operation\": \"multiply\"\r\n }" + }, + "url": { + "raw": "http://localhost:8080/api/persons", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "api", + "persons" + ] + } + }, + "response": [] + }, + { + "name": "getPersonById", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/api/persons/1", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "api", + "persons", + "1" + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file diff --git a/onion-architecture/infrastructure/pom.xml b/onion-architecture/infrastructure/pom.xml new file mode 100644 index 000000000000..d26e2a7ef69d --- /dev/null +++ b/onion-architecture/infrastructure/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + com.iluwatar + onion-architecture + 1.26.0-SNAPSHOT + + infrastructure + Infrastructure + + + + com.iluwatar + domain + ${project.version} + + + + com.iluwatar + application + ${project.version} + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + com.h2database + h2 + runtime + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/Application.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/Application.java new file mode 100644 index 000000000000..c86c95740599 --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/Application.java @@ -0,0 +1,38 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/config/ApplicationConfig.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/config/ApplicationConfig.java new file mode 100644 index 000000000000..7794c91e3bcf --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/config/ApplicationConfig.java @@ -0,0 +1,47 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.config; + +import com.iluwatar.onion.application.usecase.GetPersonUseCase; +import com.iluwatar.onion.application.usecase.SavePersonUseCase; +import com.iluwatar.onion.domain.repository.PersonRepository; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class ApplicationConfig { + + @Bean + public SavePersonUseCase savePersonUseCase(PersonRepository repository) { + return new SavePersonUseCase(repository); + } + + @Bean + public GetPersonUseCase getPersonUseCase(PersonRepository repository) { + return new GetPersonUseCase(repository); + } +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaCategoryEntity.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaCategoryEntity.java new file mode 100644 index 000000000000..aafd242992be --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaCategoryEntity.java @@ -0,0 +1,55 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.persistence; + +import jakarta.persistence.*; + +@Entity +@Table(name = "category") +public class JpaCategoryEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String type; + + public JpaCategoryEntity() {} + + public JpaCategoryEntity(Long id, String type) { + this.id = id; + this.type = type; + } + + public Long getId() { + return id; + } + + public String getType() { + return type; + } +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaPersonEntity.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaPersonEntity.java new file mode 100644 index 000000000000..bf71b5306c92 --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/JpaPersonEntity.java @@ -0,0 +1,93 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.persistence; + +import jakarta.persistence.*; + +@Entity +@Table(name = "person") +public class JpaPersonEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String firstName; + private String lastName; + private int age; + private String phoneNumber; + private String email; + + @ManyToOne private JpaCategoryEntity category; + + public JpaPersonEntity() {} + + public JpaPersonEntity( + Long id, + String firstName, + String lastName, + int age, + String phoneNumber, + String email, + JpaCategoryEntity category) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.phoneNumber = phoneNumber; + this.email = email; + this.category = category; + } + + public Long getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public int getAge() { + return age; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getEmail() { + return email; + } + + public JpaCategoryEntity getCategory() { + return category; + } +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapter.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapter.java new file mode 100644 index 000000000000..4c4aa267493a --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapter.java @@ -0,0 +1,102 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.persistence; + +import com.iluwatar.onion.domain.model.Category; +import com.iluwatar.onion.domain.model.Person; +import com.iluwatar.onion.domain.repository.PersonRepository; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.springframework.stereotype.Repository; + +@Repository +public class PersonRepositoryAdapter implements PersonRepository { + + private final SpringDataPersonRepository repository; + + public PersonRepositoryAdapter(SpringDataPersonRepository repository) { + this.repository = repository; + } + + @Override + public Optional findById(Long id) { + return repository.findById(id).map(this::mapToDomain); + } + + @Override + public Optional findByFirstName(String firstName) { + return repository.findByFirstName(firstName).map(this::mapToDomain); + } + + @Override + public Optional findByLastName(String lastName) { + return repository.findByLastName(lastName).map(this::mapToDomain); + } + + @Override + public Optional> findAll() { + return repository.findAll().stream() + .map(this::mapToDomain) + .collect(Collectors.collectingAndThen(Collectors.toList(), Optional::of)); + } + + @Override + public Person save(Person person) { + JpaPersonEntity entity = mapToEntity(person); + JpaPersonEntity savedEntity = repository.save(entity); + return mapToDomain(savedEntity); + } + + @Override + public boolean deleteById(Long id) { + repository.deleteById(id); + return repository.findById(id).isEmpty(); + } + + private JpaPersonEntity mapToEntity(Person person) { + return new JpaPersonEntity( + person.getId(), + person.getFirstName(), + person.getLastName(), + person.getAge(), + person.getPhoneNumber(), + person.getEmail(), + new JpaCategoryEntity(person.getCategory().getId(), person.getCategory().getType())); + } + + private Person mapToDomain(JpaPersonEntity entity) { + return new Person( + entity.getId(), + entity.getFirstName(), + entity.getLastName(), + entity.getAge(), + entity.getPhoneNumber(), + entity.getEmail(), + new Category(entity.getCategory().getId(), entity.getCategory().getType())); + } +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/SpringDataPersonRepository.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/SpringDataPersonRepository.java new file mode 100644 index 000000000000..35f86515c70b --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/persistence/SpringDataPersonRepository.java @@ -0,0 +1,37 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.persistence; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface SpringDataPersonRepository extends JpaRepository { + + Optional findByFirstName(String firstName); + + Optional findByLastName(String lastName); +} diff --git a/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/web/PersonController.java b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/web/PersonController.java new file mode 100644 index 000000000000..417e749f41a6 --- /dev/null +++ b/onion-architecture/infrastructure/src/main/java/com/iluwatar/onion/infrastructure/web/PersonController.java @@ -0,0 +1,72 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.web; + +import com.iluwatar.onion.application.dto.PersonResponse; +import com.iluwatar.onion.application.dto.SavePersonCommand; +import com.iluwatar.onion.application.usecase.GetPersonUseCase; +import com.iluwatar.onion.application.usecase.SavePersonUseCase; +import com.iluwatar.onion.domain.exception.DomainException; +import java.util.List; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/api") +public class PersonController { + + private final SavePersonUseCase savePersonUseCase; + private final GetPersonUseCase getPersonUseCase; + + public PersonController(SavePersonUseCase savePersonUseCase, GetPersonUseCase getPersonUseCase) { + this.savePersonUseCase = savePersonUseCase; + this.getPersonUseCase = getPersonUseCase; + } + + @GetMapping("/persons/{id}") + public ResponseEntity getPerson(@PathVariable("id") Long id) { + var person = getPersonUseCase.execute(id); + return ResponseEntity.ok(person); + } + + @GetMapping("/persons") + public ResponseEntity> getAllPersons() { + var persons = getPersonUseCase.executeAll(); + return ResponseEntity.ok(persons); + } + + @PostMapping("/persons") + public ResponseEntity savePerson(@RequestBody SavePersonCommand command) { + try { + var savedPerson = savePersonUseCase.execute(command); + return ResponseEntity.status(HttpStatus.OK).body(savedPerson); + } catch (DomainException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } + } +} diff --git a/onion-architecture/infrastructure/src/main/resources/application.properties b/onion-architecture/infrastructure/src/main/resources/application.properties new file mode 100644 index 000000000000..6a3ed156f558 --- /dev/null +++ b/onion-architecture/infrastructure/src/main/resources/application.properties @@ -0,0 +1,19 @@ +# You can also specify the server port in the application.properties file. +# Uncomment the following line and set the desired port number to change +# the default port (8080) to a different value. +#server.port=8080 + +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# Force Spring Boot to always run SQL initialization scripts on startup +spring.sql.init.mode=always + +# If using Spring Data JPA / Hibernate, defer data insertion until AFTER entities are generated +spring.jpa.defer-datasource-initialization=true + +# Keep Hibernate's DDL generation active (or set to 'update') +spring.jpa.hibernate.ddl-auto=create-drop diff --git a/onion-architecture/infrastructure/src/main/resources/data.sql b/onion-architecture/infrastructure/src/main/resources/data.sql new file mode 100644 index 000000000000..6291dd984e31 --- /dev/null +++ b/onion-architecture/infrastructure/src/main/resources/data.sql @@ -0,0 +1,4 @@ +INSERT INTO category (id, type) VALUES (1, 'Teenage'); +INSERT INTO category (id, type) VALUES (2, 'Young Adult'); +INSERT INTO category (id, type) VALUES (3, 'Adult'); +INSERT INTO category (id, type) VALUES (4, 'Senior'); \ No newline at end of file diff --git a/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapterTest.java b/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapterTest.java new file mode 100644 index 000000000000..49fd2816f172 --- /dev/null +++ b/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/persistence/PersonRepositoryAdapterTest.java @@ -0,0 +1,332 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.persistence; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +import com.iluwatar.onion.domain.model.Category; +import com.iluwatar.onion.domain.model.Person; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class PersonRepositoryAdapterTest { + + @Mock private SpringDataPersonRepository springDataRepository; + + @Captor private ArgumentCaptor entityCaptor; + + private PersonRepositoryAdapter personRepositoryAdapter; + private JpaPersonEntity jpaPersonEntity; + + @BeforeEach + void setUp() { + personRepositoryAdapter = new PersonRepositoryAdapter(springDataRepository); + + // Setup test data + var jpaCategory = new JpaCategoryEntity(1L, "Professional"); + jpaPersonEntity = + new JpaPersonEntity( + 1L, "John", "Doe", 25, "+1234567890", "john.doe@example.com", jpaCategory); + } + + @Nested + @DisplayName("Find By ID") + class FindById { + + @Test + @DisplayName("Should return Person when entity exists") + void shouldReturnPersonWhenEntityExists() { + // Arrange + when(springDataRepository.findById(1L)).thenReturn(Optional.of(jpaPersonEntity)); + + // Act + var result = personRepositoryAdapter.findById(1L); + + // Assert + assertTrue(result.isPresent()); + Person person = result.get(); + assertEquals(1L, person.getId()); + assertEquals("John", person.getFirstName()); + assertEquals("Doe", person.getLastName()); + assertEquals(25, person.getAge()); + assertEquals("+1234567890", person.getPhoneNumber()); + assertEquals("john.doe@example.com", person.getEmail()); + assertEquals(1L, person.getCategory().getId()); + assertEquals("Professional", person.getCategory().getType()); + + verify(springDataRepository, times(1)).findById(1L); + } + + @Test + @DisplayName("Should return empty Optional when entity not found") + void shouldReturnEmptyWhenEntityNotFound() { + // Arrange + when(springDataRepository.findById(999L)).thenReturn(Optional.empty()); + + // Act + var result = personRepositoryAdapter.findById(999L); + + // Assert + assertTrue(result.isEmpty()); + verify(springDataRepository, times(1)).findById(999L); + } + } + + @Nested + @DisplayName("Find By First Name") + class FindByFirstName { + + @Test + @DisplayName("Should return Person when entity with first name exists") + void shouldReturnPersonWhenEntityExists() { + // Arrange + when(springDataRepository.findByFirstName("John")).thenReturn(Optional.of(jpaPersonEntity)); + + // Act + var result = personRepositoryAdapter.findByFirstName("John"); + + // Assert + assertTrue(result.isPresent()); + assertEquals("John", result.get().getFirstName()); + verify(springDataRepository, times(1)).findByFirstName("John"); + } + + @Test + @DisplayName("Should return empty Optional when no entity found") + void shouldReturnEmptyWhenNotFound() { + // Arrange + when(springDataRepository.findByFirstName("Unknown")).thenReturn(Optional.empty()); + + // Act + var result = personRepositoryAdapter.findByFirstName("Unknown"); + + // Assert + assertTrue(result.isEmpty()); + verify(springDataRepository, times(1)).findByFirstName("Unknown"); + } + } + + @Nested + @DisplayName("Find By Last Name") + class FindByLastName { + + @Test + @DisplayName("Should return Person when entity with last name exists") + void shouldReturnPersonWhenEntityExists() { + // Arrange + when(springDataRepository.findByLastName("Doe")).thenReturn(Optional.of(jpaPersonEntity)); + + // Act + var result = personRepositoryAdapter.findByLastName("Doe"); + + // Assert + assertTrue(result.isPresent()); + assertEquals("Doe", result.get().getLastName()); + verify(springDataRepository, times(1)).findByLastName("Doe"); + } + } + + @Nested + @DisplayName("Find All") + class FindAll { + + @Test + @DisplayName("Should return list of Persons when entities exist") + void shouldReturnListOfPersons() { + // Arrange + var category2 = new JpaCategoryEntity(2L, "Personal"); + var person2 = + new JpaPersonEntity( + 2L, "Jane", "Smith", 30, "+9876543210", "jane@example.com", category2); + + when(springDataRepository.findAll()).thenReturn(List.of(jpaPersonEntity, person2)); + + // Act + var result = personRepositoryAdapter.findAll(); + + // Assert + assertTrue(result.isPresent()); + var persons = result.get(); + assertEquals(2, persons.size()); + assertEquals("John", persons.get(0).getFirstName()); + assertEquals("Jane", persons.get(1).getFirstName()); + + verify(springDataRepository, times(1)).findAll(); + } + + @Test + @DisplayName("Should return empty list when no entities exist") + void shouldReturnEmptyListWhenNoEntities() { + // Arrange + when(springDataRepository.findAll()).thenReturn(List.of()); + + // Act + var result = personRepositoryAdapter.findAll(); + + // Assert + assertTrue(result.isPresent()); + assertTrue(result.get().isEmpty()); + verify(springDataRepository, times(1)).findAll(); + } + } + + @Nested + @DisplayName("Save") + class Save { + + @Test + @DisplayName("Should save person and return domain model") + void shouldSavePersonAndReturnDomainModel() { + // Arrange + var personToSave = + new Person( + null, // New person without ID + "Jane", + "Smith", + 28, + "+1111111111", + "jane@example.com", + new Category(2L, "Personal")); + + var savedCategory = new JpaCategoryEntity(2L, "Personal"); + var savedEntity = + new JpaPersonEntity( + 100L, // ID assigned by database + "Jane", + "Smith", + 28, + "+1111111111", + "jane@example.com", + savedCategory); + + when(springDataRepository.save(any(JpaPersonEntity.class))).thenReturn(savedEntity); + + // Act + var result = personRepositoryAdapter.save(personToSave); + + // Assert + assertNotNull(result); + assertEquals(100L, result.getId()); + assertEquals("Jane", result.getFirstName()); + assertEquals("Smith", result.getLastName()); + assertEquals(28, result.getAge()); + + verify(springDataRepository, times(1)).save(any(JpaPersonEntity.class)); + } + + @Test + @DisplayName("Should correctly map domain model to JPA entity") + void shouldCorrectlyMapDomainToEntity() { + // Arrange + var personToSave = + new Person( + null, + "Bob", + "Johnson", + 35, + "+2222222222", + "bob@example.com", + new Category(3L, "Business")); + + var savedEntity = + new JpaPersonEntity( + 200L, + "Bob", + "Johnson", + 35, + "+2222222222", + "bob@example.com", + new JpaCategoryEntity(3L, "Business")); + + when(springDataRepository.save(any(JpaPersonEntity.class))).thenReturn(savedEntity); + + // Act + personRepositoryAdapter.save(personToSave); + + // Assert - Verify what was passed to Spring Data repository + verify(springDataRepository).save(entityCaptor.capture()); + JpaPersonEntity capturedEntity = entityCaptor.getValue(); + + assertEquals("Bob", capturedEntity.getFirstName()); + assertEquals("Johnson", capturedEntity.getLastName()); + assertEquals(35, capturedEntity.getAge()); + assertEquals("+2222222222", capturedEntity.getPhoneNumber()); + assertEquals("bob@example.com", capturedEntity.getEmail()); + assertEquals(3L, capturedEntity.getCategory().getId()); + assertEquals("Business", capturedEntity.getCategory().getType()); + } + } + + @Nested + @DisplayName("Delete By ID") + class DeleteById { + + @Test + @DisplayName("Should return true when person is successfully deleted") + void shouldReturnTrueWhenDeleted() { + // Arrange + doNothing().when(springDataRepository).deleteById(1L); + when(springDataRepository.findById(1L)).thenReturn(Optional.empty()); + + // Act + boolean result = personRepositoryAdapter.deleteById(1L); + + // Assert + assertTrue(result); + verify(springDataRepository, times(1)).deleteById(1L); + verify(springDataRepository, times(1)).findById(1L); + } + + @Test + @DisplayName("Should return false when person still exists after deletion") + void shouldReturnFalseWhenStillExists() { + // Arrange + doNothing().when(springDataRepository).deleteById(1L); + when(springDataRepository.findById(1L)).thenReturn(Optional.of(jpaPersonEntity)); + + // Act + boolean result = personRepositoryAdapter.deleteById(1L); + + // Assert + assertFalse(result); + verify(springDataRepository, times(1)).deleteById(1L); + verify(springDataRepository, times(1)).findById(1L); + } + } +} diff --git a/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/web/PersonControllerTest.java b/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/web/PersonControllerTest.java new file mode 100644 index 000000000000..9e0369b985c8 --- /dev/null +++ b/onion-architecture/infrastructure/src/test/java/com/iluwatar/onion/infrastructure/web/PersonControllerTest.java @@ -0,0 +1,348 @@ +/* + * + * * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * * + * * The MIT License + * * Copyright © 2014-2022 Ilkka Seppälä + * * + * * Permission is hereby granted, free of charge, to any person obtaining a copy + * * of this software and associated documentation files (the "Software"), to deal + * * in the Software without restriction, including without limitation the rights + * * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * * copies of the Software, and to permit persons to whom the Software is + * * furnished to do so, subject to the following conditions: + * * + * * The above copyright notice and this permission notice shall be included in + * * all copies or substantial portions of the Software. + * * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * * THE SOFTWARE. + * + */ +package com.iluwatar.onion.infrastructure.web; + +import static org.hamcrest.Matchers.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iluwatar.onion.application.dto.PersonResponse; +import com.iluwatar.onion.application.dto.SavePersonCommand; +import com.iluwatar.onion.application.usecase.GetPersonUseCase; +import com.iluwatar.onion.application.usecase.SavePersonUseCase; +import com.iluwatar.onion.domain.exception.DomainException; +import java.util.List; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +@WebMvcTest(PersonController.class) +class PersonControllerTest { + + @Autowired private MockMvc mockMvc; + + @Autowired private ObjectMapper objectMapper; + + @MockitoBean private SavePersonUseCase savePersonUseCase; + + @MockitoBean private GetPersonUseCase getPersonUseCase; + + @Nested + @DisplayName("GET /api/persons/{id}") + class GetPersonById { + + @Test + @DisplayName("Should return person when person exists") + void shouldReturnPersonWhenExists() throws Exception { + // Arrange + var response = + new PersonResponse( + 1L, "John", "Doe", 25, "+1234567890", "john.doe@example.com", 1L, "Professional"); + + when(getPersonUseCase.execute(1L)).thenReturn(response); + + // Act & Assert + mockMvc + .perform(get("/api/persons/1").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.id").value(1)) + .andExpect(jsonPath("$.firstName").value("John")) + .andExpect(jsonPath("$.lastName").value("Doe")) + .andExpect(jsonPath("$.age").value(25)) + .andExpect(jsonPath("$.phoneNumber").value("+1234567890")) + .andExpect(jsonPath("$.email").value("john.doe@example.com")) + .andExpect(jsonPath("$.categoryId").value(1)) + .andExpect(jsonPath("$.categoryType").value("Professional")); + + verify(getPersonUseCase, times(1)).execute(1L); + } + + @Test + @DisplayName("Should handle different person IDs") + void shouldHandleDifferentPersonIds() throws Exception { + // Arrange + var response = + new PersonResponse( + 42L, "Jane", "Smith", 30, "+9876543210", "jane@example.com", 2L, "Personal"); + + when(getPersonUseCase.execute(42L)).thenReturn(response); + + // Act & Assert + mockMvc + .perform(get("/api/persons/42").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.id").value(42)) + .andExpect(jsonPath("$.firstName").value("Jane")); + + verify(getPersonUseCase, times(1)).execute(42L); + } + } + + @Nested + @DisplayName("GET /api/persons") + class GetAllPersons { + + @Test + @DisplayName("Should return list of persons") + void shouldReturnListOfPersons() throws Exception { + // Arrange + var person1 = + new PersonResponse( + 1L, "John", "Doe", 25, "+1234567890", "john@example.com", 1L, "Professional"); + var person2 = + new PersonResponse( + 2L, "Jane", "Smith", 30, "+9876543210", "jane@example.com", 2L, "Personal"); + + var persons = List.of(person1, person2); + when(getPersonUseCase.executeAll()).thenReturn(persons); + + // Act & Assert + mockMvc + .perform(get("/api/persons").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$", hasSize(2))) + .andExpect(jsonPath("$[0].id").value(1)) + .andExpect(jsonPath("$[0].firstName").value("John")) + .andExpect(jsonPath("$[1].id").value(2)) + .andExpect(jsonPath("$[1].firstName").value("Jane")); + + verify(getPersonUseCase, times(1)).executeAll(); + } + + @Test + @DisplayName("Should return empty list when no persons exist") + void shouldReturnEmptyListWhenNoPersons() throws Exception { + // Arrange + when(getPersonUseCase.executeAll()).thenReturn(List.of()); + + // Act & Assert + mockMvc + .perform(get("/api/persons").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$", hasSize(0))); + + verify(getPersonUseCase, times(1)).executeAll(); + } + + @Test + @DisplayName("Should handle large list of persons") + void shouldHandleLargeListOfPersons() throws Exception { + // Arrange + var persons = + List.of( + new PersonResponse(1L, "Person1", "Last1", 25, "+1", "p1@example.com", 1L, "Cat1"), + new PersonResponse(2L, "Person2", "Last2", 26, "+2", "p2@example.com", 1L, "Cat1"), + new PersonResponse(3L, "Person3", "Last3", 27, "+3", "p3@example.com", 1L, "Cat1")); + + when(getPersonUseCase.executeAll()).thenReturn(persons); + + // Act & Assert + mockMvc + .perform(get("/api/persons").contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", hasSize(3))); + + verify(getPersonUseCase, times(1)).executeAll(); + } + } + + @Nested + @DisplayName("POST /api/persons") + class SavePerson { + + @Test + @DisplayName("Should create person with valid data") + void shouldCreatePersonWithValidData() throws Exception { + // Arrange + var command = + new SavePersonCommand( + "John", + "Doe", + 25, + "+1234567890", + "john.doe@example.com", + "123 Main St", + 1L, + "Professional"); + + var response = + new PersonResponse( + 1L, "John", "Doe", 25, "+1234567890", "john.doe@example.com", 1L, "Professional"); + + when(savePersonUseCase.execute(any(SavePersonCommand.class))).thenReturn(response); + + // Act & Assert + mockMvc + .perform( + post("/api/persons") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(command))) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.id").value(1)) + .andExpect(jsonPath("$.firstName").value("John")) + .andExpect(jsonPath("$.lastName").value("Doe")) + .andExpect(jsonPath("$.age").value(25)) + .andExpect(jsonPath("$.phoneNumber").value("+1234567890")) + .andExpect(jsonPath("$.email").value("john.doe@example.com")) + .andExpect(jsonPath("$.categoryId").value(1)) + .andExpect(jsonPath("$.categoryType").value("Professional")); + + verify(savePersonUseCase, times(1)).execute(any(SavePersonCommand.class)); + } + + @Test + @DisplayName("Should handle validation errors from use case") + void shouldPropagateValidationErrors() throws Exception { + // Arrange + var command = + new SavePersonCommand( + "Young", + "Person", + 17, // Invalid age + "+1234567890", + "young@example.com", + "123 Main St", + 1L, + "Student"); + + when(savePersonUseCase.execute(any(SavePersonCommand.class))) + .thenThrow(new DomainException("Age cannot be less than 18")); + + // Act & Assert + mockMvc + .perform( + post("/api/persons") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(command))) + .andExpect(status().is4xxClientError()); + + verify(savePersonUseCase, times(1)).execute(any(SavePersonCommand.class)); + } + + @Test + @DisplayName("Should handle malformed JSON") + void shouldHandleMalformedJson() throws Exception { + // Act & Assert + mockMvc + .perform( + post("/api/persons") + .contentType(MediaType.APPLICATION_JSON) + .content("{invalid json}")) + .andExpect(status().isBadRequest()); + + verify(savePersonUseCase, never()).execute(any(SavePersonCommand.class)); + } + + @Test + @DisplayName("Should accept all required fields in command") + void shouldAcceptAllRequiredFields() throws Exception { + // Arrange + var command = + new SavePersonCommand( + "Complete", + "Person", + 30, + "+1111111111", + "complete@example.com", + "456 Oak Ave", + 5L, + "Business"); + + var response = + new PersonResponse( + 10L, "Complete", "Person", 30, "+1111111111", "complete@example.com", 5L, "Business"); + + when(savePersonUseCase.execute(any(SavePersonCommand.class))).thenReturn(response); + + // Act & Assert + mockMvc + .perform( + post("/api/persons") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(command))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.categoryType").value("Business")); + + verify(savePersonUseCase, times(1)).execute(any(SavePersonCommand.class)); + } + } + + @Nested + @DisplayName("Controller Integration") + class ControllerIntegration { + + @Test + @DisplayName("Should handle multiple requests sequentially") + void shouldHandleMultipleRequestsSequentially() throws Exception { + // Arrange + var getResponse = + new PersonResponse( + 1L, "John", "Doe", 25, "+1234567890", "john@example.com", 1L, "Professional"); + + var savePersonCommand = + new SavePersonCommand( + "Jane", "Smith", 30, "+9876543210", "jane@example.com", "456 Oak", 2L, "Personal"); + + var savePersonResponse = + new PersonResponse( + 2L, "Jane", "Smith", 30, "+9876543210", "jane@example.com", 2L, "Personal"); + + when(getPersonUseCase.execute(1L)).thenReturn(getResponse); + when(savePersonUseCase.execute(any(SavePersonCommand.class))).thenReturn(savePersonResponse); + + // Act & Assert - GET request + mockMvc + .perform(get("/api/persons/1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.firstName").value("John")); + + // Act & Assert - POST request + mockMvc + .perform( + post("/api/persons") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(savePersonCommand))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.firstName").value("Jane")); + + verify(getPersonUseCase, times(1)).execute(1L); + verify(savePersonUseCase, times(1)).execute(any(SavePersonCommand.class)); + } + } +} diff --git a/onion-architecture/pom.xml b/onion-architecture/pom.xml new file mode 100644 index 000000000000..07df2a1224c1 --- /dev/null +++ b/onion-architecture/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + onion-architecture + pom + + + 5.10.0 + 5.23.0 + 3.24.2 + + + + domain + application + infrastructure + + diff --git a/pom.xml b/pom.xml index b856945f3b1e..ac63dd2b97cc 100644 --- a/pom.xml +++ b/pom.xml @@ -106,7 +106,7 @@ converter curiously-recurring-template-pattern currying - dao-factory + dao-factory data-access-object data-bus data-locality @@ -252,6 +252,7 @@ backpressure actor-model rate-limiting-pattern + onion-architecture @@ -346,6 +347,11 @@ mockito-core ${mockito.version} + + org.mockito + mockito-junit-jupiter + ${mockito.version} + org.mongodb bson From f1dcddfd3a793e9c1e3c72aad01ab01b7aa9b5fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:33:44 +0300 Subject: [PATCH 02/17] build(deps): bump com.fasterxml.jackson.core:jackson-databind (#3533) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.18.3 to 2.22.0. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.22.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dynamic-proxy/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic-proxy/pom.xml b/dynamic-proxy/pom.xml index 7facbcf6d095..eb5bc5c7e06d 100644 --- a/dynamic-proxy/pom.xml +++ b/dynamic-proxy/pom.xml @@ -51,7 +51,7 @@ com.fasterxml.jackson.core jackson-databind - 2.18.3 + 2.22.0 org.springframework From 7e0ddb01cd532d691c4939b65ee5a6bba5a0834e Mon Sep 17 00:00:00 2001 From: Priyanshu Date: Mon, 17 Aug 2026 00:01:20 +0530 Subject: [PATCH 03/17] feat: Implement Fallback design pattern #2846 (#3538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: implement Fallback design pattern with circuit breaker and service monitoring * docs: add README for Fallback design pattern implementation --------- Co-authored-by: Ilkka Seppälä --- fallback/README.md | 114 ++++++++++++++++ fallback/pom.xml | 70 ++++++++++ .../main/java/com/iluwatar/fallback/App.java | 99 ++++++++++++++ .../iluwatar/fallback/FallbackExecutor.java | 110 ++++++++++++++++ .../iluwatar/fallback/FallbackService.java | 47 +++++++ .../com/iluwatar/fallback/PrimaryService.java | 59 +++++++++ .../com/iluwatar/fallback/RemoteService.java | 36 ++++++ .../fallback/SimpleCircuitBreaker.java | 96 ++++++++++++++ .../java/com/iluwatar/fallback/AppTest.java | 37 ++++++ .../fallback/FallbackPatternTest.java | 122 ++++++++++++++++++ pom.xml | 1 + 11 files changed, 791 insertions(+) create mode 100644 fallback/README.md create mode 100644 fallback/pom.xml create mode 100644 fallback/src/main/java/com/iluwatar/fallback/App.java create mode 100644 fallback/src/main/java/com/iluwatar/fallback/FallbackExecutor.java create mode 100644 fallback/src/main/java/com/iluwatar/fallback/FallbackService.java create mode 100644 fallback/src/main/java/com/iluwatar/fallback/PrimaryService.java create mode 100644 fallback/src/main/java/com/iluwatar/fallback/RemoteService.java create mode 100644 fallback/src/main/java/com/iluwatar/fallback/SimpleCircuitBreaker.java create mode 100644 fallback/src/test/java/com/iluwatar/fallback/AppTest.java create mode 100644 fallback/src/test/java/com/iluwatar/fallback/FallbackPatternTest.java diff --git a/fallback/README.md b/fallback/README.md new file mode 100644 index 000000000000..d6612e756444 --- /dev/null +++ b/fallback/README.md @@ -0,0 +1,114 @@ +--- +title: "Fallback Pattern in Java: Graceful Degradation in Microservices" +shortTitle: Fallback +description: "Learn about the Fallback pattern in Java design, which ensures microservice resilience and graceful system degradation when primary dependencies fail." +category: Resilience +language: en +tag: + - Cloud distributed + - Fault tolerance + - Microservices +--- + +## Intent of Fallback Design Pattern + +The Fallback design pattern is a resiliency pattern used in microservices architecture to handle failures gracefully. It ensures that when a service is unavailable, fails, or times out, the system can continue to operate by providing an alternative response or executing a predefined fallback mechanism. This pattern enhances robustness and reliability by preventing cascading failures and improving the overall user experience. + +## Detailed Explanation of Fallback Pattern with Real-World Examples + +Real-world example + +> Consider a movie streaming application like Netflix. The home page loads personalized recommendations for the logged-in user. If the recommendation microservice goes offline or is too slow, the user shouldn't see a broken page. Instead, the system falls back to a cached list of globally popular movies. While the response is degraded (not personalized), the application remains functional, providing a seamless user experience. + +In plain words + +> Fallback ensures that if a primary service call fails, the application falls back to a backup strategy (e.g. cached response, default value, or simplified service) rather than raising an error and failing completely. + +Wikipedia says + +> A fallback is a contingency option to be taken if the preferred choice is unavailable. In software, fallback mechanisms are crucial for fault tolerance, allowing systems to degrade gracefully rather than crash. + +## Programmatic Example of Fallback Pattern in Java + +This Java example demonstrates how the Fallback pattern can manage service failures, integrate with a Circuit Breaker, and apply timeout limits. + +1. **Defining the Remote Service Interface** + + The `RemoteService` interface represents any external dependency call. + +```java +public interface RemoteService { + String execute() throws Exception; +} +``` + +2. **Defining the Primary Service and Fallback Service** + + The `PrimaryService` simulates our main external dependency which may suffer from errors or latency. The `FallbackService` returns a cached or degraded static response. + +```java +// Primary Service simulating latency and errors +var healthyPrimary = new PrimaryService("Healthy data from primary service", 10, false); +var failingPrimary = new PrimaryService("Failing service", 0, true); +var slowPrimary = new PrimaryService("Slow response from primary service", 500, false); + +// Fallback Service providing degraded response +var fallback = new FallbackService("Fallback degraded/cached response"); +``` + +3. **Monitoring Health with a Circuit Breaker** + + A `SimpleCircuitBreaker` tracks the number of failures to trip the circuit to `OPEN`, bypassing the primary service immediately to avoid waiting for timeouts. + +```java +// Trip after 2 failures; retry after 1 second +var circuitBreaker = new SimpleCircuitBreaker(2, 1000); +``` + +4. **Executing Calls with the FallbackExecutor** + + The `FallbackExecutor` uses virtual threads to execute the primary service call. It applies timeouts, handles exceptions, records failures to the circuit breaker, and falls back to the fallback service as needed. + +```java +try (var executor = new FallbackExecutor()) { + // Scenario 1: Healthy primary service call + String response1 = executor.execute(healthyPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response: {}", response1); // Healthy data from primary service + + // Scenario 2: Failing service call triggers fallback + String response2 = executor.execute(failingPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response: {}", response2); // Fallback degraded/cached response +} +``` + +## When to Use the Fallback Pattern in Java + +The Fallback pattern is applicable: + +* In microservices architectures where dependencies are called over the network and are prone to network partitions, timeouts, and outages. +* When returning a default, empty, or cached value is preferable to failing the entire request. +* In user-facing systems where maintaining a working UI (even with degraded features) is critical for user satisfaction. + +## Real-World Applications of Fallback Pattern in Java + +* [Resilience4j Fallback mechanism](https://resilience4j.readme.io/docs/fallback) +* [Netflix Hystrix Fallback](https://github.com/Netflix/Hystrix/wiki/How-To-Use#Fallback) +* Spring Cloud Circuit Breaker integrations + +## Benefits and Trade-offs of Fallback Pattern + +Benefits: + +* **Graceful Degradation**: Improves user experience by returning partial/cached data instead of errors. +* **Cascading Failure Prevention**: Avoids blocking threads waiting on hung services. +* **Fault Tolerance**: Improves system uptime and reliability. + +Trade-Offs: + +* **Stale Data**: Fallback cached responses may present out-of-date information to the user. +* **Increased Complexity**: Requires writing alternative execution flows and testing fallback scenarios. + +## Related Patterns + +- [Circuit Breaker](https://github.com/iluwatar/java-design-patterns/tree/master/circuit-breaker): Restricts calls to failing services. Often wraps the primary service before fallback is triggered. +- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry): Retries failed calls before triggering the fallback. diff --git a/fallback/pom.xml b/fallback/pom.xml new file mode 100644 index 000000000000..361aea79079b --- /dev/null +++ b/fallback/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + fallback + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.fallback.App + + + + + + + + + diff --git a/fallback/src/main/java/com/iluwatar/fallback/App.java b/fallback/src/main/java/com/iluwatar/fallback/App.java new file mode 100644 index 000000000000..6e51acc5e5a0 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/App.java @@ -0,0 +1,99 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Fallback design pattern is a resiliency pattern used in microservices architecture to handle + * failures gracefully. When a service is unavailable, fails, or times out, the system responds with + * a pre-configured fallback mechanism (like cached data or a simplified response). + * + *

This App demonstrates: 1. Healthy calls returning standard responses. 2. Failing calls + * (throwing exception) falling back to a fallback handler. 3. Latent calls (timing out) falling + * back. 4. Circuit Breaker tripping and immediately fast-failing to the fallback handler. 5. + * Recovery after a retry duration, returning the system to a healthy CLOSED state. + */ +public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Main entry point for the application. + * + * @param args Command line arguments (not used) + */ + public static void main(String[] args) { + try (var executor = new FallbackExecutor()) { + var healthyPrimary = new PrimaryService("Healthy data from primary service", 10, false); + var failingPrimary = new PrimaryService("Failing service", 0, true); + var slowPrimary = new PrimaryService("Slow response from primary service", 500, false); + var fallback = new FallbackService("Fallback degraded/cached response"); + + // Failure threshold is 2 failures, retry time period is 1 second (1000ms) + var circuitBreaker = new SimpleCircuitBreaker(2, 1000); + + // Scenario 1: Healthy primary service call + LOGGER.info("Scenario 1: Executing request to healthy primary service..."); + String response1 = executor.execute(healthyPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response received: {}", response1); + LOGGER.info("Circuit Breaker State: {}\n", circuitBreaker.getState()); + + // Scenario 2: Failing primary service call (fails and increments failure count to 1) + LOGGER.info("Scenario 2: Executing request to failing primary service (throws exception)..."); + String response2 = executor.execute(failingPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response received: {}", response2); + LOGGER.info("Circuit Breaker State: {}\n", circuitBreaker.getState()); + + // Scenario 3: Slow primary service call (times out and increments failure count to 2, + // tripping breaker) + LOGGER.info("Scenario 3: Executing request to slow primary service (triggers timeout)..."); + String response3 = executor.execute(slowPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response received: {}", response3); + LOGGER.info("Circuit Breaker State: {}\n", circuitBreaker.getState()); + + // Scenario 4: Fast failing when circuit is OPEN + LOGGER.info("Scenario 4: Executing request while Circuit Breaker is OPEN..."); + String response4 = executor.execute(healthyPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response received: {}", response4); + LOGGER.info("Circuit Breaker State: {}\n", circuitBreaker.getState()); + + // Scenario 5: Recovery from OPEN state + LOGGER.info("Scenario 5: Waiting for retry period to elapse..."); + try { + Thread.sleep(1100); // Wait longer than retryTimePeriodMs (1000ms) + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + LOGGER.info( + "Circuit Breaker State (should be HALF_OPEN on next check): {}", + circuitBreaker.getState()); + LOGGER.info("Executing request to healthy primary service to reset breaker..."); + String response5 = executor.execute(healthyPrimary, fallback, circuitBreaker, 100); + LOGGER.info("Response received: {}", response5); + LOGGER.info("Circuit Breaker State (should be CLOSED): {}\n", circuitBreaker.getState()); + } + } +} diff --git a/fallback/src/main/java/com/iluwatar/fallback/FallbackExecutor.java b/fallback/src/main/java/com/iluwatar/fallback/FallbackExecutor.java new file mode 100644 index 000000000000..01bf3a204d01 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/FallbackExecutor.java @@ -0,0 +1,110 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Orchestrates primary service execution with timeouts, circuit breaker health checks, and fallback + * execution logic. Implements AutoCloseable to ensure thread pools are closed cleanly. + */ +public class FallbackExecutor implements AutoCloseable { + private static final Logger LOGGER = LoggerFactory.getLogger(FallbackExecutor.class); + private final ExecutorService executorService; + + /** Constructor for FallbackExecutor. Initializes a virtual thread per task executor. */ + public FallbackExecutor() { + this.executorService = Executors.newVirtualThreadPerTaskExecutor(); + } + + /** + * Executes the primary service call. If it fails, times out, or the circuit breaker is open, it + * falls back to the fallback service. + * + * @param primary the primary service call to execute + * @param fallback the fallback service to call when primary fails or is bypassed + * @param circuitBreaker the circuit breaker monitoring service health + * @param timeoutMs timeout limit for the primary service in milliseconds + * @return response string + */ + public String execute( + RemoteService primary, + RemoteService fallback, + SimpleCircuitBreaker circuitBreaker, + long timeoutMs) { + + // 1. Check Circuit Breaker + if (circuitBreaker.getState() == SimpleCircuitBreaker.State.OPEN) { + LOGGER.warn("Circuit is OPEN. Fast-failing and calling fallback service."); + try { + return fallback.execute(); + } catch (Exception ex) { + LOGGER.error("Fallback service execution failed: {}", ex.getMessage()); + return "Fallback Error"; + } + } + + // 2. Attempt service call with timeout + Callable task = primary::execute; + Future future = executorService.submit(task); + + try { + String result = future.get(timeoutMs, TimeUnit.MILLISECONDS); + circuitBreaker.recordSuccess(); + return result; + } catch (TimeoutException e) { + LOGGER.error("Service call timed out. Triggering fallback."); + future.cancel(true); // Interrupt / cancel the task + circuitBreaker.recordFailure(); + try { + return fallback.execute(); + } catch (Exception ex) { + LOGGER.error("Fallback service execution failed: {}", ex.getMessage()); + return "Fallback Error"; + } + } catch (Exception e) { + LOGGER.error("Service call failed with exception: {}. Triggering fallback.", e.getMessage()); + circuitBreaker.recordFailure(); + try { + return fallback.execute(); + } catch (Exception ex) { + LOGGER.error("Fallback service execution failed: {}", ex.getMessage()); + return "Fallback Error"; + } + } + } + + @Override + public void close() { + executorService.shutdown(); + } +} diff --git a/fallback/src/main/java/com/iluwatar/fallback/FallbackService.java b/fallback/src/main/java/com/iluwatar/fallback/FallbackService.java new file mode 100644 index 000000000000..c84925f20606 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/FallbackService.java @@ -0,0 +1,47 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +/** + * A concrete implementation of the remote service representing the fallback handler. It is invoked + * when the primary service fails, returns a cached response or degrades gracefully. + */ +public class FallbackService implements RemoteService { + private final String fallbackResponse; + + /** + * Constructor for FallbackService. + * + * @param fallbackResponse the fallback response to return + */ + public FallbackService(String fallbackResponse) { + this.fallbackResponse = fallbackResponse; + } + + @Override + public String execute() { + return fallbackResponse; + } +} diff --git a/fallback/src/main/java/com/iluwatar/fallback/PrimaryService.java b/fallback/src/main/java/com/iluwatar/fallback/PrimaryService.java new file mode 100644 index 000000000000..55cdb2644e93 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/PrimaryService.java @@ -0,0 +1,59 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +/** + * A concrete implementation of the remote service representing the primary service. It can be + * configured to simulate latency and errors to test resilience features. + */ +public class PrimaryService implements RemoteService { + private final long latencyMs; + private final String response; + private final boolean shouldThrowException; + + /** + * Constructor for PrimaryService. + * + * @param response the successful response to return + * @param latencyMs simulated latency in milliseconds + * @param shouldThrowException if true, the service will throw an exception + */ + public PrimaryService(String response, long latencyMs, boolean shouldThrowException) { + this.latencyMs = latencyMs; + this.response = response; + this.shouldThrowException = shouldThrowException; + } + + @Override + public String execute() throws Exception { + if (shouldThrowException) { + throw new RuntimeException("Primary service failed!"); + } + if (latencyMs > 0) { + Thread.sleep(latencyMs); + } + return response; + } +} diff --git a/fallback/src/main/java/com/iluwatar/fallback/RemoteService.java b/fallback/src/main/java/com/iluwatar/fallback/RemoteService.java new file mode 100644 index 000000000000..7e84a7fdbe21 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/RemoteService.java @@ -0,0 +1,36 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +/** Representation of a service (e.g. a microservice client) that might fail. */ +public interface RemoteService { + /** + * Executes the service logic. + * + * @return the service response + * @throws Exception if service call fails or is interrupted + */ + String execute() throws Exception; +} diff --git a/fallback/src/main/java/com/iluwatar/fallback/SimpleCircuitBreaker.java b/fallback/src/main/java/com/iluwatar/fallback/SimpleCircuitBreaker.java new file mode 100644 index 000000000000..185167820364 --- /dev/null +++ b/fallback/src/main/java/com/iluwatar/fallback/SimpleCircuitBreaker.java @@ -0,0 +1,96 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** A simplified circuit breaker implementation for tracking remote service health. */ +public class SimpleCircuitBreaker { + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleCircuitBreaker.class); + + private final int failureThreshold; + private final long retryTimePeriodMs; + private int failureCount = 0; + private long lastFailureTime = 0; + private State state = State.CLOSED; + + /** The state of the circuit breaker. */ + public enum State { + CLOSED, + OPEN, + HALF_OPEN + } + + /** + * Constructor for SimpleCircuitBreaker. + * + * @param failureThreshold consecutive failure count threshold to trip the breaker + * @param retryTimePeriodMs time duration to wait in OPEN state before trying again (HALF_OPEN) + */ + public SimpleCircuitBreaker(int failureThreshold, long retryTimePeriodMs) { + this.failureThreshold = failureThreshold; + this.retryTimePeriodMs = retryTimePeriodMs; + } + + /** + * Get the current state of the circuit breaker after evaluating transitions. + * + * @return current state + */ + public synchronized State getState() { + evaluateState(); + return state; + } + + private void evaluateState() { + if (state == State.OPEN) { + if (System.currentTimeMillis() - lastFailureTime > retryTimePeriodMs) { + state = State.HALF_OPEN; + LOGGER.info("Circuit Breaker transitioned to HALF_OPEN"); + } + } + } + + /** Records a successful operation, resetting the failure counter and closing the circuit. */ + public synchronized void recordSuccess() { + failureCount = 0; + state = State.CLOSED; + LOGGER.info("Circuit Breaker transitioned to CLOSED (success recorded)"); + } + + /** Records a failure, potentially tripping the circuit to OPEN if threshold is met. */ + public synchronized void recordFailure() { + failureCount++; + lastFailureTime = System.currentTimeMillis(); + if (state == State.CLOSED && failureCount >= failureThreshold) { + state = State.OPEN; + LOGGER.warn("Circuit Breaker transitioned to OPEN (failure threshold reached)"); + } else if (state == State.HALF_OPEN) { + state = State.OPEN; + LOGGER.warn("Circuit Breaker transitioned to OPEN (failed during HALF_OPEN)"); + } + } +} diff --git a/fallback/src/test/java/com/iluwatar/fallback/AppTest.java b/fallback/src/test/java/com/iluwatar/fallback/AppTest.java new file mode 100644 index 000000000000..86ffb6f363be --- /dev/null +++ b/fallback/src/test/java/com/iluwatar/fallback/AppTest.java @@ -0,0 +1,37 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** Test verifying that App main method runs without throwing exceptions. */ +class AppTest { + @Test + void testMain() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/fallback/src/test/java/com/iluwatar/fallback/FallbackPatternTest.java b/fallback/src/test/java/com/iluwatar/fallback/FallbackPatternTest.java new file mode 100644 index 000000000000..f338c1c8c5c1 --- /dev/null +++ b/fallback/src/test/java/com/iluwatar/fallback/FallbackPatternTest.java @@ -0,0 +1,122 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.fallback; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +/** Unit and integration tests for the Fallback design pattern. */ +class FallbackPatternTest { + + @Test + void testHealthyServiceCall() { + try (var executor = new FallbackExecutor()) { + var primary = new PrimaryService("Primary Response", 0, false); + var fallback = new FallbackService("Fallback Response"); + var circuitBreaker = new SimpleCircuitBreaker(2, 1000); + + String response = executor.execute(primary, fallback, circuitBreaker, 100); + assertEquals("Primary Response", response); + assertEquals(SimpleCircuitBreaker.State.CLOSED, circuitBreaker.getState()); + } + } + + @Test + void testFailingServiceCall() { + try (var executor = new FallbackExecutor()) { + var primary = new PrimaryService("Primary Response", 0, true); + var fallback = new FallbackService("Fallback Response"); + var circuitBreaker = new SimpleCircuitBreaker(2, 1000); + + // First failure: should call fallback, state remains CLOSED since threshold is 2 + String response1 = executor.execute(primary, fallback, circuitBreaker, 100); + assertEquals("Fallback Response", response1); + assertEquals(SimpleCircuitBreaker.State.CLOSED, circuitBreaker.getState()); + + // Second failure: should call fallback, state becomes OPEN + String response2 = executor.execute(primary, fallback, circuitBreaker, 100); + assertEquals("Fallback Response", response2); + assertEquals(SimpleCircuitBreaker.State.OPEN, circuitBreaker.getState()); + } + } + + @Test + void testTimeoutServiceCall() { + try (var executor = new FallbackExecutor()) { + // Primary takes 300ms, timeout limit is 50ms + var primary = new PrimaryService("Primary Response", 300, false); + var fallback = new FallbackService("Fallback Response"); + var circuitBreaker = new SimpleCircuitBreaker(1, 1000); + + String response = executor.execute(primary, fallback, circuitBreaker, 50); + assertEquals("Fallback Response", response); + assertEquals(SimpleCircuitBreaker.State.OPEN, circuitBreaker.getState()); + } + } + + @Test + void testCircuitBreakerOpenFastFail() { + try (var executor = new FallbackExecutor()) { + // Configure primary service to throw exception if called + var primary = new PrimaryService("Primary Response", 0, true); + var fallback = new FallbackService("Fallback Response"); + var circuitBreaker = new SimpleCircuitBreaker(1, 1000); + + // Force open by registering a failure + circuitBreaker.recordFailure(); + assertEquals(SimpleCircuitBreaker.State.OPEN, circuitBreaker.getState()); + + // Now call execute. It should short-circuit and not call the failing primary (fast-fail). + String response = executor.execute(primary, fallback, circuitBreaker, 100); + assertEquals("Fallback Response", response); + } + } + + @Test + void testCircuitBreakerRecovery() throws InterruptedException { + try (var executor = new FallbackExecutor()) { + var primary = new PrimaryService("Primary Response", 0, false); + var fallback = new FallbackService("Fallback Response"); + // Failure threshold = 1, retry period = 100ms + var circuitBreaker = new SimpleCircuitBreaker(1, 100); + + // Trip the breaker + circuitBreaker.recordFailure(); + assertEquals(SimpleCircuitBreaker.State.OPEN, circuitBreaker.getState()); + + // Wait 150ms to exceed retry period + Thread.sleep(150); + + // State should evaluate to HALF_OPEN + assertEquals(SimpleCircuitBreaker.State.HALF_OPEN, circuitBreaker.getState()); + + // Execute. Healthy primary service succeeds, state transitions to CLOSED + String response = executor.execute(primary, fallback, circuitBreaker, 100); + assertEquals("Primary Response", response); + assertEquals(SimpleCircuitBreaker.State.CLOSED, circuitBreaker.getState()); + } + } +} diff --git a/pom.xml b/pom.xml index ac63dd2b97cc..2688d8be324d 100644 --- a/pom.xml +++ b/pom.xml @@ -252,6 +252,7 @@ backpressure actor-model rate-limiting-pattern + fallback onion-architecture From 401c44b797d3b48c6cf1ac62ff6ea7fb38109889 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:32:18 +0300 Subject: [PATCH 04/17] docs: add priyanshuvishwakarma273403 as a contributor for code (#3568) * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 94c3cb43c478..9c451a4b1643 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3728,6 +3728,15 @@ "contributions": [ "translation" ] + }, + { + "login": "priyanshuvishwakarma273403", + "name": "Priyanshu", + "avatar_url": "https://avatars.githubusercontent.com/u/222148451?v=4", + "profile": "https://www.priyanshu-portfolio.co.in", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 9109b48ae93e..fb9fccf9be92 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-409-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-410-orange.svg?style=flat-square)](#contributors-)
@@ -607,6 +607,7 @@ This project is licensed under the terms of the MIT license. Giuliano Oliveira
Giuliano Oliveira

🌍 + Priyanshu
Priyanshu

💻 From f5bdf688f1ede98572f0e0af038771a4e56271eb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:37:59 +0300 Subject: [PATCH 05/17] build(deps): bump com.diffplug.spotless:spotless-maven-plugin (#3540) Bumps [com.diffplug.spotless:spotless-maven-plugin](https://github.com/diffplug/spotless) from 2.44.2 to 3.8.0. - [Release notes](https://github.com/diffplug/spotless/releases) - [Changelog](https://github.com/diffplug/spotless/blob/main/CHANGES.md) - [Commits](https://github.com/diffplug/spotless/compare/maven/2.44.2...maven/3.8.0) --- updated-dependencies: - dependency-name: com.diffplug.spotless:spotless-maven-plugin dependency-version: 3.8.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- microservices-self-registration/contextservice/pom.xml | 2 +- microservices-self-registration/eurekaserver/pom.xml | 2 +- microservices-self-registration/greetingservice/pom.xml | 2 +- pom.xml | 2 +- rate-limiting-pattern/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/microservices-self-registration/contextservice/pom.xml b/microservices-self-registration/contextservice/pom.xml index 71f61fcf6a30..964ebdecee4e 100644 --- a/microservices-self-registration/contextservice/pom.xml +++ b/microservices-self-registration/contextservice/pom.xml @@ -70,7 +70,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.44.4 + 3.8.0 diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml index fac49a1e4938..d8b923b813cf 100644 --- a/microservices-self-registration/eurekaserver/pom.xml +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -52,7 +52,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.44.4 + 3.8.0 diff --git a/microservices-self-registration/greetingservice/pom.xml b/microservices-self-registration/greetingservice/pom.xml index 36221db34add..b6a92aabc8a3 100644 --- a/microservices-self-registration/greetingservice/pom.xml +++ b/microservices-self-registration/greetingservice/pom.xml @@ -66,7 +66,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.44.4 + 3.8.0 diff --git a/pom.xml b/pom.xml index 2688d8be324d..904ddb9618ec 100644 --- a/pom.xml +++ b/pom.xml @@ -491,7 +491,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.44.4 + 3.8.0 diff --git a/rate-limiting-pattern/pom.xml b/rate-limiting-pattern/pom.xml index 517a02094a9b..370b59e7b283 100644 --- a/rate-limiting-pattern/pom.xml +++ b/rate-limiting-pattern/pom.xml @@ -59,7 +59,7 @@ com.diffplug.spotless spotless-maven-plugin - 2.44.2 + 3.8.0 From 47693507db73d9778b9b57695cadab4371cb1e8d Mon Sep 17 00:00:00 2001 From: Arnab Nandy Date: Mon, 17 Aug 2026 00:13:10 +0530 Subject: [PATCH 06/17] docs: Update factory method Java API links (#3539) * Update factory method Java API links Signed-off-by: Arnab Nandy * Trigger PR checks Signed-off-by: Arnab Nandy --------- Signed-off-by: Arnab Nandy --- factory-method/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/factory-method/README.md b/factory-method/README.md index 4334b052353d..6a0046956211 100644 --- a/factory-method/README.md +++ b/factory-method/README.md @@ -103,13 +103,12 @@ Use the Factory Method Pattern in Java when: ## Real-World Applications of Factory Method Pattern in Java -* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) -* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) -* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) -* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) -* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-) -* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-) -* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) +* [java.util.Calendar]() +* [java.util.ResourceBundle]() +* [java.text.NumberFormat]() +* [java.nio.charset.Charset]() +* [java.net.URLStreamHandlerFactory]() +* [java.util.EnumSet]() * Frameworks that run application components, configured dynamically at runtime. ## Benefits and Trade-offs of Factory Method Pattern From a7000fe61b12be895b9a70f99e4e33ff02992806 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:43:53 +0300 Subject: [PATCH 07/17] docs: add arnabnandy7 as a contributor for doc (#3569) * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9c451a4b1643..f8d36d2f22cb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3737,6 +3737,15 @@ "contributions": [ "code" ] + }, + { + "login": "arnabnandy7", + "name": "Arnab Nandy", + "avatar_url": "https://avatars.githubusercontent.com/u/5053648?v=4", + "profile": "https://github.com/arnabnandy-cognizant", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index fb9fccf9be92..69c09eedc47e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-410-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-411-orange.svg?style=flat-square)](#contributors-)
@@ -608,6 +608,7 @@ This project is licensed under the terms of the MIT license. Giuliano Oliveira
Giuliano Oliveira

🌍 Priyanshu
Priyanshu

💻 + Arnab Nandy
Arnab Nandy

📖 From 5d6ff2f0c43762c80e023689d58ef09c38b3cad6 Mon Sep 17 00:00:00 2001 From: BAGHDAD Mohamed <123114744+MohamedMBG@users.noreply.github.com> Date: Sun, 16 Aug 2026 19:47:18 +0100 Subject: [PATCH 08/17] feat: add rule engine design pattern (#3548) Add an educational rule-engine module demonstrating the Rule Engine pattern. Each business rule is an independent object exposing evaluate (decision) and execute (action); a RuleEngine evaluates a collection of rules against an immutable loan-application context in insertion order, runs the passing rules, and reports every passed and failed rule via an immutable RuleEngineResult. Includes three concrete rules, an App demo, unit tests, README, and class diagram. --- pom.xml | 1 + rule-engine/README.md | 199 ++++++++++++++++++ rule-engine/etc/rule-engine.urm.puml | 61 ++++++ rule-engine/pom.xml | 70 ++++++ .../java/com/iluwatar/ruleengine/App.java | 69 ++++++ .../iluwatar/ruleengine/CreditScoreRule.java | 61 ++++++ .../iluwatar/ruleengine/LoanApplication.java | 38 ++++ .../iluwatar/ruleengine/MinimumAgeRule.java | 58 +++++ .../ruleengine/MinimumIncomeRule.java | 61 ++++++ .../java/com/iluwatar/ruleengine/Rule.java | 61 ++++++ .../com/iluwatar/ruleengine/RuleEngine.java | 91 ++++++++ .../iluwatar/ruleengine/RuleEngineResult.java | 48 +++++ .../java/com/iluwatar/ruleengine/AppTest.java | 37 ++++ .../iluwatar/ruleengine/LoanRulesTest.java | 81 +++++++ .../ruleengine/RuleEngineResultTest.java | 55 +++++ .../iluwatar/ruleengine/RuleEngineTest.java | 122 +++++++++++ 16 files changed, 1113 insertions(+) create mode 100644 rule-engine/README.md create mode 100644 rule-engine/etc/rule-engine.urm.puml create mode 100644 rule-engine/pom.xml create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/App.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java create mode 100644 rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java create mode 100644 rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java create mode 100644 rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java create mode 100644 rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java create mode 100644 rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java diff --git a/pom.xml b/pom.xml index 904ddb9618ec..4a16f9940bbe 100644 --- a/pom.xml +++ b/pom.xml @@ -208,6 +208,7 @@ resource-acquisition-is-initialization retry role-object + rule-engine saga separated-interface serialized-entity diff --git a/rule-engine/README.md b/rule-engine/README.md new file mode 100644 index 000000000000..53106a71d524 --- /dev/null +++ b/rule-engine/README.md @@ -0,0 +1,199 @@ +--- +title: "Rule Engine Pattern in Java: Replacing Tangled Conditionals with Composable Rules" +shortTitle: Rule Engine +description: "Learn the Rule Engine design pattern in Java. Encapsulate each business rule as an independent object and let an engine evaluate and execute them against a shared context, replacing large nested if/else blocks with small, testable, composable rules." +category: Behavioral +language: en +tag: + - Business + - Decoupling + - Domain + - Encapsulation + - Extensibility +--- + +## Intent of Rule Engine Design Pattern + +Encapsulate each business rule as an independent, self-contained object and let an engine evaluate and execute a collection of those rules against a shared context, so that decision logic can grow and change without rewriting a large nested conditional block. + +## Detailed Explanation of Rule Engine Pattern with Real-World Examples + +Real-world example + +> A bank decides whether to approve a loan by checking several independent criteria: the applicant must be old enough, earn enough, and have a good enough credit score. Instead of hard-coding one enormous condition, the bank keeps each criterion as a separate policy on a checklist. A clerk walks the whole checklist for every application, ticks off the criteria that pass, and writes down the ones that fail. Adding a new criterion means adding a line to the checklist, not rewriting the whole approval procedure. + +In plain words + +> The Rule Engine pattern turns each branch of a giant `if/else` into its own object and hands a collection of them to an engine that runs them all against the same input, collecting which passed and which failed. + +## Programmatic Example of Rule Engine Pattern in Java + +Each rule separates the **decision** (`evaluate`) from the **action** (`execute`). `evaluate` reports whether a rule's condition holds; `execute` performs the side effect associated with a satisfied rule. + +```java +public interface Rule { + + String name(); + + boolean evaluate(T context); + + void execute(T context); +} +``` + +The context is an immutable value object that carries the data the rules inspect. + +```java +public record LoanApplication( + int age, double monthlyIncome, double loanAmount, int creditScore) {} +``` + +Concrete rules encapsulate one criterion each. New criteria are added by writing new classes — the engine never changes. + +```java +public class MinimumAgeRule implements Rule { + + private final int minimumAge; + + public MinimumAgeRule(int minimumAge) { + this.minimumAge = minimumAge; + } + + @Override + public String name() { + return "MinimumAgeRule"; + } + + @Override + public boolean evaluate(LoanApplication context) { + return context.age() >= minimumAge; + } + + @Override + public void execute(LoanApplication context) { + LOGGER.info("Applicant age {} meets the minimum age of {}.", context.age(), minimumAge); + } +} +``` + +The engine holds a defensively copied, immutable list of rules. It evaluates every rule in insertion order, executes the ones that pass, and reports the combined outcome. It never stops at the first failure, so a single run reports *all* the reasons an application was rejected. + +```java +public class RuleEngine { + + private final List> rules; + + public RuleEngine(List> rules) { + this.rules = List.copyOf(rules); + } + + public RuleEngineResult run(T context) { + Objects.requireNonNull(context, "context must not be null"); + List passed = new ArrayList<>(); + List failed = new ArrayList<>(); + for (Rule rule : rules) { + if (rule.evaluate(context)) { + rule.execute(context); + passed.add(rule.name()); + } else { + failed.add(rule.name()); + } + } + return new RuleEngineResult(failed.isEmpty(), passed, failed); + } +} +``` + +The result is an immutable value object describing the run. + +```java +public record RuleEngineResult( + boolean approved, List passedRules, List failedRules) { + + public RuleEngineResult { + passedRules = List.copyOf(passedRules); + failedRules = List.copyOf(failedRules); + } +} +``` + +Putting it together, the `App` builds an engine and runs two applications through it. + +```java +var engine = + new RuleEngine<>( + List.of( + new MinimumAgeRule(18), + new MinimumIncomeRule(2000.0), + new CreditScoreRule(650))); + +engine.run(new LoanApplication(30, 3500.0, 15000.0, 720)); // approved +engine.run(new LoanApplication(17, 1500.0, 15000.0, 720)); // rejected: age and income +``` + +Program output: + +``` +Applicant age 30 meets the minimum age of 18. +Applicant income 3500.0 meets the minimum income of 2000.0. +Applicant credit score 720 meets the minimum score of 650. +Loan approved. Passed rules: [MinimumAgeRule, MinimumIncomeRule, CreditScoreRule] +Applicant credit score 720 meets the minimum score of 650. +Loan rejected. Failed rules: [MinimumAgeRule, MinimumIncomeRule] +``` + +### Behavioral decisions + +The example commits to the following semantics, each covered by tests: + +* `evaluate` returning `true` means the rule **passes** (its condition is satisfied); a passing rule then has its `execute` action run. +* The engine evaluates **every** rule; it does not stop after the first failure, so all rejection reasons are reported. +* Outcomes are reported as an immutable `RuleEngineResult` carrying the overall `approved` flag plus the names of the passed and failed rules. +* Rules execute in **insertion order**. +* A `null` context passed to `run` throws `NullPointerException`; a `null` rule collection or a `null` rule element is rejected on construction. +* An engine with **no rules** approves vacuously (nothing failed). + +## Class diagram + +See [rule-engine.urm.puml](./etc/rule-engine.urm.puml) for the PlantUML class diagram. + +## When to Use the Rule Engine Pattern in Java + +* Decision logic is a growing set of independent conditions that would otherwise become a large, hard-to-read nested `if/else`. +* Rules must be added, removed, or reordered without touching the code that coordinates them. +* You need to report *all* failing conditions, not just the first one. +* Business rules deserve to be unit tested in isolation. + +## Real-World Applications of Rule Engine Pattern in Java + +* Loan, insurance, and credit approval workflows. +* Validation frameworks such as Bean Validation, where each constraint is an independent rule. +* Fraud detection and risk scoring, where many independent checks contribute to one decision. +* Pricing, discount, and promotion eligibility engines. + +## Benefits and Trade-offs of Rule Engine Pattern + +Benefits + +* Encapsulation: each rule owns one criterion. +* Extensibility: new rules are new classes; the engine is closed for modification. +* Testability: rules and the engine can be tested independently. +* Transparency: the result lists every passed and failed rule. + +Trade-offs + +* Debugging a decision means tracing several small objects instead of reading one block. +* Rule ordering and conflicts must be managed deliberately when rules are not independent. +* Over-abstracting trivial logic into a rule engine adds indirection that a simple `if` would not. + +## Related Java Design Patterns + +* [Specification](../specification): combines boolean criteria that an object must satisfy; a Rule Engine orchestrates and executes such criteria. +* [Chain of Responsibility](../chain-of-responsibility): passes a request along handlers; a Rule Engine instead runs every rule against one context. +* [Strategy](../strategy): each rule is effectively a pluggable strategy for one decision. +* [Command](../command): a rule's `execute` action resembles an encapsulated command. + +## References and Credits + +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420) (Martin Fowler) +* [Should I use a Rules Engine? (Martin Fowler)](https://martinfowler.com/bliki/RulesEngine.html) diff --git a/rule-engine/etc/rule-engine.urm.puml b/rule-engine/etc/rule-engine.urm.puml new file mode 100644 index 000000000000..c560f7862485 --- /dev/null +++ b/rule-engine/etc/rule-engine.urm.puml @@ -0,0 +1,61 @@ +@startuml +package com.iluwatar.ruleengine { + interface Rule { + + name() : String {abstract} + + evaluate(context : T) : boolean {abstract} + + execute(context : T) : void {abstract} + } + class RuleEngine { + - rules : List> + + RuleEngine(rules : List>) + + run(context : T) : RuleEngineResult + + rules() : List> + } + class RuleEngineResult { + + RuleEngineResult(approved : boolean, passedRules : List, failedRules : List) + + approved() : boolean + + passedRules() : List + + failedRules() : List + } + class LoanApplication { + + LoanApplication(age : int, monthlyIncome : double, loanAmount : double, creditScore : int) + + age() : int + + monthlyIncome() : double + + loanAmount() : double + + creditScore() : int + } + class MinimumAgeRule { + - minimumAge : int + + MinimumAgeRule(minimumAge : int) + + name() : String + + evaluate(context : LoanApplication) : boolean + + execute(context : LoanApplication) : void + } + class MinimumIncomeRule { + - minimumIncome : double + + MinimumIncomeRule(minimumIncome : double) + + name() : String + + evaluate(context : LoanApplication) : boolean + + execute(context : LoanApplication) : void + } + class CreditScoreRule { + - minimumScore : int + + CreditScoreRule(minimumScore : int) + + name() : String + + evaluate(context : LoanApplication) : boolean + + execute(context : LoanApplication) : void + } + class App { + + App() + + main(args : String[]) : void + } +} +RuleEngine --> "*" Rule +RuleEngine ..> RuleEngineResult +MinimumAgeRule ..|> Rule +MinimumIncomeRule ..|> Rule +CreditScoreRule ..|> Rule +MinimumAgeRule ..> LoanApplication +MinimumIncomeRule ..> LoanApplication +CreditScoreRule ..> LoanApplication +@enduml diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml new file mode 100644 index 000000000000..29738d783a99 --- /dev/null +++ b/rule-engine/pom.xml @@ -0,0 +1,70 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + rule-engine + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.ruleengine.App + + + + + + + + + diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/App.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/App.java new file mode 100644 index 000000000000..78a51f152b84 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/App.java @@ -0,0 +1,69 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +/** + * The Rule Engine pattern encapsulates each business rule as an independent object and lets a + * {@link RuleEngine} evaluate a collection of them against a shared context. This replaces large, + * tangled conditional blocks with small, testable rules that can be added or removed without + * touching the orchestration logic. + * + *

This demo builds a loan approval engine from three rules and runs two applications through it: + * one that satisfies every rule and one that fails two of them. Because the engine evaluates every + * rule rather than stopping at the first failure, the result reports all the reasons an application + * was rejected. + */ +@Slf4j +public class App { + + /** + * Program entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + var engine = + new RuleEngine<>( + List.of( + new MinimumAgeRule(18), new MinimumIncomeRule(2000.0), new CreditScoreRule(650))); + + var approved = new LoanApplication(30, 3500.0, 15000.0, 720); + var rejected = new LoanApplication(17, 1500.0, 15000.0, 720); + + report(engine.run(approved)); + report(engine.run(rejected)); + } + + private static void report(RuleEngineResult result) { + if (result.approved()) { + LOGGER.info("Loan approved. Passed rules: {}", result.passedRules()); + } else { + LOGGER.info("Loan rejected. Failed rules: {}", result.failedRules()); + } + } +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java new file mode 100644 index 000000000000..28cd59baadbb --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/CreditScoreRule.java @@ -0,0 +1,61 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import lombok.extern.slf4j.Slf4j; + +/** Passes when the applicant's credit score reaches the required minimum. */ +@Slf4j +public class CreditScoreRule implements Rule { + + private final int minimumScore; + + /** + * Creates the rule. + * + * @param minimumScore the inclusive minimum credit score the applicant must have + */ + public CreditScoreRule(int minimumScore) { + this.minimumScore = minimumScore; + } + + @Override + public String name() { + return "CreditScoreRule"; + } + + @Override + public boolean evaluate(LoanApplication context) { + return context.creditScore() >= minimumScore; + } + + @Override + public void execute(LoanApplication context) { + LOGGER.info( + "Applicant credit score {} meets the minimum score of {}.", + context.creditScore(), + minimumScore); + } +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java new file mode 100644 index 000000000000..0eda1f17d3e2 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/LoanApplication.java @@ -0,0 +1,38 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +/** + * Immutable context that the loan {@link Rule rules} are evaluated against. + * + *

Using a record keeps the domain object immutable and free of behaviour, so the business logic + * lives entirely inside the rules rather than being scattered across the data it operates on. + * + * @param age applicant age in years + * @param monthlyIncome applicant net monthly income + * @param loanAmount requested loan amount + * @param creditScore applicant credit score + */ +public record LoanApplication(int age, double monthlyIncome, double loanAmount, int creditScore) {} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java new file mode 100644 index 000000000000..71532dde4707 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumAgeRule.java @@ -0,0 +1,58 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import lombok.extern.slf4j.Slf4j; + +/** Passes when the applicant is at least the required minimum age. */ +@Slf4j +public class MinimumAgeRule implements Rule { + + private final int minimumAge; + + /** + * Creates the rule. + * + * @param minimumAge the inclusive minimum age the applicant must reach + */ + public MinimumAgeRule(int minimumAge) { + this.minimumAge = minimumAge; + } + + @Override + public String name() { + return "MinimumAgeRule"; + } + + @Override + public boolean evaluate(LoanApplication context) { + return context.age() >= minimumAge; + } + + @Override + public void execute(LoanApplication context) { + LOGGER.info("Applicant age {} meets the minimum age of {}.", context.age(), minimumAge); + } +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java new file mode 100644 index 000000000000..fc6d40964fc9 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/MinimumIncomeRule.java @@ -0,0 +1,61 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import lombok.extern.slf4j.Slf4j; + +/** Passes when the applicant's monthly income reaches the required minimum. */ +@Slf4j +public class MinimumIncomeRule implements Rule { + + private final double minimumIncome; + + /** + * Creates the rule. + * + * @param minimumIncome the inclusive minimum monthly income the applicant must earn + */ + public MinimumIncomeRule(double minimumIncome) { + this.minimumIncome = minimumIncome; + } + + @Override + public String name() { + return "MinimumIncomeRule"; + } + + @Override + public boolean evaluate(LoanApplication context) { + return context.monthlyIncome() >= minimumIncome; + } + + @Override + public void execute(LoanApplication context) { + LOGGER.info( + "Applicant income {} meets the minimum income of {}.", + context.monthlyIncome(), + minimumIncome); + } +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java new file mode 100644 index 000000000000..723b31e73b52 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/Rule.java @@ -0,0 +1,61 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +/** + * Abstraction for a single, self-contained business rule. + * + *

A rule separates the decision ({@link #evaluate(Object)}) from the action ({@link + * #execute(Object)}). {@code evaluate} inspects the context and reports whether the rule's + * condition is satisfied, while {@code execute} performs the side effect associated with a + * satisfied rule. Keeping the two responsibilities apart lets a {@link RuleEngine} decide which + * rules apply before running any action, and lets new rules be added without touching the engine. + * + * @param type of the context the rule is evaluated against + */ +public interface Rule { + + /** + * Returns a human readable identifier used when reporting rule outcomes. + * + * @return the rule name + */ + String name(); + + /** + * Evaluates the rule against the given context. + * + * @param context the immutable input the rule inspects + * @return {@code true} when the rule's condition is satisfied, {@code false} otherwise + */ + boolean evaluate(T context); + + /** + * Performs the action associated with a satisfied rule. + * + * @param context the immutable input the action operates on + */ + void execute(T context); +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java new file mode 100644 index 000000000000..85a8db9d74b5 --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngine.java @@ -0,0 +1,91 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Orchestrates a fixed collection of {@link Rule rules} against a context. + * + *

The engine owns the coordination logic that would otherwise live in a large nested {@code + * if}/{@code else} block: it evaluates every rule in insertion order, runs the action of each rule + * whose condition is satisfied, and reports the combined outcome as a {@link RuleEngineResult}. + * Evaluation never stops early, so a single run reports all failing rules rather than only + * the first, which is what makes rejection reasons useful. + * + *

The rule collection is copied defensively on construction, making the engine immutable and + * safe to reuse across many contexts. New behaviour is added by supplying additional {@link Rule} + * implementations; the engine itself never changes. + * + * @param type of the context the rules are evaluated against + */ +public class RuleEngine { + + private final List> rules; + + /** + * Creates an engine for the given rules. + * + * @param rules the rules to evaluate, applied in iteration order; must not be {@code null} or + * contain {@code null} elements + * @throws NullPointerException if {@code rules} is {@code null} or contains a {@code null} rule + */ + public RuleEngine(List> rules) { + this.rules = List.copyOf(rules); + } + + /** + * Evaluates every rule against the context and executes the rules that pass. + * + * @param context the context inspected by the rules; must not be {@code null} + * @return the combined outcome of the run + * @throws NullPointerException if {@code context} is {@code null} + */ + public RuleEngineResult run(T context) { + Objects.requireNonNull(context, "context must not be null"); + List passed = new ArrayList<>(); + List failed = new ArrayList<>(); + for (Rule rule : rules) { + if (rule.evaluate(context)) { + rule.execute(context); + passed.add(rule.name()); + } else { + failed.add(rule.name()); + } + } + return new RuleEngineResult(failed.isEmpty(), passed, failed); + } + + /** + * Returns the rules held by this engine. + * + * @return an immutable view of the configured rules + */ + public List> rules() { + return rules; + } +} diff --git a/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java b/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java new file mode 100644 index 000000000000..868e3986602f --- /dev/null +++ b/rule-engine/src/main/java/com/iluwatar/ruleengine/RuleEngineResult.java @@ -0,0 +1,48 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import java.util.List; + +/** + * Immutable outcome produced by {@link RuleEngine#run(Object)}. + * + *

The result reports whether every rule passed and, for transparency, the names of the rules + * that passed and failed in the order they were evaluated. The lists are copied on construction so + * the result cannot be mutated by callers or by later changes to the source collections. + * + * @param approved {@code true} when no rule failed + * @param passedRules names of the rules whose condition was satisfied, in evaluation order + * @param failedRules names of the rules whose condition was not satisfied, in evaluation order + */ +public record RuleEngineResult( + boolean approved, List passedRules, List failedRules) { + + /** Defensive copy keeps the value object immutable. */ + public RuleEngineResult { + passedRules = List.copyOf(passedRules); + failedRules = List.copyOf(failedRules); + } +} diff --git a/rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java b/rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java new file mode 100644 index 000000000000..a8746fa0c387 --- /dev/null +++ b/rule-engine/src/test/java/com/iluwatar/ruleengine/AppTest.java @@ -0,0 +1,37 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void shouldLaunchApp() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java b/rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java new file mode 100644 index 000000000000..80ba160b1ffa --- /dev/null +++ b/rule-engine/src/test/java/com/iluwatar/ruleengine/LoanRulesTest.java @@ -0,0 +1,81 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +/** Verifies each concrete rule independently at, above and below its threshold. */ +class LoanRulesTest { + + private static LoanApplication applicant(int age, double income, int score) { + return new LoanApplication(age, income, 10000.0, score); + } + + @Test + void minimumAgeRulePassesAtOrAboveThreshold() { + var rule = new MinimumAgeRule(18); + assertTrue(rule.evaluate(applicant(18, 3000.0, 700))); + assertTrue(rule.evaluate(applicant(40, 3000.0, 700))); + assertDoesNotThrow(() -> rule.execute(applicant(18, 3000.0, 700))); + } + + @Test + void minimumAgeRuleFailsBelowThreshold() { + var rule = new MinimumAgeRule(18); + assertFalse(rule.evaluate(applicant(17, 3000.0, 700))); + } + + @Test + void minimumIncomeRulePassesAtOrAboveThreshold() { + var rule = new MinimumIncomeRule(2000.0); + assertTrue(rule.evaluate(applicant(30, 2000.0, 700))); + assertTrue(rule.evaluate(applicant(30, 5000.0, 700))); + assertDoesNotThrow(() -> rule.execute(applicant(30, 2000.0, 700))); + } + + @Test + void minimumIncomeRuleFailsBelowThreshold() { + var rule = new MinimumIncomeRule(2000.0); + assertFalse(rule.evaluate(applicant(30, 1999.99, 700))); + } + + @Test + void creditScoreRulePassesAtOrAboveThreshold() { + var rule = new CreditScoreRule(650); + assertTrue(rule.evaluate(applicant(30, 3000.0, 650))); + assertTrue(rule.evaluate(applicant(30, 3000.0, 800))); + assertDoesNotThrow(() -> rule.execute(applicant(30, 3000.0, 650))); + } + + @Test + void creditScoreRuleFailsBelowThreshold() { + var rule = new CreditScoreRule(650); + assertFalse(rule.evaluate(applicant(30, 3000.0, 649))); + } +} diff --git a/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java b/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java new file mode 100644 index 000000000000..0bae5dc12c0d --- /dev/null +++ b/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineResultTest.java @@ -0,0 +1,55 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RuleEngineResultTest { + + @Test + void copiesListsDefensivelyOnConstruction() { + var passed = new ArrayList<>(List.of("MinimumAgeRule")); + var failed = new ArrayList<>(List.of("CreditScoreRule")); + var result = new RuleEngineResult(false, passed, failed); + + passed.add("MinimumIncomeRule"); // mutate the sources after construction + failed.clear(); + + assertEquals(List.of("MinimumAgeRule"), result.passedRules()); + assertEquals(List.of("CreditScoreRule"), result.failedRules()); + } + + @Test + void exposedListsAreUnmodifiable() { + var result = new RuleEngineResult(true, List.of("MinimumAgeRule"), List.of()); + assertThrows(UnsupportedOperationException.class, () -> result.passedRules().add("x")); + assertThrows(UnsupportedOperationException.class, () -> result.failedRules().add("x")); + } +} diff --git a/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java b/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java new file mode 100644 index 000000000000..fd8f89943ac9 --- /dev/null +++ b/rule-engine/src/test/java/com/iluwatar/ruleengine/RuleEngineTest.java @@ -0,0 +1,122 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.ruleengine; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +class RuleEngineTest { + + private static RuleEngine loanEngine() { + return new RuleEngine<>( + List.of(new MinimumAgeRule(18), new MinimumIncomeRule(2000.0), new CreditScoreRule(650))); + } + + @Test + void approvesWhenEveryRulePasses() { + var result = loanEngine().run(new LoanApplication(30, 3000.0, 10000.0, 700)); + assertTrue(result.approved()); + assertEquals( + List.of("MinimumAgeRule", "MinimumIncomeRule", "CreditScoreRule"), result.passedRules()); + assertTrue(result.failedRules().isEmpty()); + } + + @Test + void rejectsWhenASingleRuleFails() { + var result = loanEngine().run(new LoanApplication(30, 3000.0, 10000.0, 600)); + assertFalse(result.approved()); + assertEquals(List.of("CreditScoreRule"), result.failedRules()); + assertEquals(List.of("MinimumAgeRule", "MinimumIncomeRule"), result.passedRules()); + } + + @Test + void reportsEveryFailingRuleWithoutStoppingEarly() { + var result = loanEngine().run(new LoanApplication(16, 500.0, 10000.0, 400)); + assertFalse(result.approved()); + assertEquals( + List.of("MinimumAgeRule", "MinimumIncomeRule", "CreditScoreRule"), result.failedRules()); + assertTrue(result.passedRules().isEmpty()); + } + + @Test + void evaluatesRulesInInsertionOrder() { + var engine = + new RuleEngine<>( + List.of( + new CreditScoreRule(650), new MinimumAgeRule(18), new MinimumIncomeRule(2000.0))); + var result = engine.run(new LoanApplication(16, 500.0, 10000.0, 400)); + assertEquals( + List.of("CreditScoreRule", "MinimumAgeRule", "MinimumIncomeRule"), result.failedRules()); + } + + @Test + void emptyEngineApprovesVacuously() { + var result = + new RuleEngine(List.of()).run(new LoanApplication(1, 1.0, 1.0, 1)); + assertTrue(result.approved()); + assertTrue(result.passedRules().isEmpty()); + assertTrue(result.failedRules().isEmpty()); + } + + @Test + void rejectsNullContext() { + assertThrows(NullPointerException.class, () -> loanEngine().run(null)); + } + + @Test + void rejectsNullRuleCollection() { + assertThrows(NullPointerException.class, () -> new RuleEngine(null)); + } + + @Test + void rejectsNullRuleElement() { + var rules = new ArrayList>(); + rules.add(null); + assertThrows(NullPointerException.class, () -> new RuleEngine<>(rules)); + } + + @Test + void copiesRulesDefensivelyOnConstruction() { + var rules = new ArrayList>(); + rules.add(new MinimumAgeRule(18)); + var engine = new RuleEngine<>(rules); + + rules.add(new CreditScoreRule(650)); // mutate the source after construction + assertEquals(1, engine.rules().size()); + } + + @Test + void exposedRulesAreUnmodifiable() { + var engine = loanEngine(); + assertThrows( + UnsupportedOperationException.class, () -> engine.rules().add(new MinimumAgeRule(21))); + } +} From 653bced9882dba8b17eb267c5ecc95b9a1327b2c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:47:52 +0300 Subject: [PATCH 09/17] docs: add MohamedMBG as a contributor for code (#3570) * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index f8d36d2f22cb..968092934e60 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3746,6 +3746,15 @@ "contributions": [ "doc" ] + }, + { + "login": "MohamedMBG", + "name": "BAGHDAD Mohamed", + "avatar_url": "https://avatars.githubusercontent.com/u/123114744?v=4", + "profile": "https://github.com/MohamedMBG", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 69c09eedc47e..7df0d735816f 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-411-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-412-orange.svg?style=flat-square)](#contributors-)
@@ -609,6 +609,7 @@ This project is licensed under the terms of the MIT license. Giuliano Oliveira
Giuliano Oliveira

🌍 Priyanshu
Priyanshu

💻 Arnab Nandy
Arnab Nandy

📖 + BAGHDAD Mohamed
BAGHDAD Mohamed

💻 From d49833234519aa405cc29191465fd2e1bce94337 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:49:02 +0300 Subject: [PATCH 10/17] build(deps): bump ch.qos.logback:logback-core in /subclass-sandbox (#3545) Bumps [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) from 1.5.34 to 1.5.35. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.34...v_1.5.35) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-core dependency-version: 1.5.35 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- subclass-sandbox/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index 1085dddb087b..79aa0b63cbfd 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -35,7 +35,7 @@ subclass-sandbox 2.0.18 - 1.5.34 + 1.5.35 From c298e94d96f1e692528dc742f1aee5a73e8516b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:50:34 +0300 Subject: [PATCH 11/17] build(deps): bump ch.qos.logback:logback-core in /polling-publisher (#3546) Bumps [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) from 1.5.18 to 1.5.34. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.18...v_1.5.34) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-core dependency-version: 1.5.34 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- polling-publisher/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polling-publisher/pom.xml b/polling-publisher/pom.xml index 2e5f7e8f35cb..1f69809390af 100644 --- a/polling-publisher/pom.xml +++ b/polling-publisher/pom.xml @@ -93,7 +93,7 @@ ch.qos.logback logback-core - 1.5.18 + 1.5.34 ch.qos.logback From 1673930bc0b4eadeb32a67292fdb435c6804a0f6 Mon Sep 17 00:00:00 2001 From: Anvesh Srivastava Date: Mon, 17 Aug 2026 00:26:51 +0530 Subject: [PATCH 12/17] feat: Add Backends For Frontends (BFF) pattern (#300) (#3543) * Add Backends For Frontends pattern (#300) Implements the BFF pattern with two client-specific gateways (MobileBff, DesktopBff) aggregating shared downstream services (AuthService, CartService, OrderService, SupplierService) into client-tailored response shapes. Closes #300 * Rename SupplierService lookup key to productName for clarity The service is looked up by product name throughout the codebase, not an actual product ID as the previous naming implied. * Address review feedback: remove unnecessary compact constructors, add InMemory* service tests --- backends-for-frontends/README.md | 148 ++++++++++++++++++ .../etc/backends-for-frontends.png | Bin 0 -> 136578 bytes .../etc/backends-for-frontends.urm.puml | 130 +++++++++++++++ backends-for-frontends/pom.xml | 67 ++++++++ .../src/main/java/com/iluwatar/bff/App.java | 109 +++++++++++++ .../java/com/iluwatar/bff/bff/ClientBff.java | 44 ++++++ .../java/com/iluwatar/bff/bff/DesktopBff.java | 94 +++++++++++ .../java/com/iluwatar/bff/bff/MobileBff.java | 86 ++++++++++ .../com/iluwatar/bff/bff/package-info.java | 29 ++++ .../bff/dto/DesktopDashboardResponse.java | 42 +++++ .../bff/dto/MobileDashboardResponse.java | 39 +++++ .../com/iluwatar/bff/dto/package-info.java | 28 ++++ .../java/com/iluwatar/bff/model/CartItem.java | 43 +++++ .../java/com/iluwatar/bff/model/Order.java | 34 ++++ .../java/com/iluwatar/bff/model/Product.java | 35 +++++ .../iluwatar/bff/model/SupplierRecord.java | 35 +++++ .../java/com/iluwatar/bff/model/User.java | 35 +++++ .../com/iluwatar/bff/model/package-info.java | 30 ++++ .../java/com/iluwatar/bff/package-info.java | 29 ++++ .../com/iluwatar/bff/service/AuthService.java | 43 +++++ .../com/iluwatar/bff/service/CartService.java | 43 +++++ .../iluwatar/bff/service/OrderService.java | 43 +++++ .../iluwatar/bff/service/SupplierService.java | 43 +++++ .../bff/service/impl/InMemoryAuthService.java | 58 +++++++ .../bff/service/impl/InMemoryCartService.java | 51 ++++++ .../service/impl/InMemoryOrderService.java | 51 ++++++ .../service/impl/InMemorySupplierService.java | 51 ++++++ .../bff/service/impl/package-info.java | 29 ++++ .../iluwatar/bff/service/package-info.java | 29 ++++ .../test/java/com/iluwatar/bff/AppTest.java | 41 +++++ .../com/iluwatar/bff/bff/DesktopBffTest.java | 77 +++++++++ .../com/iluwatar/bff/bff/MobileBffTest.java | 83 ++++++++++ .../service/impl/InMemoryAuthServiceTest.java | 54 +++++++ .../service/impl/InMemoryCartServiceTest.java | 60 +++++++ .../impl/InMemoryOrderServiceTest.java | 58 +++++++ .../impl/InMemorySupplierServiceTest.java | 58 +++++++ pom.xml | 1 + 37 files changed, 1930 insertions(+) create mode 100644 backends-for-frontends/README.md create mode 100644 backends-for-frontends/etc/backends-for-frontends.png create mode 100644 backends-for-frontends/etc/backends-for-frontends.urm.puml create mode 100644 backends-for-frontends/pom.xml create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/App.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/bff/ClientBff.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/bff/package-info.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/dto/DesktopDashboardResponse.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/dto/MobileDashboardResponse.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/dto/package-info.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/CartItem.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/Order.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/Product.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/SupplierRecord.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/User.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/model/package-info.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/package-info.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/AuthService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/CartService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/OrderService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/SupplierService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryAuthService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryCartService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryOrderService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemorySupplierService.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/package-info.java create mode 100644 backends-for-frontends/src/main/java/com/iluwatar/bff/service/package-info.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/bff/DesktopBffTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/bff/MobileBffTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryAuthServiceTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryCartServiceTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryOrderServiceTest.java create mode 100644 backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemorySupplierServiceTest.java diff --git a/backends-for-frontends/README.md b/backends-for-frontends/README.md new file mode 100644 index 000000000000..12038e821e38 --- /dev/null +++ b/backends-for-frontends/README.md @@ -0,0 +1,148 @@ +--- +title: "Backends For Frontends Pattern in Java: Tailoring APIs to Client Needs" +shortTitle: Backends For Frontends +description: "Learn the Backends For Frontends (BFF) design pattern in Java. Understand how to give each client type its own dedicated backend service, with real-world examples, code, and diagrams." +category: Architectural +language: en +tag: + - API design + - Architecture + - Client-server + - Decoupling + - Microservices +--- + +## Also known as + +* Backend For Frontend +* BFF Pattern + +## Intent of Backends For Frontends Pattern + +Provide each client-side application (mobile, desktop, chatbot, and so on) with its own dedicated +backend service, so every client gets an API shaped exactly for its own needs instead of sharing +one general-purpose backend with every other client. + +## Detailed Explanation of Backends For Frontends Pattern with Real-World Examples + +Real-world example + +> Imagine a retail company whose mobile app, desktop back-office tool, and support chatbot all +> need customer, cart, order and supplier data -- but a phone screen wants a short summary while +> the back-office desktop tool wants full order and stock detail. Rather than exposing one shared +> API that every client has to filter or over-fetch from, the company stands up a small BFF service +> for the mobile clients and a separate BFF service for the intranet clients. Each BFF calls only +> the downstream microservices its client needs and returns a payload shaped for that client. + +In plain words + +> Give every kind of client its own tailor-made backend, instead of forcing all clients through one +> one-size-fits-all API. + +Sam Newman, who popularized the pattern, says + +> Create separate backend services to be consumed by specific frontend applications or interfaces. + +## Architecture Diagram + +``` +node mobile{ + component iosapp as "ios app" + component androidapp as "android app" +} +node intranet{ + component desktop as "desktop app" + component chatbot +} +component bff as "BFF server"{ + component iosbff as "ios BFF" + component androidbff as "android BFF" + component chatbotbff as "chatbot BFF" + component desktopbff as "desktop BFF" +} +node intranetserv as "intranet services server"{ + component ss as "supplier service API" +} +cloud onlypublic as "public cloud"{ + component cas as "customer authentication service API" + component cs as "cart service API" +} +cloud cloudserv as "managed cloud"{ + component os as "order service API" +} +iosapp -- iosbff +androidapp -- androidbff +chatbot -- chatbotbff +desktop -- desktopbff +iosbff -- cas +androidbff -- cas +iosbff -- cs +androidbff -- cs +iosbff -- os +androidbff -- os +chatbotbff -- os +desktopbff -- os +chatbotbff -- ss +desktopbff -- ss +``` + +This example implements a simplified version of the diagram above with two client-facing BFFs +instead of four, to keep the demo focused: a **Mobile BFF** standing in for the ios/android BFFs, +and a **Desktop BFF** standing in for the desktop/chatbot BFFs. Both call into the same shared +downstream services (`AuthService`, `OrderService`), while `CartService` is only used by the +Mobile BFF and `SupplierService` is only reachable from the Desktop BFF, matching the fan-out +shown in the diagram. + +## Class Diagram + +![Backends For Frontends class diagram](./etc/backends-for-frontends.png) + +## When to Use the Backends For Frontends Pattern in Java + +* Different client types (mobile, web, desktop, voice/chat) need meaningfully different shapes, + granularity, or aggregation of the same underlying data. +* A single shared API has grown a large number of client-specific conditional branches, optional + fields, or query parameters to accommodate every consumer. +* Different client teams need to iterate on their own API independently without coordinating + changes through one shared backend team. +* Some clients (e.g. mobile) need aggressively trimmed payloads for bandwidth/latency reasons, + while others (e.g. an internal desktop tool) need much richer data. + +## Benefits and Trade-offs of Backends For Frontends Pattern + +Benefits: + +* Each client gets an API optimized for its own needs, improving performance and simplicity on + the client side. +* Client teams can evolve their BFF independently, reducing cross-team coordination. +* Downstream microservices stay generic and reusable; client-specific logic lives in the BFF + layer instead of leaking into shared services. + +Trade-offs: + +* Introduces additional services to build, deploy, and operate. +* Logic that is genuinely shared across clients can end up duplicated across BFFs if not + carefully factored out. +* Adds an extra network hop between the client and the downstream services. + +## How to Implement Backends For Frontends Pattern in Java + +1. Identify the distinct client types that need meaningfully different data shapes. +2. Define the downstream services each client's data actually depends on (`AuthService`, + `CartService`, `OrderService`, `SupplierService` in this example). +3. Create one BFF per client type, implementing a shared `ClientBff` contract, where each BFF + only depends on the downstream services its client needs. +4. Have each BFF aggregate and reshape the downstream data into a response DTO tailored to its + client (`MobileDashboardResponse`, `DesktopDashboardResponse`). +5. Wire the client applications to call their own BFF rather than the downstream services + directly. + +## Source Code + +* [Pattern: Backends For Frontends](https://samnewman.io/patterns/architectural/bff/) by Sam Newman +* [Microservices Patterns: With examples in Java](https://www.amazon.com/Microservices-Patterns-examples-Chris-Richardson/dp/1617294543) by Chris Richardson + +## References and Credits + +* [Building Microservices](https://www.oreilly.com/library/view/building-microservices-2nd/9781492034018/) by Sam Newman +* [Pattern: Backend for frontend (microservices.io)](https://microservices.io/patterns/apigateway.html) diff --git a/backends-for-frontends/etc/backends-for-frontends.png b/backends-for-frontends/etc/backends-for-frontends.png new file mode 100644 index 0000000000000000000000000000000000000000..f42c786fecf455deb2ded4327b25f65a2947bf70 GIT binary patch literal 136578 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

%_@^rnHcuxYZDS)Y4IQ1 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 literal 0 HcmV?d00001 diff --git a/backends-for-frontends/etc/backends-for-frontends.urm.puml b/backends-for-frontends/etc/backends-for-frontends.urm.puml new file mode 100644 index 000000000000..b09c06742d27 --- /dev/null +++ b/backends-for-frontends/etc/backends-for-frontends.urm.puml @@ -0,0 +1,130 @@ +@startuml +package com.iluwatar.bff { + class App { + - LOGGER : Logger {static} + - USER_ID : String {static} + - PRODUCT_ID : String {static} + - DEMO_PRICE_USD : double {static} + - DEMO_STOCK_LEVEL : int {static} + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.bff.bff { + interface ClientBff { + + getDashboard(userId : String) : T {abstract} + } + class DesktopBff { + - authService : AuthService + - orderService : OrderService + - supplierService : SupplierService + + DesktopBff(auth : AuthService, orders : OrderService, suppliers : SupplierService) + + getDashboard(userId : String) : DesktopDashboardResponse + } + class MobileBff { + - MAX_RECENT_ORDERS : int {static} + - authService : AuthService + - cartService : CartService + - orderService : OrderService + + MobileBff(auth : AuthService, cart : CartService, orders : OrderService) + + getDashboard(userId : String) : MobileDashboardResponse + } +} +package com.iluwatar.bff.dto { + class DesktopDashboardResponse { + - greeting : String + - loyaltyTier : String + - orderStatuses : List + - supplierStockSummaries : List + + DesktopDashboardResponse(greeting : String, loyaltyTier : String, orderStatuses : List, supplierStockSummaries : List) + } + class MobileDashboardResponse { + - greeting : String + - cartItemCount : int + - cartTotalUsd : double + - recentOrderSummaries : List + + MobileDashboardResponse(greeting : String, cartItemCount : int, cartTotalUsd : double, recentOrderSummaries : List) + } +} +package com.iluwatar.bff.model { + class CartItem { + - product : Product + - quantity : int + + CartItem(product : Product, quantity : int) + + lineTotal() : double + } + class Order { + - id : String + - productName : String + - status : String + + Order(id : String, productName : String, status : String) + } + class Product { + - id : String + - name : String + - priceUsd : double + + Product(id : String, name : String, priceUsd : double) + } + class SupplierRecord { + - productId : String + - supplierName : String + - stockLevel : int + + SupplierRecord(productId : String, supplierName : String, stockLevel : int) + } + class User { + - id : String + - displayName : String + - loyaltyTier : String + + User(id : String, displayName : String, loyaltyTier : String) + } +} +package com.iluwatar.bff.service { + interface AuthService { + + getUser(userId : String) : User {abstract} + } + interface CartService { + + getCart(userId : String) : List {abstract} + } + interface OrderService { + + getOrders(userId : String) : List {abstract} + } + interface SupplierService { + + getSupplierRecords(productId : String) : List {abstract} + } +} +package com.iluwatar.bff.service.impl { + class InMemoryAuthService { + - users : Map + + InMemoryAuthService(userData : Map) + + getUser(userId : String) : User + } + class InMemoryCartService { + - cartsByUserId : Map> + + InMemoryCartService(carts : Map>) + + getCart(userId : String) : List + } + class InMemoryOrderService { + - ordersByUserId : Map> + + InMemoryOrderService(orders : Map>) + + getOrders(userId : String) : List + } + class InMemorySupplierService { + - recordsByProductId : Map> + + InMemorySupplierService(records : Map>) + + getSupplierRecords(productId : String) : List + } +} +DesktopBff ..|> ClientBff +MobileBff ..|> ClientBff +DesktopBff --> "-authService" AuthService +DesktopBff --> "-orderService" OrderService +DesktopBff --> "-supplierService" SupplierService +MobileBff --> "-authService" AuthService +MobileBff --> "-cartService" CartService +MobileBff --> "-orderService" OrderService +InMemoryAuthService ..|> AuthService +InMemoryCartService ..|> CartService +InMemoryOrderService ..|> OrderService +InMemorySupplierService ..|> SupplierService +CartItem --> "-product" Product +@enduml diff --git a/backends-for-frontends/pom.xml b/backends-for-frontends/pom.xml new file mode 100644 index 000000000000..8f1e454fa646 --- /dev/null +++ b/backends-for-frontends/pom.xml @@ -0,0 +1,67 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + backends-for-frontends + + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.slf4j + slf4j-api + + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + com.iluwatar.bff.App + + + + + + + diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/App.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/App.java new file mode 100644 index 000000000000..b76939c53fd4 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/App.java @@ -0,0 +1,109 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff; + +import com.iluwatar.bff.bff.DesktopBff; +import com.iluwatar.bff.bff.MobileBff; +import com.iluwatar.bff.model.CartItem; +import com.iluwatar.bff.model.Order; +import com.iluwatar.bff.model.Product; +import com.iluwatar.bff.model.SupplierRecord; +import com.iluwatar.bff.model.User; +import com.iluwatar.bff.service.impl.InMemoryAuthService; +import com.iluwatar.bff.service.impl.InMemoryCartService; +import com.iluwatar.bff.service.impl.InMemoryOrderService; +import com.iluwatar.bff.service.impl.InMemorySupplierService; +import java.util.List; +import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * {@link App} demonstrates the Backends For Frontends (BFF) pattern. + * + *

A single set of downstream microservices (customer authentication, cart, order and supplier + * services) is shared by every client. Two different client-facing gateways -- {@link MobileBff} + * for the mobile apps and {@link DesktopBff} for the intranet desktop/chatbot clients -- each call + * a different subset of those services and reshape the results into a response tailored to what + * their own client actually needs, rather than exposing one one-size-fits-all API to every client. + */ +public final class App { + + /** Logger for this class. */ + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** User id used in the demonstration. */ + private static final String USER_ID = "u-1"; + + /** Product id used in the demonstration. */ + private static final String PRODUCT_ID = "p-42"; + + /** Unit price of the demo product in US dollars. */ + private static final double DEMO_PRICE_USD = 79.99; + + /** Supplier stock level used in the demonstration. */ + private static final int DEMO_STOCK_LEVEL = 120; + + private App() { + // utility class + } + + /** + * Program entry point. + * + * @param args no argument sent + */ + public static void main(final String[] args) { + // shared downstream microservices, as drawn in the pattern diagram + var authService = new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Alice", "GOLD"))); + + var product = new Product(PRODUCT_ID, "Wireless Headphones", DEMO_PRICE_USD); + var cartService = new InMemoryCartService(Map.of(USER_ID, List.of(new CartItem(product, 2)))); + + var orderService = + new InMemoryOrderService( + Map.of( + USER_ID, + List.of( + new Order("o-1", "Wireless Headphones", "DELIVERED"), + new Order("o-2", "USB-C Cable", "IN_TRANSIT")))); + + var supplierService = + new InMemorySupplierService( + Map.of( + "Wireless Headphones", + List.of(new SupplierRecord(PRODUCT_ID, "Acme Audio Co.", DEMO_STOCK_LEVEL)))); + + // client-specific BFFs, each calling only the services their client needs + var mobileBff = new MobileBff(authService, cartService, orderService); + var desktopBff = new DesktopBff(authService, orderService, supplierService); + + var mobileResponse = mobileBff.getDashboard(USER_ID); + LOGGER.info("Mobile BFF response: {}", mobileResponse); + + var desktopResponse = desktopBff.getDashboard(USER_ID); + LOGGER.info("Desktop BFF response: {}", desktopResponse); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/ClientBff.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/ClientBff.java new file mode 100644 index 000000000000..4c1d8d768ecb --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/ClientBff.java @@ -0,0 +1,44 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.bff; + +/** + * Common contract every client-specific Backend For Frontend implements: given a user id, build + * whatever response shape ({@code T}) that particular client needs. Each implementation is free to + * call a different subset of downstream services and aggregate them differently -- that freedom is + * the entire point of the pattern. + * + * @param the response DTO shape this BFF returns to its client + */ +public interface ClientBff { + + /** + * Builds the dashboard response for a given user, tailored to this BFF's client. + * + * @param userId identifier of the user requesting their dashboard + * @return the client-specific response + */ + T getDashboard(String userId); +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java new file mode 100644 index 000000000000..1073f4556558 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/DesktopBff.java @@ -0,0 +1,94 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.bff; + +import com.iluwatar.bff.dto.DesktopDashboardResponse; +import com.iluwatar.bff.service.AuthService; +import com.iluwatar.bff.service.OrderService; +import com.iluwatar.bff.service.SupplierService; +import java.util.ArrayList; +import java.util.List; + +/** + * Backend For Frontend serving the intranet clients (desktop app, chatbot) from the diagram. It + * aggregates the auth, order and supplier services and reshapes the results into a richer, + * back-office style payload. Unlike {@link MobileBff}, it does not touch the cart service at all + * and it does reach into the intranet-only supplier service, matching the fan-out drawn in the + * pattern diagram. + */ +public final class DesktopBff implements ClientBff { + + /** The customer authentication service. */ + private final AuthService authService; + + /** The order service. */ + private final OrderService orderService; + + /** The supplier service (intranet-only). */ + private final SupplierService supplierService; + + /** + * Creates a desktop BFF wired to the downstream services it depends on. + * + * @param auth the customer authentication service + * @param orders the order service + * @param suppliers the supplier service + */ + public DesktopBff( + final AuthService auth, final OrderService orders, final SupplierService suppliers) { + this.authService = auth; + this.orderService = orders; + this.supplierService = suppliers; + } + + @Override + public DesktopDashboardResponse getDashboard(final String userId) { + var user = authService.getUser(userId); + var orders = orderService.getOrders(userId); + + var orderStatuses = + orders.stream() + .map(order -> order.id() + ": " + order.productName() + " [" + order.status() + "]") + .toList(); + + var supplierStockSummaries = new ArrayList(); + for (var order : orders) { + for (var supplierRecord : supplierService.getSupplierRecords(order.productName())) { + supplierStockSummaries.add( + supplierRecord.supplierName() + + ": " + + supplierRecord.stockLevel() + + " units of " + + order.productName()); + } + } + + return new DesktopDashboardResponse( + "Welcome back, " + user.displayName(), + user.loyaltyTier(), + List.copyOf(orderStatuses), + List.copyOf(supplierStockSummaries)); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java new file mode 100644 index 000000000000..a51a7c8a8201 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/MobileBff.java @@ -0,0 +1,86 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.bff; + +import com.iluwatar.bff.dto.MobileDashboardResponse; +import com.iluwatar.bff.service.AuthService; +import com.iluwatar.bff.service.CartService; +import com.iluwatar.bff.service.OrderService; +import java.util.List; + +/** + * Backend For Frontend serving the mobile clients (iOS app, Android app) from the diagram. It + * aggregates the auth, cart and order services and reshapes the results into a small payload suited + * to a phone screen and a limited-bandwidth connection. It never calls the supplier service: a + * mobile shopper has no use for back-office stock data, so this BFF simply does not expose it, + * rather than sending it and letting the client ignore it. + */ +public final class MobileBff implements ClientBff { + + /** Maximum number of recent order summaries to include in the mobile response. */ + private static final int MAX_RECENT_ORDERS = 3; + + /** The customer authentication service. */ + private final AuthService authService; + + /** The cart service. */ + private final CartService cartService; + + /** The order service. */ + private final OrderService orderService; + + /** + * Creates a mobile BFF wired to the downstream services it depends on. + * + * @param auth the customer authentication service + * @param cart the cart service + * @param orders the order service + */ + public MobileBff(final AuthService auth, final CartService cart, final OrderService orders) { + this.authService = auth; + this.cartService = cart; + this.orderService = orders; + } + + @Override + public MobileDashboardResponse getDashboard(final String userId) { + var user = authService.getUser(userId); + var cart = cartService.getCart(userId); + var orders = orderService.getOrders(userId); + + var cartTotal = cart.stream().mapToDouble(item -> item.lineTotal()).sum(); + var recentOrderSummaries = + orders.stream() + .limit(MAX_RECENT_ORDERS) + .map(order -> order.productName() + " (" + order.status() + ")") + .toList(); + + return new MobileDashboardResponse( + "Hi " + user.displayName() + "!", + cart.size(), + cartTotal, + List.copyOf(recentOrderSummaries)); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/package-info.java new file mode 100644 index 000000000000..c338c3158023 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/bff/package-info.java @@ -0,0 +1,29 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * Client-specific Backend For Frontend implementations: one per client type (mobile, desktop) that + * each aggregate a different subset of downstream services. + */ +package com.iluwatar.bff.bff; diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/DesktopDashboardResponse.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/DesktopDashboardResponse.java new file mode 100644 index 000000000000..434e1f1cc088 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/DesktopDashboardResponse.java @@ -0,0 +1,42 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.dto; + +import java.util.List; + +/** + * The shape of data the desktop back-office client renders: richer than the mobile payload, + * including full order status and supplier stock levels that a mobile shopper never needs. + * + * @param greeting a short personalized greeting for the user + * @param loyaltyTier the user's loyalty program tier + * @param orderStatuses detailed "id: productName [status]" lines for every order + * @param supplierStockSummaries "supplierName: stockLevel units" lines for relevant products + */ +public record DesktopDashboardResponse( + String greeting, + String loyaltyTier, + List orderStatuses, + List supplierStockSummaries) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/MobileDashboardResponse.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/MobileDashboardResponse.java new file mode 100644 index 000000000000..d6d27619c36d --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/MobileDashboardResponse.java @@ -0,0 +1,39 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.dto; + +import java.util.List; + +/** + * The shape of data the mobile (iOS/Android) client actually renders: a lean payload with just + * enough for a small screen, deliberately excluding fields the desktop client needs. + * + * @param greeting a short personalized greeting for the user + * @param cartItemCount number of items currently in the user's cart + * @param cartTotalUsd total value of the user's cart in US dollars + * @param recentOrderSummaries short human-readable summaries of the user's most recent orders + */ +public record MobileDashboardResponse( + String greeting, int cartItemCount, double cartTotalUsd, List recentOrderSummaries) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/package-info.java new file mode 100644 index 000000000000..43a23d0dbc4e --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/dto/package-info.java @@ -0,0 +1,28 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * Response DTOs shaped by each BFF for its specific client (mobile dashboard, desktop dashboard). + */ +package com.iluwatar.bff.dto; diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/CartItem.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/CartItem.java new file mode 100644 index 000000000000..a71c4848c791 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/CartItem.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.model; + +/** + * A single line item inside a user's shopping cart, as returned by the cart service API. + * + * @param product the product being purchased + * @param quantity number of units of the product + */ +public record CartItem(Product product, int quantity) { + + /** + * Computes the line total for this cart item. + * + * @return quantity multiplied by unit price + */ + public double lineTotal() { + return quantity * product.priceUsd(); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Order.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Order.java new file mode 100644 index 000000000000..02a2026695b0 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Order.java @@ -0,0 +1,34 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.model; + +/** + * A past order returned by the order service API. + * + * @param id order identifier + * @param productName name of the ordered product + * @param status current fulfillment status, e.g. "DELIVERED", "IN_TRANSIT" + */ +public record Order(String id, String productName, String status) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Product.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Product.java new file mode 100644 index 000000000000..ae4176860b6e --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/Product.java @@ -0,0 +1,35 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.model; + +/** + * Simple product record returned by the downstream Cart/Order services. Represents the data a + * catalog or cart entry carries before each BFF trims or reshapes it for its own client. + * + * @param id product identifier + * @param name display name of the product + * @param priceUsd unit price in US dollars + */ +public record Product(String id, String name, double priceUsd) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/SupplierRecord.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/SupplierRecord.java new file mode 100644 index 000000000000..f7dfa38fe89d --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/SupplierRecord.java @@ -0,0 +1,35 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.model; + +/** + * A supplier stock record returned by the supplier service API, used by the desktop back-office + * client to show inventory information that mobile customers never need to see. + * + * @param productId identifier of the product this record refers to + * @param supplierName name of the supplying vendor + * @param stockLevel units currently available from this supplier + */ +public record SupplierRecord(String productId, String supplierName, int stockLevel) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/User.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/User.java new file mode 100644 index 000000000000..5c59c7f963ec --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/User.java @@ -0,0 +1,35 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.model; + +/** + * Authenticated user profile returned by the customer authentication service API. Kept + * intentionally minimal; each BFF decides which of these fields its client actually needs. + * + * @param id unique user identifier + * @param displayName human-readable name of the user + * @param loyaltyTier loyalty program tier, e.g. "GOLD", "SILVER", "STANDARD" + */ +public record User(String id, String displayName, String loyaltyTier) {} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/model/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/package-info.java new file mode 100644 index 000000000000..37d2855a8671 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/model/package-info.java @@ -0,0 +1,30 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * Domain model records shared across downstream services: User, Product, CartItem, Order, and + * SupplierRecord. Each BFF consumes these raw domain objects and reshapes them into its own + * client-specific DTO. + */ +package com.iluwatar.bff.model; diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/package-info.java new file mode 100644 index 000000000000..ede18f2b22f9 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/package-info.java @@ -0,0 +1,29 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * Backends For Frontends pattern: a dedicated gateway per client type (mobile, desktop) that + * aggregates only the downstream services each client actually needs. + */ +package com.iluwatar.bff; diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/AuthService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/AuthService.java new file mode 100644 index 000000000000..a87b75b48bb6 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/AuthService.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service; + +import com.iluwatar.bff.model.User; + +/** + * Represents the customer authentication service API from the diagram: a downstream microservice + * shared by every client-specific BFF. Each BFF calls this the same way; only what they do with the + * result differs. + */ +public interface AuthService { + + /** + * Looks up the authenticated user profile for the given id. + * + * @param userId identifier of the user to look up + * @return the matching {@link User} + */ + User getUser(String userId); +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/CartService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/CartService.java new file mode 100644 index 000000000000..7ae24fba64bc --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/CartService.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service; + +import com.iluwatar.bff.model.CartItem; +import java.util.List; + +/** + * Represents the cart service API from the diagram. In this example only the mobile and android + * clients need cart data, so only {@link com.iluwatar.bff.bff.MobileBff} calls this service. + */ +public interface CartService { + + /** + * Retrieves the current cart contents for a user. + * + * @param userId identifier of the user whose cart is requested + * @return the list of items currently in the user's cart + */ + List getCart(String userId); +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/OrderService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/OrderService.java new file mode 100644 index 000000000000..b8e6ee8fa03e --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/OrderService.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service; + +import com.iluwatar.bff.model.Order; +import java.util.List; + +/** + * Represents the order service API from the diagram. This downstream service is shared by every + * client-specific BFF, matching the fan-out shown for "order service API" in the pattern diagram. + */ +public interface OrderService { + + /** + * Retrieves the order history for a user. + * + * @param userId identifier of the user whose orders are requested + * @return the list of past orders for the user + */ + List getOrders(String userId); +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/SupplierService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/SupplierService.java new file mode 100644 index 000000000000..ac7c2dfbc849 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/SupplierService.java @@ -0,0 +1,43 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service; + +import com.iluwatar.bff.model.SupplierRecord; +import java.util.List; + +/** + * Represents the supplier service API from the diagram, reachable only from the intranet services + * server. Only back-office style clients (desktop app, chatbot) call this service. + */ +public interface SupplierService { + + /** + * Retrieves supplier stock records for a product. + * + * @param productName name of the product to check stock for + * @return the list of supplier stock records for the product + */ + List getSupplierRecords(String productName); +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryAuthService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryAuthService.java new file mode 100644 index 000000000000..5c2ffc35958f --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryAuthService.java @@ -0,0 +1,58 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import com.iluwatar.bff.model.User; +import com.iluwatar.bff.service.AuthService; +import java.util.Map; + +/** + * In-memory stand-in for the real customer authentication service API. Real deployments would + * replace this with an HTTP/gRPC client; the BFFs are written against the {@link AuthService} + * interface, so swapping the implementation later requires no change to any BFF. + */ +public final class InMemoryAuthService implements AuthService { + + /** Users stored in memory, keyed by user id. */ + private final Map users; + + /** + * Creates the service with a fixed backing map of users, keyed by user id. + * + * @param userData the user data this service serves + */ + public InMemoryAuthService(final Map userData) { + this.users = userData; + } + + @Override + public User getUser(final String userId) { + var user = users.get(userId); + if (user == null) { + throw new IllegalArgumentException("Unknown user id: " + userId); + } + return user; + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryCartService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryCartService.java new file mode 100644 index 000000000000..fed3b59da2c8 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryCartService.java @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import com.iluwatar.bff.model.CartItem; +import com.iluwatar.bff.service.CartService; +import java.util.List; +import java.util.Map; + +/** In-memory stand-in for the real cart service API. */ +public final class InMemoryCartService implements CartService { + + /** Carts stored in memory, keyed by user id. */ + private final Map> cartsByUserId; + + /** + * Creates the service with a fixed backing map of carts, keyed by user id. + * + * @param carts the cart data this service serves + */ + public InMemoryCartService(final Map> carts) { + this.cartsByUserId = carts; + } + + @Override + public List getCart(final String userId) { + return cartsByUserId.getOrDefault(userId, List.of()); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryOrderService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryOrderService.java new file mode 100644 index 000000000000..979956d06244 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemoryOrderService.java @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import com.iluwatar.bff.model.Order; +import com.iluwatar.bff.service.OrderService; +import java.util.List; +import java.util.Map; + +/** In-memory stand-in for the real order service API. */ +public final class InMemoryOrderService implements OrderService { + + /** Order histories stored in memory, keyed by user id. */ + private final Map> ordersByUserId; + + /** + * Creates the service with a fixed backing map of order histories, keyed by user id. + * + * @param orders the order data this service serves + */ + public InMemoryOrderService(final Map> orders) { + this.ordersByUserId = orders; + } + + @Override + public List getOrders(final String userId) { + return ordersByUserId.getOrDefault(userId, List.of()); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemorySupplierService.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemorySupplierService.java new file mode 100644 index 000000000000..ac2d351db3a5 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/InMemorySupplierService.java @@ -0,0 +1,51 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import com.iluwatar.bff.model.SupplierRecord; +import com.iluwatar.bff.service.SupplierService; +import java.util.List; +import java.util.Map; + +/** In-memory stand-in for the real supplier service API, reachable only from the intranet. */ +public final class InMemorySupplierService implements SupplierService { + + /** Supplier records stored in memory, keyed by product name. */ + private final Map> recordsByProductName; + + /** + * Creates the service with a fixed backing map of supplier records, keyed by product name. + * + * @param records the supplier data this service serves + */ + public InMemorySupplierService(final Map> records) { + this.recordsByProductName = records; + } + + @Override + public List getSupplierRecords(final String productName) { + return recordsByProductName.getOrDefault(productName, List.of()); + } +} diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/package-info.java new file mode 100644 index 000000000000..fbdb5d026bc8 --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/impl/package-info.java @@ -0,0 +1,29 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * In-memory implementations of the downstream service API interfaces, used for the pattern + * demonstration. Production deployments would replace these with real HTTP/gRPC clients. + */ +package com.iluwatar.bff.service.impl; diff --git a/backends-for-frontends/src/main/java/com/iluwatar/bff/service/package-info.java b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/package-info.java new file mode 100644 index 000000000000..05bfcb3911df --- /dev/null +++ b/backends-for-frontends/src/main/java/com/iluwatar/bff/service/package-info.java @@ -0,0 +1,29 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/** + * Downstream service API interfaces shared by all BFFs: AuthService, CartService, OrderService, and + * SupplierService. Each BFF wires in only the services its client requires. + */ +package com.iluwatar.bff.service; diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java new file mode 100644 index 000000000000..d06d945c8c33 --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/AppTest.java @@ -0,0 +1,41 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** + * Tests that {@link App}'s demo entry point runs end-to-end without throwing, following the + * convention used throughout this repository for pattern demo apps. + */ +class AppTest { + + @Test + void mainShouldRunWithoutException() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/DesktopBffTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/DesktopBffTest.java new file mode 100644 index 000000000000..d4a2331b101b --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/DesktopBffTest.java @@ -0,0 +1,77 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.bff; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.bff.model.Order; +import com.iluwatar.bff.model.SupplierRecord; +import com.iluwatar.bff.model.User; +import com.iluwatar.bff.service.impl.InMemoryAuthService; +import com.iluwatar.bff.service.impl.InMemoryOrderService; +import com.iluwatar.bff.service.impl.InMemorySupplierService; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link DesktopBff}. */ +class DesktopBffTest { + + private static final String USER_ID = "u-1"; + + @Test + void shouldAggregateOrdersAndSupplierStockIntoDesktopShape() { + var authService = new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Alice", "GOLD"))); + var orderService = + new InMemoryOrderService( + Map.of(USER_ID, List.of(new Order("o-1", "Headphones", "DELIVERED")))); + var supplierService = + new InMemorySupplierService( + Map.of("Headphones", List.of(new SupplierRecord("p-1", "Acme Audio", 30)))); + + var bff = new DesktopBff(authService, orderService, supplierService); + var response = bff.getDashboard(USER_ID); + + assertEquals("Welcome back, Alice", response.greeting()); + assertEquals("GOLD", response.loyaltyTier()); + assertTrue(response.orderStatuses().get(0).contains("Headphones")); + assertTrue(response.supplierStockSummaries().get(0).contains("Acme Audio")); + } + + @Test + void shouldReturnNoSupplierSummariesWhenNoOrdersExist() { + var authService = + new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Carol", "STANDARD"))); + var orderService = new InMemoryOrderService(Map.of(USER_ID, List.of())); + var supplierService = new InMemorySupplierService(Map.of()); + + var bff = new DesktopBff(authService, orderService, supplierService); + var response = bff.getDashboard(USER_ID); + + assertEquals(0, response.orderStatuses().size()); + assertEquals(0, response.supplierStockSummaries().size()); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/MobileBffTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/MobileBffTest.java new file mode 100644 index 000000000000..f05a0be99b61 --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/bff/MobileBffTest.java @@ -0,0 +1,83 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.bff; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.bff.model.CartItem; +import com.iluwatar.bff.model.Order; +import com.iluwatar.bff.model.Product; +import com.iluwatar.bff.model.User; +import com.iluwatar.bff.service.impl.InMemoryAuthService; +import com.iluwatar.bff.service.impl.InMemoryCartService; +import com.iluwatar.bff.service.impl.InMemoryOrderService; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link MobileBff}. */ +class MobileBffTest { + + private static final String USER_ID = "u-1"; + + @Test + void shouldAggregateCartAndOrdersIntoMobileShape() { + var authService = new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Alice", "GOLD"))); + var product = new Product("p-1", "Headphones", 50.0); + var cartService = new InMemoryCartService(Map.of(USER_ID, List.of(new CartItem(product, 2)))); + var orderService = + new InMemoryOrderService( + Map.of(USER_ID, List.of(new Order("o-1", "Headphones", "DELIVERED")))); + + var bff = new MobileBff(authService, cartService, orderService); + var response = bff.getDashboard(USER_ID); + + assertEquals("Hi Alice!", response.greeting()); + assertEquals(1, response.cartItemCount()); + assertEquals(100.0, response.cartTotalUsd()); + assertTrue(response.recentOrderSummaries().get(0).contains("Headphones")); + } + + @Test + void shouldCapRecentOrderSummariesAtThree() { + var authService = new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Bob", "SILVER"))); + var cartService = new InMemoryCartService(Map.of(USER_ID, List.of())); + var orderService = + new InMemoryOrderService( + Map.of( + USER_ID, + List.of( + new Order("o-1", "A", "DELIVERED"), + new Order("o-2", "B", "DELIVERED"), + new Order("o-3", "C", "DELIVERED"), + new Order("o-4", "D", "DELIVERED")))); + + var bff = new MobileBff(authService, cartService, orderService); + var response = bff.getDashboard(USER_ID); + + assertEquals(3, response.recentOrderSummaries().size()); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryAuthServiceTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryAuthServiceTest.java new file mode 100644 index 000000000000..db4da0c0ba0d --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryAuthServiceTest.java @@ -0,0 +1,54 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import com.iluwatar.bff.model.User; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link InMemoryAuthService}. */ +class InMemoryAuthServiceTest { + + private static final String USER_ID = "u-1"; + + @Test + void shouldReturnUserForKnownId() { + var expected = new User(USER_ID, "Alice", "GOLD"); + var service = new InMemoryAuthService(Map.of(USER_ID, expected)); + + var actual = service.getUser(USER_ID); + + assertEquals(expected, actual); + } + + @Test + void shouldThrowForUnknownId() { + var service = new InMemoryAuthService(Map.of(USER_ID, new User(USER_ID, "Alice", "GOLD"))); + + assertThrows(IllegalArgumentException.class, () -> service.getUser("unknown-id")); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryCartServiceTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryCartServiceTest.java new file mode 100644 index 000000000000..19e54841fa44 --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryCartServiceTest.java @@ -0,0 +1,60 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.bff.model.CartItem; +import com.iluwatar.bff.model.Product; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link InMemoryCartService}. */ +class InMemoryCartServiceTest { + + private static final String USER_ID = "u-1"; + + @Test + void shouldReturnCartItemsForKnownUser() { + var product = new Product("p-1", "Headphones", 49.99); + var item = new CartItem(product, 2); + var service = new InMemoryCartService(Map.of(USER_ID, List.of(item))); + + var cart = service.getCart(USER_ID); + + assertEquals(1, cart.size()); + assertEquals(item, cart.get(0)); + } + + @Test + void shouldReturnEmptyListForUnknownUser() { + var service = new InMemoryCartService(Map.of()); + + var cart = service.getCart("unknown-user"); + + assertTrue(cart.isEmpty()); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryOrderServiceTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryOrderServiceTest.java new file mode 100644 index 000000000000..26b7d82be105 --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemoryOrderServiceTest.java @@ -0,0 +1,58 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.bff.model.Order; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link InMemoryOrderService}. */ +class InMemoryOrderServiceTest { + + private static final String USER_ID = "u-1"; + + @Test + void shouldReturnOrdersForKnownUser() { + var order = new Order("o-1", "Headphones", "DELIVERED"); + var service = new InMemoryOrderService(Map.of(USER_ID, List.of(order))); + + var orders = service.getOrders(USER_ID); + + assertEquals(1, orders.size()); + assertEquals(order, orders.get(0)); + } + + @Test + void shouldReturnEmptyListForUnknownUser() { + var service = new InMemoryOrderService(Map.of()); + + var orders = service.getOrders("unknown-user"); + + assertTrue(orders.isEmpty()); + } +} diff --git a/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemorySupplierServiceTest.java b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemorySupplierServiceTest.java new file mode 100644 index 000000000000..ce5d39041033 --- /dev/null +++ b/backends-for-frontends/src/test/java/com/iluwatar/bff/service/impl/InMemorySupplierServiceTest.java @@ -0,0 +1,58 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.bff.service.impl; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.bff.model.SupplierRecord; +import java.util.List; +import java.util.Map; +import org.junit.jupiter.api.Test; + +/** Tests for {@link InMemorySupplierService}. */ +class InMemorySupplierServiceTest { + + private static final String PRODUCT_NAME = "Headphones"; + + @Test + void shouldReturnSupplierRecordsForKnownProductName() { + var record = new SupplierRecord("p-1", "Acme Audio", 30); + var service = new InMemorySupplierService(Map.of(PRODUCT_NAME, List.of(record))); + + var records = service.getSupplierRecords(PRODUCT_NAME); + + assertEquals(1, records.size()); + assertEquals(record, records.get(0)); + } + + @Test + void shouldReturnEmptyListForUnknownProductName() { + var service = new InMemorySupplierService(Map.of()); + + var records = service.getSupplierRecords("unknown-product"); + + assertTrue(records.isEmpty()); + } +} diff --git a/pom.xml b/pom.xml index 4a16f9940bbe..16590b9c34a7 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,7 @@ anti-corruption-layer arrange-act-assert async-method-invocation + backends-for-frontends balking bloc bridge From 29442249f8784841d693456a36d3a39278ebcbe8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:57:31 +0300 Subject: [PATCH 13/17] docs: add AnveshSrivastava as a contributor for code (#3571) * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 968092934e60..2410c6aecc03 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3755,6 +3755,15 @@ "contributions": [ "code" ] + }, + { + "login": "AnveshSrivastava", + "name": "Anvesh Srivastava", + "avatar_url": "https://avatars.githubusercontent.com/u/170334970?v=4", + "profile": "https://github.com/AnveshSrivastava", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 7df0d735816f..f49aaa4b6422 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-412-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-413-orange.svg?style=flat-square)](#contributors-)
@@ -610,6 +610,7 @@ This project is licensed under the terms of the MIT license.
Priyanshu
Priyanshu

💻 Arnab Nandy
Arnab Nandy

📖 BAGHDAD Mohamed
BAGHDAD Mohamed

💻 + Anvesh Srivastava
Anvesh Srivastava

💻 From 8c7a3105df5a5cba44e7a2aee3f450efc41b3c26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:59:12 +0300 Subject: [PATCH 14/17] build(deps): bump com.fasterxml.jackson.core:jackson-databind (#3549) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.18.3 to 2.18.9. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.18.9 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- event-sourcing/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 27a72e5f5f65..eefacf7252d4 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -55,7 +55,7 @@ com.fasterxml.jackson.core jackson-databind - 2.18.3 + 2.18.9 From a563344a355d50953de8283147fe7eca75b27671 Mon Sep 17 00:00:00 2001 From: Mukul Howale <110479646+Mukul-Howale@users.noreply.github.com> Date: Mon, 17 Aug 2026 00:42:29 +0530 Subject: [PATCH 15/17] feat: microservice messaging pattern (#3564) * Initialize microservices-messaging Spring Boot project Add initial project structure for microservices-messaging using Spring Boot. Includes Maven configuration with dependencies for Kafka, Lombok, and testing, as well as main application, test class, and application properties. * Initialize microservices messaging pattern 1. Added initial project structure for demonstrating the microservices messaging pattern. 2. Introduced service stubs (OrderService, InventoryService, PaymentService, NotificationService), a Message and MessageBroker class, and a main App entry point. 3. Added README and logging configuration. * Implement Message and MessageBroker classes 1. Added the Message class with unique ID, content, and timestamp fields, and a toString method. 2. Implemented the MessageBroker class to support topic-based publish-subscribe messaging, including subscriber management, message publishing, and logging. * Implement messaging pattern for microservices 1. Added message handling logic to InventoryService, PaymentService, and NotificationService. 2. OrderService now publishes order events to a MessageBroker, and App demonstrates the messaging workflow. 3. Each service processes relevant order events and logs actions for demonstration purposes. * Expand microservices messaging docs and add diagrams 1. Enhanced the README with detailed explanations, real-world examples, Java code samples, and references for the Microservices Messaging pattern. 2. Added flowchart and sequence diagram images to illustrate the pattern. * Refactor to use Kafka for microservices messaging 1. Added Apache Kafka for asynchronous communication between services. 2. Added KafkaMessageProducer and KafkaMessageConsumer classes, updated service implementations and main application logic to use Kafka, and adjusted the Maven configuration to include Kafka and Jackson dependencies. 3. Updated and moved all classes to the com.iluwatar.messaging package, improved documentation, and updated diagrams to reflect the new architecture. * Add unit tests and license headers to messaging module 1. Added comprehensive unit tests for App, InventoryService, KafkaMessageConsumer, KafkaMessageProducer, Message, NotificationService, OrderService, and PaymentService. 2. Added MIT license headers to all main source files and logback.xml. 3. Updated pom.xml to include JUnit Jupiter as a test dependency. * Refactor and simplify service and Kafka test classes 1. Simplified unit tests for InventoryService, NotificationService, and PaymentService by removing null content tests and adding instantiation checks. 2. Refactored KafkaMessageConsumerTest and KafkaMessageProducerTest to avoid requiring a real Kafka instance, focusing on class structure and method existence instead of integration behavior. * Add microservices-messaging module and run scripts Introduce the microservices-messaging module and register it in the root pom.xml. Add docker-compose.yml to run a local Kafka (confluentinc/cp-kafka) with a healthcheck, plus run-app.ps1 and run-app.sh helper scripts that start Kafka if needed and then launch the application. Update the module README with usage instructions. Also remove a duplicated junit-jupiter-api test dependency from the module pom to rely on project defaults. * microservices-messaging: code style and Lombok Add Lombok as a provided dependency and apply formatting/refactoring across the microservices-messaging module. Changes include import reordering, Javadoc and logging formatting, consistent lambda/try/catch indentation, small Kafka consumer/producer refinements (Duration/Properties usage and callback formatting), Message class tweaks (@Getter, JSON ctor and toString formatting) and EOF/newline fixes. Unit tests were also reformatted for consistency. These are non-functional style and readability improvements; no behavior changes intended. * Make Kafka producer/consumer testable Refactor KafkaMessageProducer and KafkaMessageConsumer to depend on the Producer/Consumer interfaces and add constructors that accept mockable instances. Extract default producer/consumer creation into factory methods so tests can inject MockProducer/MockConsumer. Update tests across the microservices-messaging module to use MockProducer/MockConsumer, add more meaningful assertions, error/interrupt handling tests, and simplify AppTest. These changes improve unit testability and remove the need for a running Kafka instance while preserving runtime behavior. * Format test Javadoc and reorder imports Normalize Javadoc formatting and reorder static JUnit imports for consistency in messaging tests. Converted multi-line test Javadocs to single-line comments and adjusted import ordering in the following files: - microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageConsumerTest.java - microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageProducerTest.java - microservices-messaging/src/test/java/com/iluwatar/messaging/OrderServiceTest.java No functional changes. * Add MIT headers and exclude .ps1 from license checks Add MIT license headers to microservices-messaging/docker-compose.yml, run-app.ps1 and run-app.sh to ensure license text is present in these scripts. Update root pom.xml to exclude PowerShell (*.ps1) files from the license plugin checks so those files are not processed by the license rule. * Add Kafka docker service to CI workflows Bring up Kafka for tests in CI and PR workflows. Adds steps to run docker compose for microservices-messaging, poll Kafka readiness (up to 20 retries), and always tear down with docker compose down. Enables Maven tests that depend on Kafka. Affects .github/workflows/maven-ci.yml and .github/workflows/maven-pr-builder.yml. * Use kafka-topics instead of kafka-topics.sh Replace calls to kafka-topics.sh with kafka-topics in CI workflows and the Docker Compose healthcheck. Updated .github/workflows/maven-ci.yml, .github/workflows/maven-pr-builder.yml, and microservices-messaging/docker-compose.yml to use the kafka-topics binary for readiness checks and healthchecks. This prevents failures on images that expose the kafka-topics command without the .sh wrapper. * Use docker compose --wait for Kafka startup Replace the custom bash readiness loop with `docker compose ... up -d --wait` in CI and PR workflows. This simplifies startup of the microservices-messaging Kafka service and removes the manual retry/polling logic. Files changed: .github/workflows/maven-ci.yml, .github/workflows/maven-pr-builder.yml. Note: requires a Docker Compose version that supports the `--wait` flag. * Reformat tests for readability Reformatted KafkaMessageConsumerTest and PaymentServiceTest for readability and consistent formatting: reflowed constructor invocation, expanded anonymous HashMap and schedulePollTask lambda blocks, and aligned assertDoesNotThrow parameters. These are pure style changes with no behavioral modifications. * Remove Kafka Docker Compose steps from CI Removed the Start/Stop Kafka Docker Service steps that ran docker compose for microservices-messaging from .github/workflows/maven-ci.yml and .github/workflows/maven-pr-builder.yml. Workflows no longer start or tear down the Kafka docker-compose service during CI/PR runs; other steps (xvfb install, Maven build, Codecov upload, Sonar cache) remain unchanged. * Bump google-java-format to 1.27.0; tidy tests Update pom.xml to use google-java-format 1.27.0 (was 1.17.0). Make minor formatting cleanups in KafkaMessageConsumerTest and PaymentServiceTest by collapsing multi-line calls into single lines. No functional changes. * Downgrade Google Java Format to 1.17.0 Update Spotless googleJavaFormat version in root pom.xml from 1.27.0 to 1.17.0 * Improve Kafka producer and consumer tests Enhance microservices-messaging tests: add consumer tests to verify run() exits immediately when stopped and gracefully handles a WakeupException (ensuring the MockConsumer is closed). Update producer error test to avoid try-with-resources, assert publish behavior and history, trigger failingProducer.errorNext(...) before closing to cover the error callback branch, then close and assert the mock producer is closed. * Refactor App.run and add messaging tests Extract App.run(...) and introduce a package-private sleepMs field to control sleep durations so the demo can be exercised programmatically and sped up for tests. Main now delegates to run; consumers are started there. Tests updated: AppTest sets sleepMs to 0 and adds testRunWithMockObjects using MockProducer/MockConsumer to exercise run without a Kafka broker; KafkaMessageProducerTest adds a null-message publish test; minor formatting fix in KafkaMessageConsumerTest. These changes improve testability and coverage for the microservices-messaging module. --- microservices-messaging/README.md | 247 ++++++++++++++++++ microservices-messaging/docker-compose.yml | 53 ++++ .../etc/microservices-messaging-flowchart.png | Bin 0 -> 115287 bytes ...croservices-messaging-sequence-diagram.png | Bin 0 -> 190642 bytes microservices-messaging/pom.xml | 118 +++++++++ microservices-messaging/run-app.ps1 | 89 +++++++ microservices-messaging/run-app.sh | 62 +++++ .../main/java/com/iluwatar/messaging/App.java | 161 ++++++++++++ .../iluwatar/messaging/InventoryService.java | 86 ++++++ .../messaging/KafkaMessageConsumer.java | 125 +++++++++ .../messaging/KafkaMessageProducer.java | 108 ++++++++ .../java/com/iluwatar/messaging/Message.java | 75 ++++++ .../messaging/NotificationService.java | 100 +++++++ .../com/iluwatar/messaging/OrderService.java | 76 ++++++ .../iluwatar/messaging/PaymentService.java | 85 ++++++ .../src/main/resources/logback.xml | 40 +++ .../java/com/iluwatar/messaging/AppTest.java | 85 ++++++ .../messaging/InventoryServiceTest.java | 118 +++++++++ .../messaging/KafkaMessageConsumerTest.java | 137 ++++++++++ .../messaging/KafkaMessageProducerTest.java | 93 +++++++ .../com/iluwatar/messaging/MessageTest.java | 165 ++++++++++++ .../messaging/NotificationServiceTest.java | 134 ++++++++++ .../iluwatar/messaging/OrderServiceTest.java | 109 ++++++++ .../messaging/PaymentServiceTest.java | 116 ++++++++ pom.xml | 2 + 25 files changed, 2384 insertions(+) create mode 100644 microservices-messaging/README.md create mode 100644 microservices-messaging/docker-compose.yml create mode 100644 microservices-messaging/etc/microservices-messaging-flowchart.png create mode 100644 microservices-messaging/etc/microservices-messaging-sequence-diagram.png create mode 100644 microservices-messaging/pom.xml create mode 100644 microservices-messaging/run-app.ps1 create mode 100644 microservices-messaging/run-app.sh create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/App.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/InventoryService.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageConsumer.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageProducer.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/Message.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/NotificationService.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/OrderService.java create mode 100644 microservices-messaging/src/main/java/com/iluwatar/messaging/PaymentService.java create mode 100644 microservices-messaging/src/main/resources/logback.xml create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/AppTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/InventoryServiceTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageConsumerTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageProducerTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/MessageTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/NotificationServiceTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/OrderServiceTest.java create mode 100644 microservices-messaging/src/test/java/com/iluwatar/messaging/PaymentServiceTest.java diff --git a/microservices-messaging/README.md b/microservices-messaging/README.md new file mode 100644 index 000000000000..3ca95350e2a8 --- /dev/null +++ b/microservices-messaging/README.md @@ -0,0 +1,247 @@ +--- +title: "Microservices Messaging Pattern in Java: Enabling Asynchronous Communication Between Services" +shortTitle: Microservices Messaging +description: "Learn about the Microservices Messaging pattern, a method for enabling asynchronous communication between services through message brokers to enhance decoupling, scalability, and fault tolerance in distributed systems." +category: Integration +language: en +tag: + - API design + - Asynchronous + - Cloud distributed + - Decoupling + - Enterprise patterns + - Event-driven + - Messaging + - Microservices + - Scalability +--- +## Also known as + +* Asynchronous Messaging +* Event-Driven Communication +* Message-Oriented Middleware (MOM) + +## Intent of Microservices Messaging Design Pattern + +The Microservices Messaging pattern enables asynchronous communication between microservices through message passing, allowing for better decoupling, scalability, and fault tolerance. Services communicate by exchanging messages over messaging channels managed by a message broker. + +## Detailed Explanation of Microservices Messaging Pattern with Real-World Examples + +Real-world example + +> Imagine an e-commerce platform where a customer places an order. The Order Service publishes an "Order Created" message to a message broker. Multiple services listen to this message: the Inventory Service updates stock levels, the Payment Service processes payment, and the Notification Service sends confirmation emails. Each service operates independently, processing messages at its own pace without blocking others. If the Payment Service is temporarily down, the message broker holds the message until it recovers, ensuring no data is lost. + +In plain words + +> The Microservices Messaging pattern allows services to communicate asynchronously through a message broker, enabling them to work independently without waiting for each other. + +Wikipedia says + +> Message-oriented middleware is software or hardware infrastructure supporting sending and receiving messages between distributed systems. MOM allows application modules to be distributed over heterogeneous platforms and reduces the complexity of developing applications that span multiple operating systems and network protocols. + +Flowchart + +![Microservices Messaging flowchart](./etc/microservices-messaging-flowchart.png) + + + +## Programmatic Example of Microservices Messaging Pattern in Java + + +The Microservices Messaging pattern demonstrates how services communicate through a message broker without direct coupling. In this example, we show an order processing system where services exchange messages asynchronously. + +The `Message` class represents the data exchanged between services. + +```java +public class Message { + private final String id; + private final String content; + private final LocalDateTime timestamp; + + public Message(String content) { + this.id = UUID.randomUUID().toString(); + this.content = content; + this.timestamp = LocalDateTime.now(); + } + + // Getters +} +``` + +The `MessageBroker` acts as the intermediary that routes messages between producers and consumers. + +```java +public class MessageBroker { + private final Map subscribers = new ConcurrentHashMap<>(); + + public void subscribe(String topic, Consumer handler) { + subscribers.computeIfAbsent(topic, k -> new ArrayList<>()).add(handler); + } + + public void publish(String topic, Message message) { + List handlers = subscribers.get(topic); + if (handlers != null) { + handlers.forEach(handler -> handler.accept(message)); + } + } +} +``` + +The `OrderService` is a message producer that publishes order messages. + +```java +public class OrderService { + private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class); + private final MessageBroker broker; + + public OrderService(MessageBroker broker) { + this.broker = broker; + } + + public void createOrder(String orderId) { + Message message = new Message("Order Created: " + orderId); + broker.publish("order-topic", message); + LOGGER.info("Published order message: {}", orderId); + } +} +``` + +The `InventoryService` is a message consumer that processes inventory updates. + +```java +public class InventoryService { + private static final Logger LOGGER = LoggerFactory.getLogger(InventoryService.class); + + public void handleMessage(Message message) { + LOGGER.info("Inventory Service received: {}", message.getContent()); + LOGGER.info("Updating inventory..."); + } +} +``` + +The `PaymentService` handles payment processing messages. + +```java +public class PaymentService { + private static final Logger LOGGER = LoggerFactory.getLogger(PaymentService.class); + + public void handleMessage(Message message) { + LOGGER.info("Payment Service received: {}", message.getContent()); + LOGGER.info("Processing payment..."); + } +} +``` + +The `main` application demonstrates the messaging pattern in action. + +```java +public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + public static void main(String[] args) throws InterruptedException { + final MessageBroker broker = new MessageBroker(); + + final InventoryService inventoryService = new InventoryService(); + final PaymentService paymentService = new PaymentService(); + + broker.subscribe("order-topic", inventoryService::handleMessage); + broker.subscribe("order-topic", paymentService::handleMessage); + + final OrderService orderService = new OrderService(broker); + + orderService.createOrder("ORDER-123"); + + Thread.sleep(1000); + } +} +``` + +Console output: + +``` +Published order message: ORDER-123 +Inventory Service received: Order Created: ORDER-123 +Updating inventory... +Payment Service received: Order Created: ORDER-123 +Processing payment... +``` + +Sequence Diagram + +![Microservices Messaging sequence_diagram](./etc/microservices-messaging-sequence-diagram.png) + +## How to Run the Application + +### Option 1: Automated Script (Recommended) + +Run the helper script from the module directory, which automatically starts Kafka via Docker Compose (if Docker is installed and Kafka is not already running) and launches the application: + +* **Windows (PowerShell)**: + ```powershell + powershell -ExecutionPolicy Bypass -File .\run-app.ps1 + ``` +* **Linux / macOS**: + ```bash + ./run-app.sh + ``` + +### Option 2: Docker Compose + +Start the Kafka container manually via Docker Compose and run the application: + +```bash +# Start Kafka container on port 9092 +docker compose up -d + +# Run the application +../mvnw compile exec:java -Dexec.mainClass="com.iluwatar.messaging.App" + +# Stop Kafka container when finished +docker compose down +``` + +## When to Use the Microservices Messaging Pattern in Java + +* When services need to communicate without blocking each other. +* In systems requiring loose coupling between components. +* For event-driven architectures where multiple services react to events. +* When you need to handle traffic spikes by buffering messages. +* In distributed systems where services may be temporarily unavailable. + +## Real-World Applications of Microservices Messaging Pattern in Java + +* Java applications using Apache Kafka, RabbitMQ, or ActiveMQ for service communication. +* E-commerce platforms for order processing and inventory management. +* Financial services for transaction processing and notifications. +* IoT systems for sensor data processing and event handling. + +## Benefits and Trade-offs of Microservices Messaging Pattern + +* Services are loosely coupled and can be developed and deployed independently. +* Message buffering improves system resilience when services are temporarily unavailable. +* Supports multiple communication patterns like publish/subscribe and request/reply. +* Enhances scalability by allowing parallel message processing. +* Natural support for event-driven architectures. + +Trade-offs: + +* Introduces additional complexity with the message broker infrastructure. +* Requires high availability setup for the message broker. +* Eventual consistency instead of immediate consistency. +* Debugging asynchronous flows is more complex than synchronous calls. +* Need to handle message duplication and ensure idempotent consumers. + +## Related Java Design Patterns + +* [Saga Pattern](https://java-design-patterns.com/patterns/saga/): Uses messaging to coordinate distributed transactions. +* [CQRS Pattern](https://java-design-patterns.com/patterns/cqrs/): Often uses messaging to separate read and write operations. +* [Event Sourcing](https://java-design-patterns.com/patterns/event-sourcing/): Stores state changes as messages. +* [API Gateway](https://java-design-patterns.com/patterns/microservices-api-gateway/): Complements messaging for synchronous requests. + +## References and Credits + +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://amzn.to/3vLKqET) +* [Microservices Patterns: With examples in Java](https://amzn.to/3UyWD5O) +* [Building Event-Driven Microservices: Leveraging Organizational Data at Scale](https://amzn.to/3PihS9R) +* [Pattern: Messaging (microservices.io)](https://microservices.io/patterns/communication-style/messaging.html) +* [Apache Kafka Documentation](https://kafka.apache.org/documentation/) \ No newline at end of file diff --git a/microservices-messaging/docker-compose.yml b/microservices-messaging/docker-compose.yml new file mode 100644 index 000000000000..b77ee549cd51 --- /dev/null +++ b/microservices-messaging/docker-compose.yml @@ -0,0 +1,53 @@ +# +# This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). +# +# The MIT License +# Copyright © 2014-2022 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +version: '3.8' + +services: + kafka: + image: confluentinc/cp-kafka:7.5.0 + container_name: kafka-messaging-demo + ports: + - "9092:9092" + environment: + KAFKA_NODE_ID: 1 + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT' + KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092' + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 + KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 + KAFKA_PROCESS_ROLES: 'broker,controller' + KAFKA_CONTROLLER_QUORUM_VOTERS: '1@kafka:29093' + KAFKA_LISTENERS: 'PLAINTEXT://kafka:29092,CONTROLLER://kafka:29093,PLAINTEXT_HOST://0.0.0.0:9092' + KAFKA_INTER_BROKER_LISTENER_NAME: 'PLAINTEXT' + KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER' + KAFKA_LOG_DIRS: '/tmp/kraft-combined-logs' + CLUSTER_ID: 'MkU3OEVBNTcwNTJENDM2Qk' + healthcheck: + test: ["CMD-SHELL", "kafka-topics --bootstrap-server localhost:9092 --list"] + interval: 5s + timeout: 10s + retries: 5 diff --git a/microservices-messaging/etc/microservices-messaging-flowchart.png b/microservices-messaging/etc/microservices-messaging-flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..dd26a2e2ce4a18ac78fd58b5416a281751c8b158 GIT binary patch literal 115287 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

t}_!7tr*|K~msWPhxZNN~?V7TB;^a^+@;y4v! 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�Z()2f;RygBed`KpV*1L<*uDj_}p}_@_!jN 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

JD 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 m^>s}JQZIOdaN`~LvJ`+9)@ literal 0 HcmV?d00001 diff --git a/microservices-messaging/pom.xml b/microservices-messaging/pom.xml new file mode 100644 index 000000000000..8fb9d59c4f74 --- /dev/null +++ b/microservices-messaging/pom.xml @@ -0,0 +1,118 @@ + + + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + microservices-messaging + 1.26.0-SNAPSHOT + + + 3.6.1 + + + + + + org.apache.kafka + kafka-clients + ${kafka.version} + + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + + com.fasterxml.jackson.core + jackson-databind + 2.16.1 + + + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.19.2 + compile + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.messaging.App + + + + + + + + + \ No newline at end of file diff --git a/microservices-messaging/run-app.ps1 b/microservices-messaging/run-app.ps1 new file mode 100644 index 000000000000..6fd4da50dfbe --- /dev/null +++ b/microservices-messaging/run-app.ps1 @@ -0,0 +1,89 @@ +# +# This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). +# +# The MIT License +# Copyright © 2014-2022 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +# PowerShell script to start Kafka container (if Docker is available) and run the Microservices Messaging App + +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition +Set-Location $ScriptDir + +Write-Host "======================================================" -ForegroundColor Cyan +Write-Host " Starting Microservices Messaging Pattern Application" -ForegroundColor Cyan +Write-Host "======================================================" -ForegroundColor Cyan + +# Check if Kafka is already running on port 9092 +$portActive = $false +try { + $socket = New-Object System.Net.Sockets.TcpClient("localhost", 9092) + if ($socket.Connected) { + $portActive = $true + $socket.Close() + } +} catch { + $portActive = $false +} + +if ($portActive) { + Write-Host "[INFO] Kafka is already running on port 9092." -ForegroundColor Green +} else { + # Check if Docker is available, or add Docker Desktop to PATH + if (-not (Get-Command docker -ErrorAction SilentlyContinue)) { + $dockerPath = "$env:LOCALAPPDATA\Programs\DockerDesktop\resources\bin" + if (Test-Path $dockerPath) { + $env:PATH += ";$dockerPath" + } + } + $dockerCmd = Get-Command docker -ErrorAction SilentlyContinue + if ($dockerCmd) { + Write-Host "[INFO] Starting Kafka container via Docker Compose..." -ForegroundColor Yellow + docker compose up -d + + Write-Host "[INFO] Waiting for Kafka to become ready on port 9092..." -ForegroundColor Yellow + $retryCount = 0 + while (-not $portActive -and $retryCount -lt 20) { + Start-Sleep -Seconds 2 + try { + $socket = New-Object System.Net.Sockets.TcpClient("localhost", 9092) + if ($socket.Connected) { + $portActive = $true + $socket.Close() + } + } catch { + $retryCount++ + } + } + + if ($portActive) { + Write-Host "[INFO] Kafka container started successfully!" -ForegroundColor Green + } else { + Write-Host "[WARNING] Kafka did not become ready on port 9092 within timeout." -ForegroundColor Red + } + } else { + Write-Host "[WARNING] Docker is not installed or not in PATH." -ForegroundColor Yellow + Write-Host "[INFO] Please ensure Kafka is running locally on localhost:9092 before running the app." -ForegroundColor Yellow + } +} + +Write-Host "[INFO] Compiling and running App.java..." -ForegroundColor Cyan +& "..\mvnw.cmd" compile exec:java "-Dexec.mainClass=com.iluwatar.messaging.App" diff --git a/microservices-messaging/run-app.sh b/microservices-messaging/run-app.sh new file mode 100644 index 000000000000..8c31c185190e --- /dev/null +++ b/microservices-messaging/run-app.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# +# This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). +# +# The MIT License +# Copyright © 2014-2022 Ilkka Seppälä +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +# Shell script to start Kafka container (if Docker is available) and run the Microservices Messaging App + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +echo "======================================================" +echo " Starting Microservices Messaging Pattern Application" +echo "======================================================" + +if nc -z localhost 9092 2>/dev/null || (echo > /dev/tcp/localhost/9092) 2>/dev/null; then + echo "[INFO] Kafka is already running on port 9092." +else + if command -v docker &> /dev/null; then + echo "[INFO] Starting Kafka container via Docker Compose..." + docker compose up -d + + echo "[INFO] Waiting for Kafka to become ready on port 9092..." + retry=0 + until nc -z localhost 9092 2>/dev/null || (echo > /dev/tcp/localhost/9092) 2>/dev/null || [ $retry -eq 20 ]; do + sleep 2 + retry=$((retry+1)) + done + + if [ $retry -lt 20 ]; then + echo "[INFO] Kafka container started successfully!" + else + echo "[WARNING] Kafka did not become ready on port 9092 within timeout." + fi + else + echo "[WARNING] Docker is not installed or not in PATH." + echo "[INFO] Please ensure Kafka is running locally on localhost:9092." + fi +fi + +echo "[INFO] Compiling and running App.java..." +../mvnw compile exec:java -Dexec.mainClass="com.iluwatar.messaging.App" diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/App.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/App.java new file mode 100644 index 000000000000..73c47c5ef1cf --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/App.java @@ -0,0 +1,161 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Microservices Messaging pattern enables asynchronous communication between services through + * Apache Kafka. This example demonstrates how services can communicate without tight coupling. + * + *

In this example: + * + *

+ * + *

Key benefits demonstrated: + * + *

    + *
  • Loose coupling - services don't directly depend on each other + *
  • Asynchronous processing - producers don't wait for consumers + *
  • Scalability - multiple consumers can process messages independently + *
  • Resilience - if one consumer fails, others continue processing + *
  • Message persistence - Kafka stores messages for reliability + *
+ * + *

Prerequisites: This example requires a running Kafka instance. Start Kafka locally: + * + *

+ * # Start Zookeeper
+ * bin/zookeeper-server-start.sh config/zookeeper.properties
+ *
+ * # Start Kafka
+ * bin/kafka-server-start.sh config/server.properties
+ *
+ * # Create topic
+ * bin/kafka-topics.sh --create --topic order-topic --bootstrap-server localhost:9092
+ * 
+ */ +public class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + private static final String BOOTSTRAP_SERVERS = "localhost:9092"; + + /** Sleep duration between operations in milliseconds. Package-private for testing. */ + static long sleepMs = 2000; + + /** + * Program entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) throws InterruptedException { + KafkaMessageProducer producer = new KafkaMessageProducer(BOOTSTRAP_SERVERS); + + InventoryService inventoryService = new InventoryService(); + PaymentService paymentService = new PaymentService(); + NotificationService notificationService = new NotificationService(); + + KafkaMessageConsumer inventoryConsumer = + new KafkaMessageConsumer( + BOOTSTRAP_SERVERS, "inventory-group", "order-topic", inventoryService::handleMessage); + + KafkaMessageConsumer paymentConsumer = + new KafkaMessageConsumer( + BOOTSTRAP_SERVERS, "payment-group", "order-topic", paymentService::handleMessage); + + KafkaMessageConsumer notificationConsumer = + new KafkaMessageConsumer( + BOOTSTRAP_SERVERS, + "notification-group", + "order-topic", + notificationService::handleMessage); + + run(producer, inventoryConsumer, paymentConsumer, notificationConsumer); + } + + /** + * Runs the Microservices Messaging Pattern demonstration. + * + * @param producer the Kafka message producer + * @param inventoryConsumer the inventory service consumer + * @param paymentConsumer the payment service consumer + * @param notificationConsumer the notification service consumer + */ + static void run( + KafkaMessageProducer producer, + KafkaMessageConsumer inventoryConsumer, + KafkaMessageConsumer paymentConsumer, + KafkaMessageConsumer notificationConsumer) + throws InterruptedException { + LOGGER.info("Starting Microservices Messaging Pattern with Apache Kafka"); + + // Start consumers in separate threads + ExecutorService executor = Executors.newFixedThreadPool(3); + executor.submit(inventoryConsumer); + executor.submit(paymentConsumer); + executor.submit(notificationConsumer); + + // Give consumers time to subscribe + Thread.sleep(sleepMs); + + // Create producer service + OrderService orderService = new OrderService(producer); + + // Demonstrate the messaging pattern + LOGGER.info("\n=== Creating Order ==="); + orderService.createOrder("ORDER-001"); + + Thread.sleep(sleepMs); + + LOGGER.info("\n=== Updating Order ==="); + orderService.updateOrder("ORDER-001"); + + Thread.sleep(sleepMs); + + LOGGER.info("\n=== Cancelling Order ==="); + orderService.cancelOrder("ORDER-001"); + + Thread.sleep(sleepMs); + + // Cleanup + LOGGER.info("\nShutting down..."); + inventoryConsumer.stop(); + paymentConsumer.stop(); + notificationConsumer.stop(); + producer.close(); + + executor.shutdown(); + executor.awaitTermination(5, TimeUnit.SECONDS); + + LOGGER.info("Microservices Messaging Pattern demonstration completed"); + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/InventoryService.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/InventoryService.java new file mode 100644 index 000000000000..9552e867d1ee --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/InventoryService.java @@ -0,0 +1,86 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * InventoryService is a message consumer that processes inventory-related messages from Kafka. It + * listens to order events and updates inventory accordingly. + * + *

This service runs in its own Kafka consumer group (inventory-group) which allows it to: + * + *

    + *
  • Process messages independently from other services + *
  • Scale horizontally by adding more instances to the consumer group + *
  • Resume from last committed offset if the service restarts + *
+ */ +public class InventoryService { + private static final Logger LOGGER = LoggerFactory.getLogger(InventoryService.class); + + /** + * Handles incoming messages related to orders from Kafka. + * + * @param message the message to process + */ + public void handleMessage(Message message) { + LOGGER.info( + "Inventory Service received message [{}]: {}", message.getId(), message.getContent()); + + if (message.getContent().contains("Order Created")) { + updateInventory(message); + } else if (message.getContent().contains("Order Cancelled")) { + restoreInventory(message); + } else { + LOGGER.debug("No inventory action needed for: {}", message.getContent()); + } + } + + private void updateInventory(Message message) { + LOGGER.info("Updating inventory for message: {}", message.getId()); + // Simulate inventory update - reserve stock for the order + try { + Thread.sleep(100); + LOGGER.info("Inventory updated successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Inventory update interrupted", e); + } + } + + private void restoreInventory(Message message) { + LOGGER.info("Restoring inventory for message: {}", message.getId()); + // Simulate inventory restoration - release reserved stock + try { + Thread.sleep(100); + LOGGER.info("Inventory restored successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Inventory restore interrupted", e); + } + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageConsumer.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageConsumer.java new file mode 100644 index 000000000000..71130e114dd8 --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageConsumer.java @@ -0,0 +1,125 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.time.Duration; +import java.util.Collections; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.consumer.ConsumerConfig; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.KafkaConsumer; +import org.apache.kafka.common.serialization.StringDeserializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Kafka message consumer that subscribes to topics and processes messages. */ +public class KafkaMessageConsumer implements AutoCloseable, Runnable { + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaMessageConsumer.class); + private final Consumer consumer; + private final ObjectMapper objectMapper; + private final String topic; + private final java.util.function.Consumer messageHandler; + private final AtomicBoolean running = new AtomicBoolean(true); + + /** + * Creates a new Kafka message consumer. + * + * @param bootstrapServers Kafka bootstrap servers + * @param groupId consumer group ID + * @param topic topic to subscribe to + * @param messageHandler handler for received messages + */ + public KafkaMessageConsumer( + String bootstrapServers, + String groupId, + String topic, + java.util.function.Consumer messageHandler) { + this(createDefaultConsumer(bootstrapServers, groupId), topic, messageHandler); + } + + KafkaMessageConsumer( + Consumer consumer, + String topic, + java.util.function.Consumer messageHandler) { + this.consumer = consumer; + this.objectMapper = new ObjectMapper(); + this.objectMapper.registerModule(new JavaTimeModule()); + this.topic = topic; + this.messageHandler = messageHandler; + } + + private static Consumer createDefaultConsumer( + String bootstrapServers, String groupId) { + Properties props = new Properties(); + props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + props.put(ConsumerConfig.GROUP_ID_CONFIG, groupId); + props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName()); + props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); + props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); + return new KafkaConsumer<>(props); + } + + @Override + public void run() { + try { + consumer.subscribe(Collections.singletonList(topic)); + LOGGER.info("Consumer subscribed to topic: {}", topic); + + while (running.get()) { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + records.forEach( + record -> { + try { + Message message = objectMapper.readValue(record.value(), Message.class); + LOGGER.info("Received message from topic '{}': {}", topic, message.getId()); + messageHandler.accept(message); + } catch (Exception e) { + LOGGER.error("Error processing message: {}", e.getMessage(), e); + } + }); + } + } catch (Exception e) { + LOGGER.error("Consumer error: {}", e.getMessage(), e); + } finally { + consumer.close(); + LOGGER.info("Consumer closed for topic: {}", topic); + } + } + + /** Stops the consumer. */ + public void stop() { + running.set(false); + } + + @Override + public void close() { + stop(); + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageProducer.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageProducer.java new file mode 100644 index 000000000000..56154152c008 --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/KafkaMessageProducer.java @@ -0,0 +1,108 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.util.Properties; +import org.apache.kafka.clients.producer.KafkaProducer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerConfig; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.common.serialization.StringSerializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Kafka message producer that publishes messages to Kafka topics. */ +public class KafkaMessageProducer implements AutoCloseable { + private static final Logger LOGGER = LoggerFactory.getLogger(KafkaMessageProducer.class); + private final Producer producer; + private final ObjectMapper objectMapper; + + /** + * Creates a new Kafka message producer. + * + * @param bootstrapServers Kafka bootstrap servers + */ + public KafkaMessageProducer(String bootstrapServers) { + this(createDefaultProducer(bootstrapServers)); + } + + KafkaMessageProducer(Producer producer) { + this.producer = producer; + this.objectMapper = new ObjectMapper(); + this.objectMapper.registerModule(new JavaTimeModule()); + } + + private static Producer createDefaultProducer(String bootstrapServers) { + Properties props = new Properties(); + props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers); + props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); + props.put(ProducerConfig.ACKS_CONFIG, "all"); + props.put(ProducerConfig.RETRIES_CONFIG, 3); + return new KafkaProducer<>(props); + } + + /** + * Publishes a message to a Kafka topic. + * + * @param topic the topic to publish to + * @param message the message to publish + */ + public void publish(String topic, Message message) { + try { + String json = objectMapper.writeValueAsString(message); + ProducerRecord record = new ProducerRecord<>(topic, message.getId(), json); + + producer.send( + record, + (metadata, exception) -> { + if (exception != null) { + LOGGER.error( + "Failed to publish message to topic {}: {}", topic, exception.getMessage()); + } else { + LOGGER.info( + "Published message to topic '{}' [partition={}, offset={}]", + topic, + metadata.partition(), + metadata.offset()); + } + }); + + } catch (Exception e) { + LOGGER.error("Error serializing message: {}", e.getMessage(), e); + } + } + + @Override + public void close() { + if (producer != null) { + producer.flush(); + producer.close(); + LOGGER.info("Kafka producer closed"); + } + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/Message.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/Message.java new file mode 100644 index 000000000000..5d0e9f96769c --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/Message.java @@ -0,0 +1,75 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.time.LocalDateTime; +import java.util.UUID; +import lombok.Getter; + +/** Represents a message exchanged between services. */ +@Getter +public class Message { + private final String id; + private final String content; + private final LocalDateTime timestamp; + + /** + * Creates a new message with the given content. + * + * @param content the message content + */ + public Message(String content) { + this.id = UUID.randomUUID().toString(); + this.content = content; + this.timestamp = LocalDateTime.now(); + } + + /** JSON constructor for deserialization. */ + @JsonCreator + public Message( + @JsonProperty("id") String id, + @JsonProperty("content") String content, + @JsonProperty("timestamp") LocalDateTime timestamp) { + this.id = id; + this.content = content; + this.timestamp = timestamp; + } + + @Override + public String toString() { + return "Message{" + + "id='" + + id + + '\'' + + ", content='" + + content + + '\'' + + ", timestamp=" + + timestamp + + '}'; + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/NotificationService.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/NotificationService.java new file mode 100644 index 000000000000..461b1a326efb --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/NotificationService.java @@ -0,0 +1,100 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * NotificationService is a message consumer that processes notification-related messages from + * Kafka. It listens to order events and sends notifications to customers. + * + *

This service runs in its own Kafka consumer group (notification-group) which allows it to: + * + *

    + *
  • Process messages independently from other services + *
  • Scale horizontally by adding more instances to the consumer group + *
  • Resume from last committed offset if the service restarts + *
+ */ +public class NotificationService { + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationService.class); + + /** + * Handles incoming messages related to orders from Kafka. + * + * @param message the message to process + */ + public void handleMessage(Message message) { + LOGGER.info( + "Notification Service received message [{}]: {}", message.getId(), message.getContent()); + + if (message.getContent().contains("Order Created")) { + sendOrderConfirmation(message); + } else if (message.getContent().contains("Order Updated")) { + sendOrderUpdate(message); + } else if (message.getContent().contains("Order Cancelled")) { + sendCancellationNotice(message); + } else { + LOGGER.debug("No notification action needed for: {}", message.getContent()); + } + } + + private void sendOrderConfirmation(Message message) { + LOGGER.info("Sending order confirmation for message: {}", message.getId()); + // Simulate sending email/SMS notification to customer + try { + Thread.sleep(50); + LOGGER.info("Order confirmation sent successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Notification send interrupted", e); + } + } + + private void sendOrderUpdate(Message message) { + LOGGER.info("Sending order update notification for message: {}", message.getId()); + // Simulate sending update notification + try { + Thread.sleep(50); + LOGGER.info("Order update notification sent successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Notification send interrupted", e); + } + } + + private void sendCancellationNotice(Message message) { + LOGGER.info("Sending cancellation notice for message: {}", message.getId()); + // Simulate sending cancellation notification + try { + Thread.sleep(50); + LOGGER.info("Cancellation notice sent successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Notification send interrupted", e); + } + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/OrderService.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/OrderService.java new file mode 100644 index 000000000000..d059e4e3e0fd --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/OrderService.java @@ -0,0 +1,76 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** OrderService is a message producer that publishes order-related messages using Kafka. */ +public class OrderService { + private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class); + private static final String ORDER_TOPIC = "order-topic"; + + private final KafkaMessageProducer producer; + + public OrderService(KafkaMessageProducer producer) { + this.producer = producer; + } + + /** + * Creates an order and publishes a message to notify other services. + * + * @param orderId the ID of the order to create + */ + public void createOrder(String orderId) { + LOGGER.info("Creating order: {}", orderId); + Message message = new Message("Order Created: " + orderId); + producer.publish(ORDER_TOPIC, message); + LOGGER.info("Order creation message published for: {}", orderId); + } + + /** + * Updates an order and publishes a message to notify other services. + * + * @param orderId the ID of the order to update + */ + public void updateOrder(String orderId) { + LOGGER.info("Updating order: {}", orderId); + Message message = new Message("Order Updated: " + orderId); + producer.publish(ORDER_TOPIC, message); + LOGGER.info("Order update message published for: {}", orderId); + } + + /** + * Cancels an order and publishes a message to notify other services. + * + * @param orderId the ID of the order to cancel + */ + public void cancelOrder(String orderId) { + LOGGER.info("Cancelling order: {}", orderId); + Message message = new Message("Order Cancelled: " + orderId); + producer.publish(ORDER_TOPIC, message); + LOGGER.info("Order cancellation message published for: {}", orderId); + } +} diff --git a/microservices-messaging/src/main/java/com/iluwatar/messaging/PaymentService.java b/microservices-messaging/src/main/java/com/iluwatar/messaging/PaymentService.java new file mode 100644 index 000000000000..4c90897a6e8f --- /dev/null +++ b/microservices-messaging/src/main/java/com/iluwatar/messaging/PaymentService.java @@ -0,0 +1,85 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * PaymentService is a message consumer that processes payment-related messages from Kafka. It + * listens to order events and handles payment processing. + * + *

This service runs in its own Kafka consumer group (payment-group) which allows it to: + * + *

    + *
  • Process messages independently from other services + *
  • Scale horizontally by adding more instances to the consumer group + *
  • Resume from last committed offset if the service restarts + *
+ */ +public class PaymentService { + private static final Logger LOGGER = LoggerFactory.getLogger(PaymentService.class); + + /** + * Handles incoming messages related to orders from Kafka. + * + * @param message the message to process + */ + public void handleMessage(Message message) { + LOGGER.info("Payment Service received message [{}]: {}", message.getId(), message.getContent()); + + if (message.getContent().contains("Order Created")) { + processPayment(message); + } else if (message.getContent().contains("Order Cancelled")) { + refundPayment(message); + } else { + LOGGER.debug("No payment action needed for: {}", message.getContent()); + } + } + + private void processPayment(Message message) { + LOGGER.info("Processing payment for message: {}", message.getId()); + // Simulate payment processing - charge the customer + try { + Thread.sleep(150); + LOGGER.info("Payment processed successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Payment processing interrupted", e); + } + } + + private void refundPayment(Message message) { + LOGGER.info("Refunding payment for message: {}", message.getId()); + // Simulate payment refund - return money to customer + try { + Thread.sleep(150); + LOGGER.info("Payment refunded successfully for: {}", message.getContent()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Payment refund interrupted", e); + } + } +} diff --git a/microservices-messaging/src/main/resources/logback.xml b/microservices-messaging/src/main/resources/logback.xml new file mode 100644 index 000000000000..7f40741c0ff1 --- /dev/null +++ b/microservices-messaging/src/main/resources/logback.xml @@ -0,0 +1,40 @@ + + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + \ No newline at end of file diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/AppTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/AppTest.java new file mode 100644 index 000000000000..430b44812e66 --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/AppTest.java @@ -0,0 +1,85 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.consumer.OffsetResetStrategy; +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link App}. Tests main application entry point. */ +class AppTest { + + @BeforeEach + void setUp() { + // Speed up sleeps so tests finish instantly + App.sleepMs = 0; + } + + @AfterEach + void tearDown() { + // Restore default so other contexts are unaffected + App.sleepMs = 2000; + } + + @Test + void testAppConstructor() { + assertNotNull(new App(), "App should be instantiable"); + } + + @Test + void testRunWithMockObjects() { + // Build mock-backed producer and consumers — no Kafka broker required + MockProducer mockProducer = + new MockProducer<>(true, new StringSerializer(), new StringSerializer()); + KafkaMessageProducer producer = new KafkaMessageProducer(mockProducer); + + MockConsumer mc1 = new MockConsumer<>(OffsetResetStrategy.EARLIEST); + MockConsumer mc2 = new MockConsumer<>(OffsetResetStrategy.EARLIEST); + MockConsumer mc3 = new MockConsumer<>(OffsetResetStrategy.EARLIEST); + + KafkaMessageConsumer inventoryConsumer = + new KafkaMessageConsumer(mc1, "order-topic", msg -> {}); + KafkaMessageConsumer paymentConsumer = new KafkaMessageConsumer(mc2, "order-topic", msg -> {}); + KafkaMessageConsumer notificationConsumer = + new KafkaMessageConsumer(mc3, "order-topic", msg -> {}); + + // Stop consumers immediately so their poll loops exit right away in the executor threads + inventoryConsumer.stop(); + paymentConsumer.stop(); + notificationConsumer.stop(); + + // sleepMs == 0, so all Thread.sleep(sleepMs) return instantly — full run() coverage + assertDoesNotThrow( + () -> App.run(producer, inventoryConsumer, paymentConsumer, notificationConsumer), + "App.run() should complete without throwing"); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/InventoryServiceTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/InventoryServiceTest.java new file mode 100644 index 000000000000..bb0842ce7aef --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/InventoryServiceTest.java @@ -0,0 +1,118 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link InventoryService}. Tests service behavior with various message types + * without Kafka dependencies. + */ +class InventoryServiceTest { + + private InventoryService inventoryService; + + @BeforeEach + void setUp() { + inventoryService = new InventoryService(); + } + + @Test + void testServiceCanBeInstantiated() { + // Arrange & Act & Assert + assertNotNull(inventoryService, "InventoryService should be instantiated"); + } + + @Test + void testHandleOrderCreatedMessage() { + // Arrange + var message = new Message("Order Created: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> inventoryService.handleMessage(message), + "Should handle order created message without error"); + } + + @Test + void testHandleOrderCancelledMessage() { + // Arrange + var message = new Message("Order Cancelled: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> inventoryService.handleMessage(message), + "Should handle order cancelled message without error"); + } + + @Test + void testHandleOrderUpdatedMessage() { + // Arrange + var message = new Message("Order Updated: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> inventoryService.handleMessage(message), + "Should handle order updated message without error"); + } + + @Test + void testHandleUnknownMessage() { + // Arrange + var message = new Message("Unknown Event: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> inventoryService.handleMessage(message), + "Should handle unknown message without error"); + } + + @Test + void testHandleMultipleMessages() { + // Act & Assert + assertDoesNotThrow( + () -> { + inventoryService.handleMessage(new Message("Order Created: ORDER-001")); + inventoryService.handleMessage(new Message("Order Updated: ORDER-001")); + inventoryService.handleMessage(new Message("Order Cancelled: ORDER-001")); + }, + "Should handle multiple messages without error"); + } + + @Test + void testHandleMessagesWhenInterrupted() { + Thread.currentThread().interrupt(); + inventoryService.handleMessage(new Message("Order Created: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + + Thread.currentThread().interrupt(); + inventoryService.handleMessage(new Message("Order Cancelled: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageConsumerTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageConsumerTest.java new file mode 100644 index 000000000000..2977f7448c56 --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageConsumerTest.java @@ -0,0 +1,137 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.util.Collections; +import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.MockConsumer; +import org.apache.kafka.clients.consumer.OffsetResetStrategy; +import org.apache.kafka.common.TopicPartition; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link KafkaMessageConsumer}. */ +class KafkaMessageConsumerTest { + + private MockConsumer mockConsumer; + private KafkaMessageConsumer kafkaMessageConsumer; + private AtomicBoolean handlerCalled; + + @BeforeEach + void setUp() { + mockConsumer = new MockConsumer<>(OffsetResetStrategy.EARLIEST); + handlerCalled = new AtomicBoolean(false); + kafkaMessageConsumer = + new KafkaMessageConsumer(mockConsumer, "test-topic", msg -> handlerCalled.set(true)); + } + + @Test + void testConsumerCanBeInstantiated() { + assertNotNull(kafkaMessageConsumer, "KafkaMessageConsumer should be instantiated"); + } + + @Test + void testRunProcessesValidMessageAndStops() throws Exception { + ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); + Message msg = new Message("Order Created: 123"); + String jsonStr = mapper.writeValueAsString(msg); + + TopicPartition tp = new TopicPartition("test-topic", 0); + mockConsumer.updateBeginningOffsets( + new HashMap<>() { + { + put(tp, 0L); + } + }); + + mockConsumer.schedulePollTask( + () -> { + mockConsumer.rebalance(Collections.singletonList(tp)); + mockConsumer.addRecord(new ConsumerRecord<>("test-topic", 0, 0L, "key", jsonStr)); + }); + + mockConsumer.schedulePollTask(() -> kafkaMessageConsumer.stop()); + + kafkaMessageConsumer.run(); + + assertTrue(handlerCalled.get(), "Handler should have been invoked"); + assertTrue(mockConsumer.closed(), "Consumer should be closed"); + } + + @Test + void testRunHandlesInvalidJsonMessage() { + TopicPartition tp = new TopicPartition("test-topic", 0); + mockConsumer.updateBeginningOffsets( + new HashMap<>() { + { + put(tp, 0L); + } + }); + + mockConsumer.schedulePollTask( + () -> { + mockConsumer.rebalance(Collections.singletonList(tp)); + mockConsumer.addRecord(new ConsumerRecord<>("test-topic", 0, 0L, "key", "{invalid json")); + }); + + mockConsumer.schedulePollTask(() -> kafkaMessageConsumer.stop()); + + assertDoesNotThrow(() -> kafkaMessageConsumer.run()); + assertTrue(mockConsumer.closed(), "Consumer should be closed"); + } + + @Test + void testCloseStopsConsumer() { + assertDoesNotThrow(() -> kafkaMessageConsumer.close()); + } + + @Test + void testRunWhenAlreadyStopped() { + // Stop the consumer before run() so the while loop exits immediately + kafkaMessageConsumer.stop(); + + // run() should complete without processing any records + assertDoesNotThrow(() -> kafkaMessageConsumer.run()); + assertTrue(mockConsumer.closed(), "Consumer should be closed even when stopped before run"); + } + + @Test + void testRunHandlesConsumerException() { + // Schedule a WakeupException during poll to trigger the outer catch block + mockConsumer.schedulePollTask(() -> mockConsumer.wakeup()); + + // run() must not propagate the exception + assertDoesNotThrow(() -> kafkaMessageConsumer.run()); + assertTrue(mockConsumer.closed(), "Consumer should be closed after exception"); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageProducerTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageProducerTest.java new file mode 100644 index 000000000000..1257495813a3 --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/KafkaMessageProducerTest.java @@ -0,0 +1,93 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link KafkaMessageProducer}. */ +class KafkaMessageProducerTest { + + private MockProducer mockProducer; + private KafkaMessageProducer kafkaMessageProducer; + + @BeforeEach + void setUp() { + mockProducer = new MockProducer<>(true, new StringSerializer(), new StringSerializer()); + kafkaMessageProducer = new KafkaMessageProducer(mockProducer); + } + + @Test + void testProducerCanBeInstantiated() { + assertNotNull(kafkaMessageProducer, "KafkaMessageProducer should be instantiated"); + } + + @Test + void testPublishMessageSuccess() { + Message message = new Message("Test Order"); + + assertDoesNotThrow(() -> kafkaMessageProducer.publish("test-topic", message)); + assertEquals(1, mockProducer.history().size()); + assertEquals("test-topic", mockProducer.history().get(0).topic()); + assertEquals(message.getId(), mockProducer.history().get(0).key()); + } + + @Test + void testPublishMessageErrorCallback() { + MockProducer failingProducer = + new MockProducer<>(false, new StringSerializer(), new StringSerializer()); + KafkaMessageProducer producerWithError = new KafkaMessageProducer(failingProducer); + Message message = new Message("Test Order"); + + assertDoesNotThrow(() -> producerWithError.publish("test-topic", message)); + assertEquals(1, failingProducer.history().size()); + + // Trigger error callback BEFORE closing so the exception != null branch is covered + failingProducer.errorNext(new RuntimeException("Kafka publish error")); + + assertDoesNotThrow(() -> producerWithError.close()); + assertTrue(failingProducer.closed()); + } + + @Test + void testClose() { + assertDoesNotThrow(() -> kafkaMessageProducer.close()); + assertTrue(mockProducer.closed()); + } + + @Test + void testPublishNullMessageCatchesException() { + // Passing null causes message.getId() to throw NPE, which is caught by the + // catch(Exception e) block — covering the "Error serializing message" log branch. + assertDoesNotThrow(() -> kafkaMessageProducer.publish("test-topic", null)); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/MessageTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/MessageTest.java new file mode 100644 index 000000000000..d80cc2b806ca --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/MessageTest.java @@ -0,0 +1,165 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import java.time.LocalDateTime; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link Message}. Tests follow FIRST principles: Fast, Isolated, Repeatable, + * Self-validating, Timely. + */ +class MessageTest { + + private ObjectMapper objectMapper; + + @BeforeEach + void setUp() { + objectMapper = new ObjectMapper(); + objectMapper.registerModule(new JavaTimeModule()); + } + + @Test + void testMessageCreation() { + // Arrange & Act + var message = new Message("Test content"); + + // Assert + assertNotNull(message.getId(), "Message ID should not be null"); + assertEquals("Test content", message.getContent(), "Content should match"); + assertNotNull(message.getTimestamp(), "Timestamp should not be null"); + } + + @Test + void testMessageIdIsUnique() { + // Arrange & Act + var message1 = new Message("Content 1"); + var message2 = new Message("Content 2"); + + // Assert + assertNotEquals(message1.getId(), message2.getId(), "Each message should have unique ID"); + } + + @Test + void testMessageTimestamp() { + // Arrange + var beforeCreation = LocalDateTime.now(); + + // Act + var message = new Message("Test"); + var afterCreation = LocalDateTime.now(); + + // Assert + assertTrue( + message.getTimestamp().isAfter(beforeCreation.minusSeconds(1)) + && message.getTimestamp().isBefore(afterCreation.plusSeconds(1)), + "Timestamp should be close to creation time"); + } + + @Test + void testJsonSerialization() throws Exception { + // Arrange + var originalMessage = new Message("Test content"); + + // Act + var json = objectMapper.writeValueAsString(originalMessage); + + // Assert + assertNotNull(json, "JSON should not be null"); + assertTrue(json.contains("Test content"), "JSON should contain content"); + assertTrue(json.contains(originalMessage.getId()), "JSON should contain ID"); + } + + @Test + void testJsonDeserialization() throws Exception { + // Arrange + var originalMessage = new Message("Test content"); + var json = objectMapper.writeValueAsString(originalMessage); + + // Act + var deserializedMessage = objectMapper.readValue(json, Message.class); + + // Assert + assertNotNull(deserializedMessage, "Deserialized message should not be null"); + assertEquals(originalMessage.getId(), deserializedMessage.getId(), "IDs should match"); + assertEquals( + originalMessage.getContent(), deserializedMessage.getContent(), "Content should match"); + } + + @Test + void testToString() { + // Arrange + var message = new Message("Test content"); + + // Act + var result = message.toString(); + + // Assert + assertNotNull(result, "ToString should not return null"); + assertTrue(result.contains("Message{"), "ToString should contain class name"); + assertTrue(result.contains("Test content"), "ToString should contain content"); + assertTrue(result.contains(message.getId()), "ToString should contain ID"); + } + + @Test + void testMessageWithEmptyContent() { + // Arrange & Act + var message = new Message(""); + + // Assert + assertNotNull(message.getId(), "ID should be generated even for empty content"); + assertEquals("", message.getContent(), "Empty content should be preserved"); + } + + @Test + void testMessageWithNullContent() { + // Arrange & Act + var message = new Message(null); + + // Assert + assertNotNull(message.getId(), "ID should be generated even for null content"); + assertEquals(null, message.getContent(), "Null content should be preserved"); + } + + @Test + void testMessageWithSpecialCharacters() { + // Arrange + var specialContent = "Test with special chars: @#$%^&*()"; + + // Act + var message = new Message(specialContent); + + // Assert + assertEquals(specialContent, message.getContent(), "Special characters should be preserved"); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/NotificationServiceTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/NotificationServiceTest.java new file mode 100644 index 000000000000..142e59087b5c --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/NotificationServiceTest.java @@ -0,0 +1,134 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link NotificationService}. Tests service behavior with various message types + * without Kafka dependencies. + */ +class NotificationServiceTest { + + private NotificationService notificationService; + + @BeforeEach + void setUp() { + notificationService = new NotificationService(); + } + + @Test + void testServiceCanBeInstantiated() { + // Arrange & Act & Assert + assertNotNull(notificationService, "NotificationService should be instantiated"); + } + + @Test + void testHandleOrderCreatedMessage() { + // Arrange + var message = new Message("Order Created: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> notificationService.handleMessage(message), + "Should handle order created message without error"); + } + + @Test + void testHandleOrderUpdatedMessage() { + // Arrange + var message = new Message("Order Updated: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> notificationService.handleMessage(message), + "Should handle order updated message without error"); + } + + @Test + void testHandleOrderCancelledMessage() { + // Arrange + var message = new Message("Order Cancelled: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> notificationService.handleMessage(message), + "Should handle order cancelled message without error"); + } + + @Test + void testHandleUnknownMessage() { + // Arrange + var message = new Message("Unknown Event: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> notificationService.handleMessage(message), + "Should handle unknown message without error"); + } + + @Test + void testHandleAllMessageTypes() { + // Act & Assert + assertDoesNotThrow( + () -> { + notificationService.handleMessage(new Message("Order Created: ORDER-001")); + notificationService.handleMessage(new Message("Order Updated: ORDER-001")); + notificationService.handleMessage(new Message("Order Cancelled: ORDER-001")); + }, + "Should handle all message types without error"); + } + + @Test + void testHandleMultipleOrdersSequentially() { + // Act & Assert + assertDoesNotThrow( + () -> { + notificationService.handleMessage(new Message("Order Created: ORDER-001")); + notificationService.handleMessage(new Message("Order Created: ORDER-002")); + notificationService.handleMessage(new Message("Order Created: ORDER-003")); + }, + "Should handle multiple orders sequentially without error"); + } + + @Test + void testHandleMessagesWhenInterrupted() { + Thread.currentThread().interrupt(); + notificationService.handleMessage(new Message("Order Created: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + + Thread.currentThread().interrupt(); + notificationService.handleMessage(new Message("Order Updated: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + + Thread.currentThread().interrupt(); + notificationService.handleMessage(new Message("Order Cancelled: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/OrderServiceTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/OrderServiceTest.java new file mode 100644 index 000000000000..2b3f38584a20 --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/OrderServiceTest.java @@ -0,0 +1,109 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.kafka.clients.producer.MockProducer; +import org.apache.kafka.common.serialization.StringSerializer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link OrderService}. Tests follow Arrange-Act-Assert pattern. */ +class OrderServiceTest { + + private MockProducer mockKafkaProducer; + private KafkaMessageProducer messageProducer; + private OrderService orderService; + + @BeforeEach + void setUp() { + mockKafkaProducer = new MockProducer<>(true, new StringSerializer(), new StringSerializer()); + messageProducer = new KafkaMessageProducer(mockKafkaProducer); + orderService = new OrderService(messageProducer); + } + + @Test + void testCreateOrder() { + // Arrange + var orderId = "ORDER-001"; + + // Act + assertDoesNotThrow(() -> orderService.createOrder(orderId)); + + // Assert + assertEquals(1, mockKafkaProducer.history().size()); + } + + @Test + void testUpdateOrder() { + // Arrange + var orderId = "ORDER-002"; + + // Act + assertDoesNotThrow(() -> orderService.updateOrder(orderId)); + + // Assert + assertEquals(1, mockKafkaProducer.history().size()); + } + + @Test + void testCancelOrder() { + // Arrange + var orderId = "ORDER-003"; + + // Act + assertDoesNotThrow(() -> orderService.cancelOrder(orderId)); + + // Assert + assertEquals(1, mockKafkaProducer.history().size()); + } + + @Test + void testMultipleOrderOperations() { + // Arrange + var orderId = "ORDER-004"; + + // Act + orderService.createOrder(orderId); + orderService.updateOrder(orderId); + orderService.cancelOrder(orderId); + + // Assert + assertEquals(3, mockKafkaProducer.history().size()); + } + + @Test + void testCreateOrderWithDifferentIds() { + // Act + orderService.createOrder("ORDER-001"); + orderService.createOrder("ORDER-002"); + orderService.createOrder("ORDER-003"); + + // Assert + assertEquals(3, mockKafkaProducer.history().size()); + } +} diff --git a/microservices-messaging/src/test/java/com/iluwatar/messaging/PaymentServiceTest.java b/microservices-messaging/src/test/java/com/iluwatar/messaging/PaymentServiceTest.java new file mode 100644 index 000000000000..608a64549c87 --- /dev/null +++ b/microservices-messaging/src/test/java/com/iluwatar/messaging/PaymentServiceTest.java @@ -0,0 +1,116 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.messaging; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for {@link PaymentService}. Tests service behavior with various message types without + * Kafka dependencies. + */ +class PaymentServiceTest { + + private PaymentService paymentService; + + @BeforeEach + void setUp() { + paymentService = new PaymentService(); + } + + @Test + void testServiceCanBeInstantiated() { + // Arrange & Act & Assert + assertNotNull(paymentService, "PaymentService should be instantiated"); + } + + @Test + void testHandleOrderCreatedMessage() { + // Arrange + var message = new Message("Order Created: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> paymentService.handleMessage(message), + "Should handle order created message without error"); + } + + @Test + void testHandleOrderCancelledMessage() { + // Arrange + var message = new Message("Order Cancelled: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> paymentService.handleMessage(message), + "Should handle order cancelled message without error"); + } + + @Test + void testHandleOrderUpdatedMessage() { + // Arrange + var message = new Message("Order Updated: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> paymentService.handleMessage(message), + "Should handle order updated message without error"); + } + + @Test + void testHandleUnknownMessage() { + // Arrange + var message = new Message("Unknown Event: ORDER-001"); + + // Act & Assert + assertDoesNotThrow( + () -> paymentService.handleMessage(message), "Should handle unknown message without error"); + } + + @Test + void testHandleMultipleMessages() { + // Act & Assert + assertDoesNotThrow( + () -> { + paymentService.handleMessage(new Message("Order Created: ORDER-001")); + paymentService.handleMessage(new Message("Order Cancelled: ORDER-001")); + }, + "Should handle multiple messages without error"); + } + + @Test + void testHandleMessagesWhenInterrupted() { + Thread.currentThread().interrupt(); + paymentService.handleMessage(new Message("Order Created: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + + Thread.currentThread().interrupt(); + paymentService.handleMessage(new Message("Order Cancelled: ORDER-001")); + org.junit.jupiter.api.Assertions.assertTrue(Thread.interrupted()); + } +} diff --git a/pom.xml b/pom.xml index 16590b9c34a7..46cec4ee61c4 100644 --- a/pom.xml +++ b/pom.xml @@ -170,6 +170,7 @@ microservices-idempotent-consumer microservices-log-aggregation microservices-self-registration + microservices-messaging model-view-controller model-view-intent model-view-presenter @@ -453,6 +454,7 @@ src/test/resources/** src/main/resources/** checkstyle-suppressions.xml + **/*.ps1 From 8b079dba5ca9e66a810378592410108709eb1d3e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 22:13:01 +0300 Subject: [PATCH 16/17] docs: add Mukul-Howale as a contributor for code (#3572) * docs: update README.md [skip ci] * docs: update .all-contributorsrc [skip ci] --------- Co-authored-by: allcontributors[bot] <46447321+allcontributors[bot]@users.noreply.github.com> --- .all-contributorsrc | 9 +++++++++ README.md | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 2410c6aecc03..df0e170f068f 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3764,6 +3764,15 @@ "contributions": [ "code" ] + }, + { + "login": "Mukul-Howale", + "name": "Mukul Howale", + "avatar_url": "https://avatars.githubusercontent.com/u/110479646?v=4", + "profile": "https://github.com/Mukul-Howale", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index f49aaa4b6422..f0e461c0fb76 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-413-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-414-orange.svg?style=flat-square)](#contributors-)
@@ -611,6 +611,7 @@ This project is licensed under the terms of the MIT license.
Arnab Nandy
Arnab Nandy

📖 BAGHDAD Mohamed
BAGHDAD Mohamed

💻 Anvesh Srivastava
Anvesh Srivastava

💻 + Mukul Howale
Mukul Howale

💻 From 22a34127d0b08449c24cf7e230c04a097deca2f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 22:16:49 +0300 Subject: [PATCH 17/17] build(deps): bump com.fasterxml.jackson.core:jackson-databind (#3567) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.22.0 to 2.22.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.22.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dynamic-proxy/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dynamic-proxy/pom.xml b/dynamic-proxy/pom.xml index eb5bc5c7e06d..bf5250998c53 100644 --- a/dynamic-proxy/pom.xml +++ b/dynamic-proxy/pom.xml @@ -51,7 +51,7 @@ com.fasterxml.jackson.core jackson-databind - 2.22.0 + 2.22.1 org.springframework