From d80eca177b2fada0f31a1e3350663096f3076cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 16 Apr 2025 21:31:31 +0300 Subject: [PATCH 001/108] docs: update book link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 881563902e26..a52d7f3f1fed 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ If you are willing to contribute to the project you will find the relevant infor # The Book -The design patterns are now available as an e-book. Find out more about "Open Source Java Design Patterns" here: https://payhip.com/b/kcaF9 +The design patterns are now available as an e-book. Find out more about "Open Source Java Design Patterns" here: https://payhip.com/b/bNQFX The project contributors can get the book for free. Contact the maintainer via [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns) or email (iluwatar (at) gmail (dot) com ). Send a message that contains your email address, Github username, and a link to an accepted pull request. From 1cde704bcbf7029e28bd8f671ac53943fe6ec6f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 22 Apr 2025 07:56:11 +0300 Subject: [PATCH 002/108] docs: remove some old diagrams --- data-access-object/README.md | 4 ---- data-locality/README.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/data-access-object/README.md b/data-access-object/README.md index bd020252d253..7e84299e23e1 100644 --- a/data-access-object/README.md +++ b/data-access-object/README.md @@ -199,10 +199,6 @@ The program output: 10:02:09.898 [main] INFO com.iluwatar.dao.App -- customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@f2f2cc1 ``` -## Detailed Explanation of Data Access Object Pattern with Real-World Examples - -![Data Access Object](./etc/dao.png "Data Access Object") - ## When to Use the Data Access Object Pattern in Java Use the Data Access Object in any of the following situations: diff --git a/data-locality/README.md b/data-locality/README.md index e9f556b8ad5c..a59103b3f89b 100644 --- a/data-locality/README.md +++ b/data-locality/README.md @@ -128,10 +128,6 @@ The console output: In this way, the data-locality module demonstrates the Data Locality pattern. By updating all components of the same type together, it increases the likelihood that the data needed for the update is already in the cache, thereby improving performance. -## Detailed Explanation of Data Locality Pattern with Real-World Examples - -![Data Locality](./etc/data-locality.urm.png "Data Locality pattern class diagram") - ## When to Use the Data Locality Pattern in Java This pattern is applicable in scenarios where large datasets are processed and performance is critical. It's particularly useful in: From fe522fd70d050494d197d3c4aa443aedef4aae1a Mon Sep 17 00:00:00 2001 From: ssrijan-007-sys <137605821+ssrijan-007-sys@users.noreply.github.com> Date: Tue, 22 Apr 2025 23:59:58 +0530 Subject: [PATCH 003/108] feat: Implement Actor Model pattern * feat: Implement Actor Model pattern #3232 * feat: Implement Actor Model pattern #3232 * feat: update Actor Model implementation with multi-actor logic #3251 * feat: update Actor Model implementation with multi-actor logic and loose coupling #3251 * test: add unit test for actor model #3251 * test: add test for App.java to increase coverage * docs: add complete README for Actor Model pattern also implemented changes #3251 --- actor-model/README.md | 201 ++++++++++++++++++ .../etc/Actor_Model_UML_Class_Diagram.png | Bin 0 -> 47298 bytes actor-model/etc/actor-model.urm.puml | 35 +++ actor-model/pom.xml | 114 ++++++++++ .../java/com/iluwatar/actormodel/Actor.java | 63 ++++++ .../com/iluwatar/actormodel/ActorSystem.java | 51 +++++ .../java/com/iluwatar/actormodel/App.java | 64 ++++++ .../com/iluwatar/actormodel/ExampleActor.java | 53 +++++ .../iluwatar/actormodel/ExampleActor2.java | 46 ++++ .../java/com/iluwatar/actormodel/Message.java | 35 +++ .../com/iluwatar/actor/ActorModelTest.java | 63 ++++++ pom.xml | 3 + 12 files changed, 728 insertions(+) create mode 100644 actor-model/README.md create mode 100644 actor-model/etc/Actor_Model_UML_Class_Diagram.png create mode 100644 actor-model/etc/actor-model.urm.puml create mode 100644 actor-model/pom.xml create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/Actor.java create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/ActorSystem.java create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/App.java create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor.java create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor2.java create mode 100644 actor-model/src/main/java/com/iluwatar/actormodel/Message.java create mode 100644 actor-model/src/test/java/com/iluwatar/actor/ActorModelTest.java diff --git a/actor-model/README.md b/actor-model/README.md new file mode 100644 index 000000000000..be8065ffefef --- /dev/null +++ b/actor-model/README.md @@ -0,0 +1,201 @@ +--- +title: "Actor Model Pattern in Java: Building Concurrent Systems with Elegance" +shortTitle: Actor Model +description: "Explore the Actor Model pattern in Java with real-world examples and practical implementation. Learn how to build scalable, message-driven systems using actors, messages, and asynchronous communication." +category: Concurrency +language: en +tag: + - Concurrency + - Messaging + - Isolation + - Asynchronous + - Distributed Systems + - Actor Model +--- + +## Also Known As + +- Message-passing concurrency +- Actor-based concurrency + +--- + +## Intent of Actor Model Pattern + +The Actor Model pattern enables the construction of highly concurrent, distributed, and fault-tolerant systems by using isolated components (actors) that interact exclusively through asynchronous message passing. + +--- + +## Detailed Explanation of Actor Model Pattern with Real-World Examples + +### 📦 Real-world Example + +Imagine a customer service system: +- Each **customer support agent** is an **actor**. +- Customers **send questions (messages)** to agents. +- Each agent handles one request at a time and can **respond asynchronously** without interfering with other agents. + +--- + +### 🧠 In Plain Words + +> "Actors are like independent workers that never share memory and only communicate through messages." + +--- + +### 📖 Wikipedia Says + +> [Actor model](https://en.wikipedia.org/wiki/Actor_model) is a mathematical model of concurrent computation that treats "actors" as the universal primitives of concurrent computation. + +--- + +### 🧹 Architecture Diagram + +![UML Class Diagram](./etc/Actor_Model_UML_Class_Diagram.png) + +--- + +## Programmatic Example of Actor Model Pattern in Java + +### Actor.java + +```java +public abstract class Actor implements Runnable { + + @Setter @Getter private String actorId; + private final BlockingQueue mailbox = new LinkedBlockingQueue<>(); + private volatile boolean active = true; + + + public void send(Message message) { + mailbox.add(message); + } + + public void stop() { + active = false; + } + + @Override + public void run() { + + } + + protected abstract void onReceive(Message message); +} + +``` + +### Message.java + +```java + +@AllArgsConstructor +@Getter +@Setter +public class Message { + private final String content; + private final String senderId; +} +``` + +### ActorSystem.java + +```java +public class ActorSystem { + public void startActor(Actor actor) { + String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID + actor.setActorId(actorId); // assign the actor it's ID + actorRegister.put(actorId, actor); // Register and save the actor with it's ID + executor.submit(actor); // Run the actor in a thread + } + public Actor getActorById(String actorId) { + return actorRegister.get(actorId); // Find by Id + } + + public void shutdown() { + executor.shutdownNow(); // Stop all threads + } +} +``` + +### App.java + +```java +public class App { + public static void main(String[] args) { + ActorSystem system = new ActorSystem(); + Actor srijan = new ExampleActor(system); + Actor ansh = new ExampleActor2(system); + + system.startActor(srijan); + system.startActor(ansh); + ansh.send(new Message("Hello ansh", srijan.getActorId())); + srijan.send(new Message("Hello srijan!", ansh.getActorId())); + + Thread.sleep(1000); // Give time for messages to process + + srijan.stop(); // Stop the actor gracefully + ansh.stop(); + system.shutdown(); // Stop the actor system + } +} +``` + +--- + +## When to Use the Actor Model Pattern in Java + +- When building **concurrent or distributed systems** +- When you want **no shared mutable state** +- When you need **asynchronous, message-driven communication** +- When components should be **isolated and loosely coupled** + +--- + +## Actor Model Pattern Java Tutorials + +- [Baeldung – Akka with Java](https://www.baeldung.com/java-akka) +- [Vaughn Vernon – Reactive Messaging Patterns](https://vaughnvernon.co/?p=1143) + +--- + +## Real-World Applications of Actor Model Pattern in Java + +- [Akka Framework](https://akka.io/) +- [Erlang and Elixir concurrency](https://www.erlang.org/) +- [Microsoft Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/) +- JVM-based game engines and simulators + +--- + +## Benefits and Trade-offs of Actor Model Pattern + +### ✅ Benefits +- High concurrency support +- Easy scaling across threads or machines +- Fault isolation and recovery +- Message ordering within actors + +### ⚠️ Trade-offs +- Harder to debug due to asynchronous behavior +- Slight performance overhead due to message queues +- More complex to design than simple method calls + +--- + +## Related Java Design Patterns + +- [Command Pattern](../command) +- [Mediator Pattern](../mediator) +- [Event-Driven Architecture](../event-driven-architecture) +- [Observer Pattern](../observer) + +--- + +## References and Credits + +- *Programming Erlang*, Joe Armstrong +- *Reactive Design Patterns*, Roland Kuhn +- *The Actor Model in 10 Minutes*, [InfoQ Article](https://www.infoq.com/articles/actor-model/) +- [Akka Documentation](https://doc.akka.io/docs/akka/current/index.html) + diff --git a/actor-model/etc/Actor_Model_UML_Class_Diagram.png b/actor-model/etc/Actor_Model_UML_Class_Diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c34d7a75fdeec17c2665cb7012233805ae7454 GIT binary patch literal 47298 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 GjQTf&f{mL1 literal 0 HcmV?d00001 diff --git a/actor-model/etc/actor-model.urm.puml b/actor-model/etc/actor-model.urm.puml new file mode 100644 index 000000000000..020c1fc735a4 --- /dev/null +++ b/actor-model/etc/actor-model.urm.puml @@ -0,0 +1,35 @@ +@startuml actor-model + +title Actor Model - UML Class Diagram + +class ActorSystem { + +actorOf(actor: Actor): Actor + +shutdown(): void +} + +class Actor { + -mailbox: BlockingQueue + -active: boolean + +send(message: Message): void + +stop(): void + +run(): void + #onReceive(message: Message): void +} + +class ExampleActor { + +onReceive(message: Message): void +} + +class Message { + -content: String + -sender: Actor + +getContent(): String + +getSender(): Actor +} + +ActorSystem --> Actor : creates +Actor <|-- ExampleActor : extends +Actor --> Message : processes +ExampleActor --> Message : uses + +@enduml diff --git a/actor-model/pom.xml b/actor-model/pom.xml new file mode 100644 index 000000000000..76c288829b8d --- /dev/null +++ b/actor-model/pom.xml @@ -0,0 +1,114 @@ + + + + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + actor-model + Actor Model + + + + + + org.junit + junit-bom + 5.11.0 + pom + import + + + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.platform + junit-platform-launcher + test + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + jar-with-dependencies + + + + com.iluwatar.actormodel.App + + + + + + make-assembly + package + + single + + + + + + + + + diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/Actor.java b/actor-model/src/main/java/com/iluwatar/actormodel/Actor.java new file mode 100644 index 000000000000..6e2aaccd1937 --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/Actor.java @@ -0,0 +1,63 @@ +/* + * 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.actormodel; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import lombok.Getter; +import lombok.Setter; + +public abstract class Actor implements Runnable { + + @Setter @Getter private String actorId; + private final BlockingQueue mailbox = new LinkedBlockingQueue<>(); + private volatile boolean active = + true; // always read from main memory and written back to main memory, + + // rather than being cached in a thread's local memory. To make it consistent to all Actors + + public void send(Message message) { + mailbox.add(message); // Add message to queue + } + + public void stop() { + active = false; // Stop the actor loop + } + + @Override + public void run() { + while (active) { + try { + Message message = mailbox.take(); // Wait for a message + onReceive(message); // Process it + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + } + + // Child classes must define what to do with a message + protected abstract void onReceive(Message message); +} diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/ActorSystem.java b/actor-model/src/main/java/com/iluwatar/actormodel/ActorSystem.java new file mode 100644 index 000000000000..db7c21cb6088 --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/ActorSystem.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.actormodel; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +public class ActorSystem { + private final ExecutorService executor = Executors.newCachedThreadPool(); + private final ConcurrentHashMap actorRegister = new ConcurrentHashMap<>(); + private final AtomicInteger idCounter = new AtomicInteger(0); + + public void startActor(Actor actor) { + String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID + actor.setActorId(actorId); // assign the actor it's ID + actorRegister.put(actorId, actor); // Register and save the actor with it's ID + executor.submit(actor); // Run the actor in a thread + } + + public Actor getActorById(String actorId) { + return actorRegister.get(actorId); // Find by Id + } + + public void shutdown() { + executor.shutdownNow(); // Stop all threads + } +} diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/App.java b/actor-model/src/main/java/com/iluwatar/actormodel/App.java new file mode 100644 index 000000000000..79fe79e48a6f --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/App.java @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/** + * The Actor Model is a design pattern used to handle concurrency in a safe, scalable, and + * message-driven way. + * + *

In the Actor Model: - An **Actor** is an independent unit that has its own state and behavior. + * - Actors **communicate only through messages** — they do not share memory. - An **ActorSystem** + * is responsible for creating, starting, and managing the lifecycle of actors. - Messages are + * delivered asynchronously, and each actor processes them one at a time. + * + *

💡 Key benefits: - No shared memory = no need for complex thread-safety - Easy to scale with + * many actors - Suitable for highly concurrent or distributed systems + * + *

🔍 This example demonstrates the Actor Model: - `ActorSystem` starts two actors: `srijan` and + * `ansh`. - `ExampleActor` and `ExampleActor2` extend the `Actor` class and override the + * `onReceive()` method to handle messages. - Actors communicate using `send()` to pass `Message` + * objects that include the message content and sender's ID. - The actors process messages + * **asynchronously in separate threads**, and we allow a short delay (`Thread.sleep`) to let them + * run. - The system is shut down gracefully at the end. + */ +package com.iluwatar.actormodel; + +public class App { + public static void main(String[] args) throws InterruptedException { + ActorSystem system = new ActorSystem(); + Actor srijan = new ExampleActor(system); + Actor ansh = new ExampleActor2(system); + + system.startActor(srijan); + system.startActor(ansh); + ansh.send(new Message("Hello ansh", srijan.getActorId())); + srijan.send(new Message("Hello srijan!", ansh.getActorId())); + + Thread.sleep(1000); // Give time for messages to process + + srijan.stop(); // Stop the actor gracefully + ansh.stop(); + system.shutdown(); // Stop the actor system + } +} diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor.java b/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor.java new file mode 100644 index 000000000000..fd49325f44bd --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor.java @@ -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. + */ +package com.iluwatar.actormodel; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ExampleActor extends Actor { + private final ActorSystem actorSystem; + @Getter private final List receivedMessages = new ArrayList<>(); + + public ExampleActor(ActorSystem actorSystem) { + this.actorSystem = actorSystem; + } + + // Logger log = Logger.getLogger(getClass().getName()); + + @Override + protected void onReceive(Message message) { + LOGGER.info( + "[{}]Received : {} from : [{}]", getActorId(), message.getContent(), message.getSenderId()); + Actor sender = actorSystem.getActorById(message.getSenderId()); // sender actor id + // Reply of the message + if (sender != null && !message.getSenderId().equals(getActorId())) { + sender.send(new Message("I got your message ", getActorId())); + } + } +} diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor2.java b/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor2.java new file mode 100644 index 000000000000..037f96716558 --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/ExampleActor2.java @@ -0,0 +1,46 @@ +/* + * 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.actormodel; + +import java.util.ArrayList; +import java.util.List; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ExampleActor2 extends Actor { + private final ActorSystem actorSystem; + @Getter private final List receivedMessages = new ArrayList<>(); + + public ExampleActor2(ActorSystem actorSystem) { + this.actorSystem = actorSystem; + } + + @Override + protected void onReceive(Message message) { + receivedMessages.add(message.getContent()); + LOGGER.info("[{}]Received : {}", getActorId(), message.getContent()); + } +} diff --git a/actor-model/src/main/java/com/iluwatar/actormodel/Message.java b/actor-model/src/main/java/com/iluwatar/actormodel/Message.java new file mode 100644 index 000000000000..03ca6e02cac0 --- /dev/null +++ b/actor-model/src/main/java/com/iluwatar/actormodel/Message.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.actormodel; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class Message { + private final String content; + private final String senderId; +} diff --git a/actor-model/src/test/java/com/iluwatar/actor/ActorModelTest.java b/actor-model/src/test/java/com/iluwatar/actor/ActorModelTest.java new file mode 100644 index 000000000000..a4a0dee569ab --- /dev/null +++ b/actor-model/src/test/java/com/iluwatar/actor/ActorModelTest.java @@ -0,0 +1,63 @@ +/* + * 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.actor; + +import static org.junit.jupiter.api.Assertions.*; + +import com.iluwatar.actormodel.ActorSystem; +import com.iluwatar.actormodel.App; +import com.iluwatar.actormodel.ExampleActor; +import com.iluwatar.actormodel.ExampleActor2; +import com.iluwatar.actormodel.Message; +import org.junit.jupiter.api.Test; + +public class ActorModelTest { + @Test + void testMainMethod() throws InterruptedException { + App.main(new String[] {}); + } + + @Test + public void testMessagePassing() throws InterruptedException { + ActorSystem system = new ActorSystem(); + + ExampleActor srijan = new ExampleActor(system); + ExampleActor2 ansh = new ExampleActor2(system); + + system.startActor(srijan); + system.startActor(ansh); + + // Ansh recieves a message from Srijan + ansh.send(new Message("Hello ansh", srijan.getActorId())); + + // Wait briefly to allow async processing + Thread.sleep(200); + + // Check that Srijan received the message + assertTrue( + ansh.getReceivedMessages().contains("Hello ansh"), + "ansh should receive the message from Srijan"); + } +} diff --git a/pom.xml b/pom.xml index 46429c75af7c..bc12b56e9d98 100644 --- a/pom.xml +++ b/pom.xml @@ -71,6 +71,7 @@ Java Design Patterns + abstract-document abstract-factory active-object @@ -243,6 +244,8 @@ virtual-proxy visitor backpressure + actor-model + From e359f1b031cc310318b3656efda1a2c36cb6d436 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:31:01 +0300 Subject: [PATCH 004/108] docs: add ssrijan-007-sys as a contributor for code (#3263) * 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 b2fef6640890..d403e424c6d6 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3493,6 +3493,15 @@ "contributions": [ "code" ] + }, + { + "login": "ssrijan-007-sys", + "name": "ssrijan-007-sys", + "avatar_url": "https://avatars.githubusercontent.com/u/137605821?v=4", + "profile": "https://github.com/ssrijan-007-sys", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index a52d7f3f1fed..45f590cffec3 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-383-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-384-orange.svg?style=flat-square)](#contributors-)
@@ -570,6 +570,7 @@ This project is licensed under the terms of the MIT license. Sanura Hettiarachchi
Sanura Hettiarachchi

💻 Kim Gi Uk
Kim Gi Uk

💻 Suchismita Deb
Suchismita Deb

💻 + ssrijan-007-sys
ssrijan-007-sys

💻 From 55bef7ca39e4a80565a3e9eed890372e663fa919 Mon Sep 17 00:00:00 2001 From: e5LA Date: Tue, 22 Apr 2025 20:44:59 +0200 Subject: [PATCH 005/108] chore: removed duplicated dependency (#3258) --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index bc12b56e9d98..808b30d38601 100644 --- a/pom.xml +++ b/pom.xml @@ -319,12 +319,6 @@ ${junit.version} test - - org.junit.jupiter - junit-jupiter-params - ${junit.version} - test - org.junit.jupiter junit-jupiter-migrationsupport From e4681e4a7ca3120f86faf63a324b6b085819ae9a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:45:40 +0300 Subject: [PATCH 006/108] docs: add e5LA as a contributor for code (#3264) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index d403e424c6d6..afa0038a4141 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3502,6 +3502,15 @@ "contributions": [ "code" ] + }, + { + "login": "e5LA", + "name": "e5LA", + "avatar_url": "https://avatars.githubusercontent.com/u/208197507?v=4", + "profile": "https://github.com/e5LA", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 45f590cffec3..0b9b5b0d90ad 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-384-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-385-orange.svg?style=flat-square)](#contributors-)
@@ -572,6 +572,9 @@ This project is licensed under the terms of the MIT license. Suchismita Deb
Suchismita Deb

💻 ssrijan-007-sys
ssrijan-007-sys

💻 + + e5LA
e5LA

💻 + From 6e20d3221383c1954bb5b4b89c5aeeb051e68f3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:50:26 +0300 Subject: [PATCH 007/108] build(deps): bump org.springframework:spring-web (#3262) Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 7.0.0-M3 to 7.0.0-M4. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v7.0.0-M3...v7.0.0-M4) --- updated-dependencies: - dependency-name: org.springframework:spring-web dependency-version: 7.0.0-M4 dependency-type: direct:production update-type: version-update:semver-patch ... 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 236723c52682..586dbc1b6ab4 100644 --- a/dynamic-proxy/pom.xml +++ b/dynamic-proxy/pom.xml @@ -56,7 +56,7 @@ org.springframework spring-web - 7.0.0-M3 + 7.0.0-M4 org.junit.jupiter From ad6bdf802d1b7a890a6801e3064cec586f55f760 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:52:25 +0300 Subject: [PATCH 008/108] build(deps): bump org.sonarsource.scanner.maven:sonar-maven-plugin (#3261) Bumps [org.sonarsource.scanner.maven:sonar-maven-plugin](https://github.com/SonarSource/sonar-scanner-maven) from 5.0.0.4389 to 5.1.0.4751. - [Release notes](https://github.com/SonarSource/sonar-scanner-maven/releases) - [Commits](https://github.com/SonarSource/sonar-scanner-maven/compare/5.0.0.4389...5.1.0.4751) --- updated-dependencies: - dependency-name: org.sonarsource.scanner.maven:sonar-maven-plugin dependency-version: 5.1.0.4751 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 808b30d38601..20f468706502 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ 3.14.0 - 5.0.0.4389 + 5.1.0.4751 https://sonarcloud.io iluwatar iluwatar_java-design-patterns From dae93adfeec9632a1400dae7d2098c3e63c09dd8 Mon Sep 17 00:00:00 2001 From: Maziyar Gerami <122622721+maziyar-gerami@users.noreply.github.com> Date: Tue, 22 Apr 2025 22:25:07 +0330 Subject: [PATCH 009/108] translation: Translate selected patterns to persian (#3256) * Persian Translation: Add persian translation to abstract-document * Persian Translation: Add abstract-document.png to abstract-document folder * Persian Translation: Add codes to README.md of abstract-document * Persian Translation: some improvements in abstract-document * Persian Translation: Add refrence links in abstract-document * Persian Translation: add rtl tag in abstract-document * active-object : translate * active-object: improve when to use * active-object: improve when to use * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets * active-object: Fix all bullets * -added persian translation of factory pattern * -renamed file * -changed wikipedia definition * -fixed table problem * -fixed problems in bullet alignments * Update README.md -fixed alignment in bullets * Update README.md -changed tags to English --------- Co-authored-by: Seyyed Keivan Shirkoubian --- localization/fa/abstract-document/README.md | 243 ++++++++++++++++++ .../etc/abstract-document.png | Bin 0 -> 96228 bytes localization/fa/active-object/README.md | 220 ++++++++++++++++ .../etc/active-object-sequence-diagram.png | Bin 0 -> 83490 bytes .../active-object/etc/active-object.urm.png | Bin 0 -> 19466 bytes .../active-object/etc/active-object.urm.puml | 25 ++ localization/fa/factory/README.md | 155 +++++++++++ .../factory/etc/factory-sequence-diagram.png | Bin 0 -> 29457 bytes 8 files changed, 643 insertions(+) create mode 100644 localization/fa/abstract-document/README.md create mode 100644 localization/fa/abstract-document/etc/abstract-document.png create mode 100644 localization/fa/active-object/README.md create mode 100644 localization/fa/active-object/etc/active-object-sequence-diagram.png create mode 100644 localization/fa/active-object/etc/active-object.urm.png create mode 100644 localization/fa/active-object/etc/active-object.urm.puml create mode 100644 localization/fa/factory/README.md create mode 100644 localization/fa/factory/etc/factory-sequence-diagram.png diff --git a/localization/fa/abstract-document/README.md b/localization/fa/abstract-document/README.md new file mode 100644 index 000000000000..7097ffc8b4ea --- /dev/null +++ b/localization/fa/abstract-document/README.md @@ -0,0 +1,243 @@ +--- +title: "الگوی Abstract Document در جاوا: ساده‌سازی مدیریت داده با انعطاف‌پذیری" +shortTitle: Abstract Document +description: "الگوی طراحی Abstract Document در جاوا را بررسی کنید. با هدف، توضیح، کاربرد، مزایا و نمونه‌های دنیای واقعی برای پیاده‌سازی ساختارهای داده‌ای پویا و انعطاف‌پذیر آشنا شوید." +category: Structural +language: fa +tag: + - Abstraction + - Decoupling + - Dynamic typing + - Encapsulation + - Extensibility + - Polymorphism +--- + +## هدف الگوی طراحی Abstract Document + +الگوی طراحی Abstract Document در جاوا یک الگوی طراحی ساختاری مهم است که راهی یکپارچه برای مدیریت ساختارهای داده‌ای سلسله‌مراتبی و درخت‌ی فراهم می‌کند، با تعریف یک واسط مشترک برای انواع مختلف اسناد. این الگو ساختار اصلی سند را از فرمت‌های خاص داده جدا می‌کند، که باعث به‌روزرسانی پویا و نگهداری ساده‌تر می‌شود. + +## توضیح دقیق الگوی Abstract Document با نمونه‌های دنیای واقعی + +الگوی طراحی Abstract Document در جاوا امکان مدیریت پویا ویژگی‌های پویا(غیر استاتیک) را فراهم می‌کند. این الگو از مفهوم traits استفاده می‌کند تا ایمنی نوع‌داده (type safety) را فراهم کرده و ویژگی‌های کلاس‌های مختلف را به مجموعه‌ای از واسط‌ها تفکیک کند. + +مثال دنیای واقعی + +> فرض کنید یک سیستم کتابخانه از الگوی Abstract Document در جاوا استفاده می‌کند، جایی که کتاب‌ها می‌توانند فرمت‌ها و ویژگی‌های متنوعی داشته باشند: کتاب‌های فیزیکی، کتاب‌های الکترونیکی، و کتاب‌های صوتی. هر فرمت ویژگی‌های خاص خود را دارد، مانند تعداد صفحات برای کتاب‌های فیزیکی، حجم فایل برای کتاب‌های الکترونیکی، و مدت‌زمان برای کتاب‌های صوتی. الگوی Abstract Document به سیستم کتابخانه اجازه می‌دهد تا این فرمت‌های متنوع را به‌صورت انعطاف‌پذیر مدیریت کند. با استفاده از این الگو، سیستم می‌تواند ویژگی‌ها را به‌صورت پویا ذخیره و بازیابی کند، بدون نیاز به ساختار سفت و سخت برای هر نوع کتاب، و این کار افزودن فرمت‌ها یا ویژگی‌های جدید را در آینده بدون تغییرات عمده در کد آسان می‌سازد. + +به زبان ساده + +> الگوی Abstract Document اجازه می‌دهد ویژگی‌هایی به اشیاء متصل شوند بدون اینکه خود آن اشیاء از آن اطلاع داشته باشند. + +ویکی‌پدیا می‌گوید + +> یک الگوی طراحی ساختاری شی‌ء‌گرا برای سازماندهی اشیاء در کلید-مقدارهایی با تایپ آزاد و ارائه داده‌ها از طریق نمای تایپ است. هدف این الگو دستیابی به انعطاف‌پذیری بالا بین اجزا در یک زبان strongly typed است که در آن بتوان ویژگی‌های جدیدی را به‌صورت پویا به ساختار درختی اشیاء اضافه کرد، بدون از دست دادن پشتیبانی از type safety. این الگو از traits برای جداسازی ویژگی‌های مختلف یک کلاس در اینترفیس‌های متفاوت استفاده می‌کند. + +نمودار کلاس + +![Abstract Document class diagram](./etc/abstract-document.png "Abstract Document class diagram") + +## مثال برنامه‌نویسی از الگوی Abstract Document در جاوا + +فرض کنید یک خودرو داریم که از قطعات مختلفی تشکیل شده است. اما نمی‌دانیم آیا این خودرو خاص واقعاً همه قطعات را دارد یا فقط برخی از آن‌ها. خودروهای ما پویا و بسیار انعطاف‌پذیر هستند. + +بیایید ابتدا کلاس‌های پایه `Document` و `AbstractDocument` را تعریف کنیم. این کلاس‌ها اساساً یک شیء را قادر می‌سازند تا یک نقشه از ویژگی‌ها و هر تعداد شیء فرزند را نگه دارد. + +```java +public interface Document { + + Void put(String key, Object value); + + Object get(String key); + + Stream children(String key, Function, T> constructor); +} + +public abstract class AbstractDocument implements Document { + + private final Map properties; + + protected AbstractDocument(Map properties) { + Objects.requireNonNull(properties, "properties map is required"); + this.properties = properties; + } + + @Override + public Void put(String key, Object value) { + properties.put(key, value); + return null; + } + + @Override + public Object get(String key) { + return properties.get(key); + } + + @Override + public Stream children(String key, Function, T> constructor) { + return Stream.ofNullable(get(key)) + .filter(Objects::nonNull) + .map(el -> (List>) el) + .findAny() + .stream() + .flatMap(Collection::stream) + .map(constructor); + } + + // Other properties and methods... +} +``` +در ادامه، یک enum به نام Property و مجموعه‌ای از واسط‌ها برای type، price، model و parts تعریف می‌کنیم. این کار به ما اجازه می‌دهد یک واسط با ظاهر استاتیک برای کلاس Car ایجاد کنیم. +```java +public enum Property { + + PARTS, TYPE, PRICE, MODEL +} + +public interface HasType extends Document { + + default Optional getType() { + return Optional.ofNullable((String) get(Property.TYPE.toString())); + } +} + +public interface HasPrice extends Document { + + default Optional getPrice() { + return Optional.ofNullable((Number) get(Property.PRICE.toString())); + } +} + +public interface HasModel extends Document { + + default Optional getModel() { + return Optional.ofNullable((String) get(Property.MODEL.toString())); + } +} + +public interface HasParts extends Document { + + default Stream getParts() { + return children(Property.PARTS.toString(), Part::new); + } +} + +public class Part extends AbstractDocument implements HasType, HasModel, HasPrice { + + public Part(Map properties) { + super(properties); + } +} +``` +اکنون آماده‌ایم تا کلاس Car را معرفی کنیم. +```java +public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts { + + public Car(Map properties) { + super(properties); + } +} +``` +و در نهایت، نحوه ساخت و استفاده از Car را در یک مثال کامل می‌بینید. +```java + public static void main(String[] args) { + LOGGER.info("Constructing parts and car"); + + var wheelProperties = Map.of( + Property.TYPE.toString(), "wheel", + Property.MODEL.toString(), "15C", + Property.PRICE.toString(), 100L); + + var doorProperties = Map.of( + Property.TYPE.toString(), "door", + Property.MODEL.toString(), "Lambo", + Property.PRICE.toString(), 300L); + + var carProperties = Map.of( + Property.MODEL.toString(), "300SL", + Property.PRICE.toString(), 10000L, + Property.PARTS.toString(), List.of(wheelProperties, doorProperties)); + + var car = new Car(carProperties); + + LOGGER.info("Here is our car:"); + LOGGER.info("-> model: {}", car.getModel().orElseThrow()); + LOGGER.info("-> price: {}", car.getPrice().orElseThrow()); + LOGGER.info("-> parts: "); + car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", + p.getType().orElse(null), + p.getModel().orElse(null), + p.getPrice().orElse(null)) + ); +} +``` +خروجی برنامه: +``` +07:21:57.391 [main] INFO com.iluwatar.abstractdocument.App -- Constructing parts and car +07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- Here is our car: +07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- -> model: 300SL +07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> price: 10000 +07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> parts: +07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- wheel/15C/100 +07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- door/Lambo/300 +``` + + ### چه زمانی از الگوی Abstract Document در جاوا استفاده کنیم؟ + +الگوی طراحی Abstract Document به‌ویژه در سناریوهایی مفید است که نیاز به مدیریت انواع مختلفی از اسناد در جاوا وجود دارد که برخی ویژگی‌ها یا رفتارهای مشترک دارند، ولی ویژگی‌ها یا رفتارهای خاص خود را نیز دارند. در ادامه چند سناریوی مناسب برای این الگو آورده شده است: + +* سیستم‌های مدیریت محتوا (CMS): ممکن است انواع مختلفی از محتوا مانند مقاله، تصویر، ویدئو و... وجود داشته باشد. هر نوع محتوا ویژگی‌های مشترکی مثل تاریخ ایجاد، نویسنده و تگ‌ها دارد، ولی همچنین ویژگی‌های خاصی مثل ابعاد تصویر یا مدت‌زمان ویدئو. + +* سیستم‌های فایل: اگر یک سیستم فایل طراحی می‌کنید که باید انواع مختلف فایل مانند اسناد، تصاویر، فایل‌های صوتی و دایرکتوری‌ها را مدیریت کند، این الگو می‌تواند راهی یکپارچه برای دسترسی به ویژگی‌هایی مانند اندازه فایل یا تاریخ ایجاد، فراهم کند و در عین حال ویژگی‌های خاص هر نوع فایل را هم مدیریت کند. + +* سیستم‌های تجارت الکترونیک: یک پلتفرم فروش آنلاین ممکن است محصولات مختلفی داشته باشد مثل محصولات فیزیکی، فایل‌های دیجیتال، و اشتراک‌ها. این محصولات ویژگی‌هایی مثل نام، قیمت و توضیح را به اشتراک می‌گذارند، ولی ویژگی‌های خاصی هم دارند مانند وزن حمل برای محصولات فیزیکی یا لینک دانلود برای دیجیتال‌ها. + +* سیستم‌های سوابق پزشکی: در مراقبت سلامت، پرونده بیماران ممکن است داده‌های مختلفی مثل مشخصات فردی، سوابق پزشکی، نتایج آزمایش‌ها و نسخه‌ها را شامل شود. این الگو می‌تواند ویژگی‌های مشترک مثل شماره بیمار یا تاریخ تولد را مدیریت کند و هم‌زمان ویژگی‌های خاصی مثل نتایج آزمایش یا داروهای تجویزی را هم پوشش دهد. + +* مدیریت پیکربندی: هنگام کار با تنظیمات پیکربندی نرم‌افزار، ممکن است انواع مختلفی از عناصر پیکربندی وجود داشته باشد، هر یک با ویژگی‌های خاص خود. این الگو می‌تواند برای مدیریت این عناصر مفید باشد. + +* پلتفرم‌های آموزشی: سیستم‌های آموزشی ممکن است انواع مختلفی از منابع یادگیری داشته باشند مثل محتوای متنی، ویدیوها، آزمون‌ها و تمرین‌ها. ویژگی‌های مشترکی مثل عنوان، نویسنده و تاریخ انتشار وجود دارد، ولی ویژگی‌های خاصی مانند مدت ویدیو یا مهلت تحویل تمرین نیز ممکن است وجود داشته باشد. + +* ابزارهای مدیریت پروژه: در برنامه‌های مدیریت پروژه، ممکن است انواع مختلفی از وظایف مانند آیتم‌های to-do، milestoneها و issueها داشته باشید. این الگو می‌تواند برای مدیریت ویژگی‌های عمومی مانند نام وظیفه و مسئول آن استفاده شود و در عین حال ویژگی‌های خاص مانند تاریخ milestone یا اولویت issue را نیز پوشش دهد. + +* اسناد ساختار ویژگی‌های متنوع و در حال تحول دارند. + +* افزودن ویژگی‌های جدید به‌صورت پویا یک نیاز رایج است. + +* جداسازی دسترسی به داده از فرمت‌های خاص حیاتی است. + +* نگهداری‌پذیری و انعطاف‌پذیری برای کد اهمیت دارد. + +ایده اصلی پشت الگوی Abstract Document فراهم کردن روشی انعطاف‌پذیر و قابل توسعه برای مدیریت انواع مختلف اسناد یا موجودیت‌ها با ویژگی‌های مشترک و خاص است. با تعریف یک واسط مشترک و پیاده‌سازی آن در انواع مختلف اسناد، می‌توان به شیوه‌ای منظم و یکپارچه برای مدیریت ساختارهای پیچیده داده دست یافت. +### مزایا و معایب الگوی Abstract Document +

+مزایا: + +* انعطاف‌پذیری: پشتیبانی از ساختارهای متنوع اسناد و ویژگی‌ها. + +* قابلیت توسعه: افزودن ویژگی‌های جدید بدون شکستن کد موجود. + +* نگهداری‌پذیری: ارتقاء کد تمیز و قابل تطبیق به‌واسطه جداسازی وظایف. + +* قابلیت استفاده مجدد: نمای دید تایپ‌شده باعث استفاده مجدد از کد برای دسترسی به نوع خاصی از ویژگی می‌شود. + +معایب: + +* پیچیدگی: نیاز به تعریف واسط‌ها و نماها، که باعث اضافه شدن سربار پیاده‌سازی می‌شود. + +* کارایی: ممکن است سربار کمی نسبت به دسترسی مستقیم به داده داشته باشد. +
+ +منابع و اعتبارها + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) + +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) + +* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)] (https://amzn.to/49zRP4R) + +* [Patterns of Enterprise Application Architecture] (https://amzn.to/3WfKBPR) + +* [Abstract Document Pattern (Wikipedia)] (https://en.wikipedia.org/wiki/Abstract_Document_Pattern) + +* [Dealing with Properties (Martin Fowler)] (http://martinfowler.com/apsupp/properties.pdf) diff --git a/localization/fa/abstract-document/etc/abstract-document.png b/localization/fa/abstract-document/etc/abstract-document.png new file mode 100644 index 0000000000000000000000000000000000000000..6bc0b29a4e77680d8eda277c93b97277bbe7193b GIT binary patch literal 96228 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∈MtPMEwTr6eK$ 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 تصور کنید در یک رستوران شلوغ، مشتریان سفارش خود را به گارسون‌ها می‌سپارند. به‌جای آنکه گارسون‌ها خودشان به آشپزخانه بروند و غذا را آماده کنند، سفارش‌ها را روی کاغذهایی می‌نویسند و به یک هماهنگ‌کننده می‌دهند. این هماهنگ‌کننده گروهی از سرآشپزها را مدیریت می‌کند که غذاها را به صورت ناهمگام آماده می‌کنند. هرگاه آشپزی آزاد شود، سفارش بعدی را از صف برمی‌دارد، غذا را آماده می‌کند و پس از آن گارسون را برای سرو غذا مطلع می‌سازد. +> +> در این قیاس، گارسون‌ها نماینده threadهای کلاینت هستند، هماهنگ‌کننده نقش زمان‌بند (scheduler) را ایفا می‌کند، و آشپزها نمایان‌گر اجرای متدها در threadهای جداگانه هستند. این ساختار باعث می‌شود گارسون‌ها بتوانند بدون مسدود شدن توسط فرایند آماده‌سازی غذا، سفارش‌های بیشتری دریافت کنند—درست مانند اینکه الگوی Active Object، فراخوانی متد را از اجرای آن جدا می‌کند تا هم‌زمانی (concurrency) را افزایش دهد. + +به زبان ساده + +> الگوی Active Object، اجرای متد را از فراخوانی آن جدا می‌کند تا در برنامه‌های چندریسمانی (multithreaded)، هم‌زمانی و پاسخ‌گویی بهتری فراهم شود. + +طبق تعریف ویکی‌پدیا + +> الگوی طراحی Active Object اجرای متد را از فراخوانی آن جدا می‌کند، برای شیءهایی که هرکدام thread کنترل مخصوص به خود را دارند. هدف، معرفی هم‌زمانی با استفاده از فراخوانی متد به‌صورت ناهمگام و یک زمان‌بند برای مدیریت درخواست‌ها است. +> +> این الگو شامل شش جزء کلیدی است: +> +> * یک proxy، که رابطی برای کلاینت‌ها با متدهای عمومی فراهم می‌کند. +> * یک interface که درخواست متد برای شیء فعال (active object) را تعریف می‌کند. +> * فهرستی از درخواست‌های معلق از سوی کلاینت‌ها. +> * یک زمان‌بند (scheduler) که تصمیم می‌گیرد کدام درخواست بعدی اجرا شود. +> * پیاده‌سازی متد شیء فعال. +> * یک callback یا متغیر برای اینکه کلاینت نتیجه را دریافت کند. + +نمودار توالی + +![Active Object sequence diagram](./etc/active-object-sequence-diagram.png) + +## مثال برنامه‌نویسی از Active Object در جاوا + +این بخش نحوه عملکرد الگوی Active Object در جاوا را توضیح می‌دهد و کاربرد آن در مدیریت وظایف ناهمگام و کنترل هم‌زمانی را نشان می‌دهد. + +اورک‌ها به دلیل ذات وحشی و غیرقابل مهارشان شناخته می‌شوند. به‌نظر می‌رسد هرکدام thread کنترل مخصوص خود را دارند. برای پیاده‌سازی یک موجود که دارای سازوکار thread مستقل خود باشد و فقط API را در اختیار قرار دهد نه اجرای داخلی را، می‌توان از الگوی Active Object استفاده کرد. + +```java +public abstract class ActiveCreature { + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + thread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + requests.take().run(); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + } + } + ); + thread.start(); + } + + public void eat() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} is eating!", name()); + logger.info("{} has finished eating!", name()); + } + } + ); + } + + public void roam() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} has started to roam the wastelands.", name()); + } + } + ); + } + + public String name() { + return this.name; + } +} +``` + +می‌توان دید هر کلاسی که از ActiveCreature ارث‌بری کند، دارای thread کنترل مختص به خود برای فراخوانی و اجرای متدها خواهد بود. + +برای مثال، کلاس Orc: + +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } +} +``` +اکنون می‌توان چند موجود مانند orc ایجاد کرد، به آن‌ها دستور داد که بخورند و پرسه بزنند، و آن‌ها این دستورات را در thread مختص به خود اجرا می‌کنند: + +```java +public class App implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(App.class.getName()); + + private static final int NUM_CREATURES = 3; + + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + List creatures = new ArrayList<>(); + try { + for (int i = 0; i < NUM_CREATURES; i++) { + creatures.add(new Orc(Orc.class.getSimpleName() + i)); + creatures.get(i).eat(); + creatures.get(i).roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + Thread.currentThread().interrupt(); + } finally { + for (int i = 0; i < NUM_CREATURES; i++) { + creatures.get(i).kill(0); + } + } + } +} +``` + +خروجی برنامه: + +``` +09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating! +09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating! +09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating! +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating! +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating! +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands. +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating! +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands. +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands. +``` + +چه زمانی از الگوی Active Object در جاوا استفاده کنیم؟ + +از الگوی Active Object در جاوا استفاده کنید زمانی که: +> * نیاز دارید وظایف ناهمگام را بدون مسدود کردن thread اصلی مدیریت کنید تا عملکرد و پاسخ‌گویی بهتری داشته باشید. +> * نیاز به تعامل ناهمگام با منابع خارجی دارید. +> * می‌خواهید پاسخ‌گویی برنامه را افزایش دهید. +> * نیاز به مدیریت وظایف هم‌زمان به‌صورت ماژولار و قابل نگهداری دارید. + +آموزش‌های Java برای الگوی Active Object +> [Android and Java Concurrency: The Active Object Pattern (Douglas Schmidt)]((https://www.youtube.com/watch?v=Cd8t2u5Qmvc)) + +کاربردهای دنیای واقعی الگوی Active Object در جاوا + +> سیستم‌های معاملات بلادرنگ که درخواست‌ها به‌صورت ناهمگام پردازش می‌شوند. +> که در آن وظایف طولانی در پس‌زمینه اجرا می‌شوند بدون آنکه رابط کاربری را متوقف کنند. +> رابط‌های کاربری گرافیکی (GUI) +> برنامه‌نویسی بازی‌ها برای مدیریت به‌روزرسانی‌های هم‌زمان وضعیت بازی یا محاسبات هوش مصنوعی. + +مزایا و ملاحظات الگوی Active Object + +با مزایا و معایب استفاده از الگوی Active Object در جاوا آشنا شوید؛ از جمله بهبود ایمنی threadها و ملاحظات سربار احتمالی (overhead). + +> مزایا: +> +> * پاسخ‌گویی بهتر thread اصلی. +> * محصورسازی مسائل مربوط به هم‌زمانی درون شیءها. +> * بهبود سازمان‌دهی کد و قابلیت نگهداری. +> * فراهم‌سازی ایمنی در برابر شرایط بحرانی (thread safety) و جلوگیری از مشکلات وضعیت مشترک. + +> معایب: +> +> * سربار اضافی به دلیل ارسال پیام و مدیریت threadها. +> * برای تمام سناریوهای هم‌زمانی مناسب نیست. + +الگوهای طراحی مرتبط در جاوا + +> * [Command](https://java-design-patterns.com/patterns/command/): درخواست را به‌عنوان یک شیء کپسوله می‌کند، مشابه روشی که Active Object فراخوانی متد را کپسوله می‌کند. +> * [Promise](https://java-design-patterns.com/patterns/promise/): راهی برای دریافت نتیجه یک فراخوانی متد ناهمگام فراهم می‌کند؛ اغلب همراه با Active Object استفاده می‌شود. +> * [Proxy](https://java-design-patterns.com/patterns/proxy/): الگوی Active Object می‌تواند از proxy برای مدیریت فراخوانی‌های متد به‌صورت ناهمگام استفاده کند. + +منابع و مراجع + +> * [Design Patterns: Elements of Reusable Object Software](https://amzn.to/3HYqrBE) +> * [Concurrent Programming in Java: Design Principles and Patterns](https://amzn.to/498SRVq) +> * [Java Concurrency in Practice](https://amzn.to/4aRMruW) +> * [Learning Concurrent Programming in Scala](https://amzn.to/3UE07nV) +> * [Pattern Languages of Program Design 3](https://amzn.to/3OI1j61) +> * [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/3UgC24V) + diff --git a/localization/fa/active-object/etc/active-object-sequence-diagram.png b/localization/fa/active-object/etc/active-object-sequence-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..b725d9b07b6d14936f2453c4febe630b92526d10 GIT binary patch literal 83490 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�TxYE36Yk<#Jh(y%^~6xa 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%0ATK8Me7XO|L7n+5a_@btd{)e()=Fo|26^A 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 literal 0 HcmV?d00001 diff --git a/localization/fa/active-object/etc/active-object.urm.puml b/localization/fa/active-object/etc/active-object.urm.puml new file mode 100644 index 000000000000..3fc3c8e1e921 --- /dev/null +++ b/localization/fa/active-object/etc/active-object.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.activeobject { + abstract class ActiveCreature { + - logger : Logger + - name : String + - requests : BlockingQueue + - thread : Thread + + ActiveCreature(name : String) + + eat() + + name() : String + + roam() + } + class App { + - creatures : Integer + - logger : Logger + + App() + + main(args : String[]) {static} + + run() + } + class Orc { + + Orc(name : String) + } +} +Orc --|> ActiveCreature +@enduml \ No newline at end of file diff --git a/localization/fa/factory/README.md b/localization/fa/factory/README.md new file mode 100644 index 000000000000..db41813464e3 --- /dev/null +++ b/localization/fa/factory/README.md @@ -0,0 +1,155 @@ +--- +title: "الگوی factory در جاوا: ساده‌سازی ایجاد اشیاء" +shortTitle: factory +description: "الگوی طراحی factory در جاوا را با مثال‌ها و توضیحات دقیق بیاموزید. یاد بگیرید چگونه با استفاده از الگوی factory کدی انعطاف‌پذیر و مقیاس‌پذیر ایجاد کنید. مناسب برای توسعه‌دهندگانی که به دنبال بهبود مهارت‌های طراحی شیءگرا هستند." +category: structural +language: fa +tag: + - Abstraction + - Encapsulation + - Gang of Four + - Instantiation + - Polymorphism +--- + +## هدف از الگوی طراحی factory + +الگوی طراحی factory در جاوا یک الگوی ساختاری است که یک رابط برای ایجاد یک شیء تعریف می‌کند اما به زیرکلاس‌ها اجازه می‌دهد نوع اشیائی را که ایجاد خواهند شد تغییر دهند. این الگو انعطاف‌پذیری و مقیاس‌پذیری را در کد شما ترویج می‌دهد. + +## توضیح دقیق الگوی factory با مثال‌های دنیای واقعی + +### مثال دنیای واقعی + +> تصور کنید در یک نانوایی انواع مختلف کیک‌ها با استفاده از الگوی طراحی factory ساخته می‌شوند. `CakeFactory` فرآیند ایجاد را مدیریت می‌کند و امکان افزودن آسان انواع جدید کیک‌ها را بدون تغییر در فرآیند اصلی فراهم می‌کند. `CakeFactory` می‌تواند انواع مختلفی از کیک‌ها مانند کیک شکلاتی، کیک وانیلی و کیک توت‌فرنگی تولید کند. به جای اینکه کارکنان نانوایی به صورت دستی مواد اولیه را انتخاب کنند و دستورالعمل‌های خاصی را برای هر نوع کیک دنبال کنند، از `CakeFactory` برای مدیریت فرآیند استفاده می‌کنند. مشتری فقط نوع کیک را درخواست می‌کند و `CakeFactory` مواد اولیه و دستورالعمل مناسب را تعیین کرده و نوع خاصی از کیک را ایجاد می‌کند. این تنظیم به نانوایی اجازه می‌دهد تا انواع جدید کیک‌ها را به راحتی اضافه کند بدون اینکه فرآیند اصلی تغییر کند، که این امر انعطاف‌پذیری و مقیاس‌پذیری را ترویج می‌دهد. + +### تعریف ویکی‌پدیا + +> الگوی factory یک شیء برای ایجاد اشیاء دیگر است – به طور رسمی، factory یک تابع یا متدی است که اشیاء با نمونه‌ها یا کلاس‌های مختلف را بازمی‌گرداند. + +### نمودار توالی + +![نمودار توالی factory](./etc/factory-sequence-diagram.png) + +## مثال برنامه‌نویسی از الگوی factory در جاوا + +تصور کنید یک کیمیاگر قصد دارد سکه‌هایی تولید کند. کیمیاگر باید بتواند هم سکه‌های طلا و هم سکه‌های مسی ایجاد کند و تغییر بین آن‌ها باید بدون تغییر در کد موجود امکان‌پذیر باشد. الگوی factory این امکان را فراهم می‌کند با ارائه یک متد ایجاد استاتیک که می‌توان آن را با پارامترهای مرتبط فراخوانی کرد. + +در جاوا، می‌توانید الگوی factory را با تعریف یک رابط `Coin` و پیاده‌سازی‌های آن `GoldCoin` و `CopperCoin` پیاده‌سازی کنید. کلاس `CoinFactory` یک متد استاتیک `getCoin` ارائه می‌دهد تا اشیاء سکه را بر اساس نوع ایجاد کند. + +```java +public interface Coin { + String getDescription(); +} +``` + +```java +public class GoldCoin implements Coin { + + static final String DESCRIPTION = "This is a gold coin."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +```java +public class CopperCoin implements Coin { + + static final String DESCRIPTION = "This is a copper coin."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +کد زیر انواع سکه‌هایی که پشتیبانی می‌شوند (`GoldCoin` و `CopperCoin`) را نشان می‌دهد. + +```java +@RequiredArgsConstructor +@Getter +public enum CoinType { + + COPPER(CopperCoin::new), + GOLD(GoldCoin::new); + + private final Supplier constructor; +} +``` + +سپس متد استاتیک `getCoin` برای ایجاد اشیاء سکه در کلاس factory `CoinFactory` کپسوله شده است. + +```java +public class CoinFactory { + + public static Coin getCoin(CoinType type) { + return type.getConstructor().get(); + } +} +``` + +اکنون، در کد کلاینت، می‌توانیم انواع مختلفی از سکه‌ها را با استفاده از کلاس factory تولید کنیم. + +```java +public static void main(String[] args) { + LOGGER.info("The alchemist begins his work."); + var coin1 = CoinFactory.getCoin(CoinType.COPPER); + var coin2 = CoinFactory.getCoin(CoinType.GOLD); + LOGGER.info(coin1.getDescription()); + LOGGER.info(coin2.getDescription()); +} +``` + +خروجی برنامه: + +``` +06:19:53.530 [main] INFO com.iluwatar.factory.App -- The alchemist begins his work. +06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a copper coin. +06:19:53.533 [main] INFO com.iluwatar.factory.App -- This is a gold coin. +``` + +## زمان استفاده از الگوی factory در جاوا + +* از الگوی طراحی factory در جاوا زمانی استفاده کنید که کلاس از قبل نوع دقیق و وابستگی‌های اشیائی که نیاز به ایجاد آن دارد را نمی‌داند. +* زمانی که یک متد یکی از چندین کلاس ممکن که یک کلاس والد مشترک دارند را بازمی‌گرداند و می‌خواهد منطق انتخاب شیء را کپسوله کند. +* این الگو معمولاً هنگام طراحی فریم‌ورک‌ها یا کتابخانه‌ها برای ارائه بهترین انعطاف‌پذیری و جداسازی از انواع کلاس‌های خاص استفاده می‌شود. + +## کاربردهای دنیای واقعی الگوی factory در جاوا + +> * [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +> * [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +> * [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +> * [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +> * این مورد [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) اشیاء singleton مختلف را بر اساس یک پروتکل بازمی‌گرداند +> * [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E)) +> * [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) و متدهای مشابه دیگر. +> +> * کتابخانه‌ی JavaFX از الگوهای factory برای ایجاد کنترل‌های مختلف رابط کاربری متناسب با نیازهای محیط کاربر استفاده می‌کند. + +## مزایا و معایب الگوی factory + +### مزایا: + +> * پیاده‌سازی الگوی factory در برنامه جاوای شما، وابستگی بین پیاده‌سازی و کلاس‌هایی که استفاده می‌کند را کاهش می‌دهد. +> * از [اصل Open/Closed](https://java-design-patterns.com/principles/#open-closed-principle) پشتیبانی می‌کند، زیرا سیستم می‌تواند انواع جدیدی را بدون تغییر کد موجود معرفی کند. + +### معایب: + +> * کد می‌تواند به دلیل معرفی چندین کلاس اضافی پیچیده‌تر شود. +> * استفاده بیش از حد می‌تواند کد را کمتر خوانا کند اگر پیچیدگی ایجاد اشیاء کم یا غیرضروری باشد. + +## الگوهای طراحی مرتبط با جاوا + +> * الگوی [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): می‌توان آن را نوعی factory در نظر گرفت که با گروهی از محصولات کار می‌کند. +> * الگوی [Singleton](https://java-design-patterns.com/patterns/singleton/): اغلب همراه با factory استفاده می‌شود تا اطمینان حاصل شود که یک کلاس تنها یک نمونه دارد. +> * الگوی [Builder](https://java-design-patterns.com/patterns/builder/): ساخت یک شیء پیچیده را از نمایش آن جدا می‌کند، مشابه نحوه‌ای که factoryها مدیریت نمونه‌سازی را انجام می‌دهند. +> * الگوی [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): یک factory از محتوای غیرقابل تغییر با رابط‌های builder و factory جداگانه است. + +## منابع و اعتبارات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0Rk5y) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/3UpTLrG) diff --git a/localization/fa/factory/etc/factory-sequence-diagram.png b/localization/fa/factory/etc/factory-sequence-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..260bea92f24736656584c4714398e47e2dbb61c2 GIT binary patch literal 29457 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

a2pE@iOs1kiD%Yk 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�=nt6c0Wf(41WEl3CS?Fjz#jnoc5nbbUbAIJDWn@L{tc!TV#TiY z-jc$6dR|Wz90hHqI3IG5A literal 0 HcmV?d00001 From f8f33f586a605e1685ea24cb2631acf961d1a182 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 22 Apr 2025 21:55:51 +0300 Subject: [PATCH 010/108] docs: add maziyar-gerami as a contributor for translation (#3265) * 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 afa0038a4141..9509bc095ae7 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3511,6 +3511,15 @@ "contributions": [ "code" ] + }, + { + "login": "maziyar-gerami", + "name": "Maziyar Gerami", + "avatar_url": "https://avatars.githubusercontent.com/u/122622721?v=4", + "profile": "http://maziyar-gerami.github.io/portfolio/", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 0b9b5b0d90ad..c2c3a5c7af10 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-385-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-386-orange.svg?style=flat-square)](#contributors-)
@@ -574,6 +574,7 @@ This project is licensed under the terms of the MIT license.
e5LA
e5LA

💻 + Maziyar Gerami
Maziyar Gerami

🌍 From 8a64f4c5743f41a2b4fc8d28ecf1e9f13acb5a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sat, 26 Apr 2025 23:14:07 +0300 Subject: [PATCH 011/108] docs: update dependency injection --- dependency-injection/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dependency-injection/README.md b/dependency-injection/README.md index c3fc2c15a977..c9a2848bdfde 100644 --- a/dependency-injection/README.md +++ b/dependency-injection/README.md @@ -118,10 +118,6 @@ The program output: 11:54:05.308 [main] INFO com.iluwatar.dependency.injection.Tobacco -- GuiceWizard smoking RivendellTobacco ``` -## Detailed Explanation of Dependency Injection Pattern with Real-World Examples - -![Dependency Injection](./etc/dependency-injection.png "Dependency Injection") - ## When to Use the Dependency Injection Pattern in Java * When aiming to reduce the coupling between classes and increase the modularity of the application. From 7d2e6262cc91a5385c670f35bab9f5a4d59a8ca9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 10:01:53 +0300 Subject: [PATCH 012/108] build(deps): bump com.mycila:license-maven-plugin from 4.6 to 5.0.0 (#3268) Bumps [com.mycila:license-maven-plugin](https://github.com/mathieucarbou/license-maven-plugin) from 4.6 to 5.0.0. - [Release notes](https://github.com/mathieucarbou/license-maven-plugin/releases) - [Commits](https://github.com/mathieucarbou/license-maven-plugin/compare/license-maven-plugin-4.6...v5.0.0) --- updated-dependencies: - dependency-name: com.mycila:license-maven-plugin dependency-version: 5.0.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> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20f468706502..d9667ed354d2 100644 --- a/pom.xml +++ b/pom.xml @@ -59,7 +59,7 @@ 3.5.2 - 4.6 + 5.0.0 3.14.0 From a62601a64f3f200450e08a45d71edcedf70a8a53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 10:02:39 +0300 Subject: [PATCH 013/108] build(deps): bump com.fasterxml.jackson.core:jackson-core (#3270) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.18.2 to 2.19.0. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.18.2...jackson-core-2.19.0) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.19.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dynamic-proxy/pom.xml | 2 +- event-sourcing/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic-proxy/pom.xml b/dynamic-proxy/pom.xml index 586dbc1b6ab4..decbb24fd02d 100644 --- a/dynamic-proxy/pom.xml +++ b/dynamic-proxy/pom.xml @@ -46,7 +46,7 @@ com.fasterxml.jackson.core jackson-core - 2.18.2 + 2.19.0 com.fasterxml.jackson.core diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 4cfd05d7adac..5660054d8195 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -50,7 +50,7 @@ com.fasterxml.jackson.core jackson-core - 2.18.2 + 2.19.0 com.fasterxml.jackson.core From 0da4dcda5b3af64b071a71f766c6ed54bcbf10cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 2 May 2025 21:55:32 +0300 Subject: [PATCH 014/108] docs: update producer-consumer --- producer-consumer/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/producer-consumer/README.md b/producer-consumer/README.md index bb62c799a08f..575be804cd45 100644 --- a/producer-consumer/README.md +++ b/producer-consumer/README.md @@ -181,10 +181,6 @@ Program output: 08:10:17.483 [pool-1-thread-5] INFO com.iluwatar.producer.consumer.Consumer -- Consumer [Consumer_2] consume item [10] produced by [Producer_1] ``` -## Detailed Explanation of Producer-Consumer Pattern with Real-World Examples - -![Producer-Consumer](./etc/producer-consumer.png "Producer-Consumer") - ## When to Use the Producer-Consumer Pattern in Java * When you need to manage a buffer or queue where producers add data and consumers take data, often in a multithreaded environment. From 3ac1a36b058864b5fcd6fb9e42435f8fe7799591 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 2 May 2025 22:02:40 +0300 Subject: [PATCH 015/108] docs: update prototype --- prototype/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/prototype/README.md b/prototype/README.md index 48f10868a86c..b97df0707ffc 100644 --- a/prototype/README.md +++ b/prototype/README.md @@ -156,10 +156,6 @@ Here's the console output from running the example. 08:36:19.014 [main] INFO com.iluwatar.prototype.App -- Orcish wolf attacks with laser ``` -## Detailed Explanation of Prototype Pattern with Real-World Examples - -![alt text](./etc/prototype.urm.png "Prototype pattern class diagram") - ## When to Use the Prototype Pattern in Java * When the classes to instantiate are specified at run-time, for example, by dynamic loading. From 8529017e025e4b0c8887730b5204926ef410f629 Mon Sep 17 00:00:00 2001 From: yoobin_mion <113106136+yybmion@users.noreply.github.com> Date: Fri, 16 May 2025 03:53:37 +0900 Subject: [PATCH 016/108] feat: Implement Thread-Pool Executor pattern (#3271) - Add implementation of Thread-Pool Executor pattern using hotel front desk example - Include unit tests - Create detailed README with pattern explanation and examples - Add Java source code with appropriate Javadoc comments Closes #3226 --- pom.xml | 1 + thread-pool-executor/README.md | 200 ++++++++++++++ .../etc/thread-pool-executor.urm.png | Bin 0 -> 86163 bytes .../etc/thread-pool-executor.urm.puml | 66 +++++ thread-pool-executor/pom.xml | 83 ++++++ .../com/iluwatar/threadpoolexecutor/App.java | 90 +++++++ .../threadpoolexecutor/FrontDeskService.java | 108 ++++++++ .../threadpoolexecutor/GuestCheckInTask.java | 52 ++++ .../VipGuestCheckInTask.java | 52 ++++ .../iluwatar/threadpoolexecutor/AppTest.java | 38 +++ .../FrontDeskServiceTest.java | 248 ++++++++++++++++++ .../GuestCheckInTaskTest.java | 55 ++++ .../VipGuestCheckInTaskTest.java | 48 ++++ 13 files changed, 1041 insertions(+) create mode 100644 thread-pool-executor/README.md create mode 100644 thread-pool-executor/etc/thread-pool-executor.urm.png create mode 100644 thread-pool-executor/etc/thread-pool-executor.urm.puml create mode 100644 thread-pool-executor/pom.xml create mode 100644 thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/App.java create mode 100644 thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/FrontDeskService.java create mode 100644 thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/GuestCheckInTask.java create mode 100644 thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTask.java create mode 100644 thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/AppTest.java create mode 100644 thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/FrontDeskServiceTest.java create mode 100644 thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/GuestCheckInTaskTest.java create mode 100644 thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTaskTest.java diff --git a/pom.xml b/pom.xml index d9667ed354d2..8337c97966da 100644 --- a/pom.xml +++ b/pom.xml @@ -231,6 +231,7 @@ table-module template-method templateview + thread-pool-executor throttling tolerant-reader trampoline diff --git a/thread-pool-executor/README.md b/thread-pool-executor/README.md new file mode 100644 index 000000000000..fa1d5a2c8062 --- /dev/null +++ b/thread-pool-executor/README.md @@ -0,0 +1,200 @@ +--- +title: "Thread-Pool Executor Pattern in Java: Efficient Concurrent Task Management" +shortTitle: Thread-Pool Executor +description: "Learn the Thread-Pool Executor pattern in Java with practical examples, class +diagrams, and implementation details. Understand how to manage concurrent tasks efficiently, +improving resource utilization and application performance." +category: Concurrency +language: en +tag: + +- Performance +- Resource Management +- Concurrency +- Multithreading +- Scalability + +--- + +## Intent of Thread-Pool Executor Design Pattern + +The Thread-Pool Executor pattern maintains a pool of worker threads to execute tasks concurrently, +optimizing resource usage by reusing existing threads instead of creating new ones for each task. + +## Detailed Explanation of Thread-Pool Executor Pattern with Real-World Examples + +### Real-world example + +> Imagine a busy airport security checkpoint where instead of opening a new lane for each traveler, +> a fixed number of security lanes (threads) are open to process all passengers. Each security +> officer (thread) processes one passenger (task) at a time, and when finished, immediately calls the +> next passenger in line. During peak travel times, passengers wait in a queue, but the system is much +> more efficient than trying to open a new security lane for each individual traveler. The airport can +> handle fluctuating passenger traffic throughout the day with consistent staffing, optimizing both +> resource utilization and passenger throughput. + +### In plain words + +> Thread-Pool Executor keeps a set of reusable threads that process multiple tasks throughout their +> lifecycle, rather than creating a new thread for each task. + +### Wikipedia says + +> A thread pool is a software design pattern for achieving concurrency of execution in a computer +> program. Often also called a replicated workers or worker-crew model, a thread pool maintains +> multiple threads waiting for tasks to be allocated for concurrent execution by the supervising +> program. + +### Class diagram + +![Thread-pool-executor Class diagram](./etc/thread-pool-executor.urm.png) + +## Programmatic Example of Thread-Pool Executor Pattern in Java + +Imagine a hotel front desk. + +The number of employees (thread pool) is limited, but guests (tasks) keep arriving endlessly. + +The Thread-Pool Executor pattern efficiently handles a large number of requests by reusing a small +set of threads. + +```java +@Slf4j +public class HotelFrontDesk { + public static void main(String[] args) throws InterruptedException, ExecutionException { + // Hire 3 front desk employees (threads) + ExecutorService frontDesk = Executors.newFixedThreadPool(3); + + LOGGER.info("Hotel front desk operation started!"); + + // 7 regular guests checking in (Runnable) + for (int i = 1; i <= 7; i++) { + String guestName = "Guest-" + i; + frontDesk.submit(() -> { + String employeeName = Thread.currentThread().getName(); + LOGGER.info("{} is checking in {}...", employeeName, guestName); + try { + Thread.sleep(2000); // Simulate check-in time + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + LOGGER.info("{} has been successfully checked in!", guestName); + }); + } + + // 3 VIP guests checking in (Callable with result) + Callable vipGuest1 = createVipGuest("VIP-Guest-1"); + Callable vipGuest2 = createVipGuest("VIP-Guest-2"); + Callable vipGuest3 = createVipGuest("VIP-Guest-3"); + + Future vipResult1 = frontDesk.submit(vipGuest1); + Future vipResult2 = frontDesk.submit(vipGuest2); + Future vipResult3 = frontDesk.submit(vipGuest3); + + // Shutdown after submitting all tasks + frontDesk.shutdown(); + + if (frontDesk.awaitTermination(1, TimeUnit.HOURS)) { + // Print VIP guests' check-in results + LOGGER.info("VIP Check-in Results:"); + LOGGER.info(vipResult1.get()); + LOGGER.info(vipResult2.get()); + LOGGER.info(vipResult3.get()); + LOGGER.info("All guests have been successfully checked in. Front desk is now closed."); + } else { + LOGGER.info("Check-in timeout. Forcefully shutting down the front desk."); + } + } + + private static Callable createVipGuest(String vipGuestName) { + return () -> { + String employeeName = Thread.currentThread().getName(); + LOGGER.info("{} is checking in VIP guest {}...", employeeName, vipGuestName); + Thread.sleep(1000); // VIPs are faster to check in + return vipGuestName + " has been successfully checked in!"; + }; + } +} +``` + +Here's the console output: + +```markdown +Hotel front desk operation started! +pool-1-thread-3 is checking in Guest-3... +pool-1-thread-2 is checking in Guest-2... +pool-1-thread-1 is checking in Guest-1... +Guest-2 has been successfully checked in! +Guest-1 has been successfully checked in! +Guest-3 has been successfully checked in! +pool-1-thread-2 is checking in Guest-5... +pool-1-thread-3 is checking in Guest-4... +pool-1-thread-1 is checking in Guest-6... +Guest-5 has been successfully checked in! +pool-1-thread-2 is checking in Guest-7... +Guest-4 has been successfully checked in! +pool-1-thread-3 is checking in VIP guest VIP-Guest-1... +Guest-6 has been successfully checked in! +pool-1-thread-1 is checking in VIP guest VIP-Guest-2... +pool-1-thread-3 is checking in VIP guest VIP-Guest-3... +Guest-7 has been successfully checked in! +VIP Check-in Results: +VIP-Guest-1 has been successfully checked in! +VIP-Guest-2 has been successfully checked in! +VIP-Guest-3 has been successfully checked in! +All guests have been successfully checked in. Front desk is now closed. +``` + +**Note:** Since this example demonstrates asynchronous thread execution, **the actual output may vary between runs**. The order of execution and timing can differ due to thread scheduling, system load, and other factors that affect concurrent processing. The core behavior of the thread pool (limiting concurrent tasks to the number of threads and reusing threads) will remain consistent, but the exact sequence of log messages may change with each execution. + +## When to Use the Thread-Pool Executor Pattern in Java + +* When you need to limit the number of threads running simultaneously to avoid resource exhaustion +* For applications that process a large number of short-lived independent tasks +* To improve performance by reducing thread creation/destruction overhead +* When implementing server applications that handle multiple client requests concurrently +* To execute recurring tasks at fixed rates or with fixed delays + +## Thread-Pool Executor Pattern Java Tutorial + +* [Thread-Pool Executor Pattern Tutorial (Baeldung)](https://www.baeldung.com/thread-pool-java-and-guava) + +## Real-World Applications of Thread-Pool Executor Pattern in Java + +* Application servers like Tomcat and Jetty use thread pools to handle HTTP requests +* Database connection pools in JDBC implementations +* Background job processing frameworks like Spring Batch +* Task scheduling systems like Quartz Scheduler +* Java EE's Managed Executor Service for enterprise applications + +## Benefits and Trade-offs of Thread-Pool Executor Pattern + +### Benefits + +* Improves performance by reusing existing threads instead of creating new ones +* Provides better resource management by limiting the number of active threads +* Simplifies thread lifecycle management and cleanup +* Facilitates easy implementation of task prioritization and scheduling +* Enhances application stability by preventing resource exhaustion + +### Trade-offs + +* May lead to thread starvation if improperly configured (too few threads) +* Potential for resource underutilization if improperly sized (too many threads) +* Requires careful shutdown handling to prevent task loss or resource leaks + +## Related Java Design Patterns + +* [Master-Worker Pattern](https://java-design-patterns.com/patterns/master-worker/): Tasks between a + master and multiple workers. +* [Producer-Consumer Pattern](https://java-design-patterns.com/patterns/producer-consumer/): + Separates task production and task consumption, typically using a blocking queue. +* [Object Pool Pattern](https://java-design-patterns.com/patterns/object-pool/): Reuses a set of + objects (e.g., threads) instead of creating/destroying them repeatedly. + +## References and Credits + +* [Java Documentation for ThreadPoolExecutor](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/ThreadPoolExecutor.html) +* [Java Concurrency in Practice](https://jcip.net/) by Brian Goetz +* [Effective Java](https://www.oreilly.com/library/view/effective-java-3rd/9780134686097/) by Joshua + Bloch diff --git a/thread-pool-executor/etc/thread-pool-executor.urm.png b/thread-pool-executor/etc/thread-pool-executor.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..d426343f81712c249e609e27f433194a9b339479 GIT binary patch literal 86163 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%0AN&-T#}*(_KYE5EIwfo} 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 L=3J)G1=s%z2PWA^ literal 0 HcmV?d00001 diff --git a/thread-pool-executor/etc/thread-pool-executor.urm.puml b/thread-pool-executor/etc/thread-pool-executor.urm.puml new file mode 100644 index 000000000000..ca83f40c1b40 --- /dev/null +++ b/thread-pool-executor/etc/thread-pool-executor.urm.puml @@ -0,0 +1,66 @@ +@startuml + +interface Runnable { + +run(): void +} + +interface Callable { + +call(): T +} + +interface ExecutorService { + +submit(task: Runnable): Future + +submit(task: Callable): Future + +shutdown(): void + +awaitTermination(timeout: long, unit: TimeUnit): boolean +} + +class ThreadPoolExecutor { + -corePoolSize: int + -maximumPoolSize: int + -keepAliveTime: long + -workQueue: BlockingQueue + +execute(task: Runnable): void + +submit(task: Callable): Future +} + +class ThreadPoolManager { + -executorService: ExecutorService + +ThreadPoolManager(numThreads: int) + +submitTask(task: Runnable): void + +submitCallable(task: Callable): Future + +shutdown(): void + +awaitTermination(timeout: long, unit: TimeUnit): boolean +} + +class Task { + -id: int + -name: String + -processingTime: long + +Task(id: int, name: String, processingTime: long) + +run(): void + +call(): TaskResult +} + +class TaskResult { + -taskId: int + -taskName: String + -executionTime: long + +TaskResult(taskId: int, taskName: String, executionTime: long) +} + +class App { + +main(args: String[]): void + -executeRunnableTasks(poolManager: ThreadPoolManager): void + -executeCallableTasks(poolManager: ThreadPoolManager): void +} + +ExecutorService <|-- ThreadPoolExecutor : implements +Task ..|> Runnable : implements +Task ..|> Callable : implements +Task --> TaskResult : produces +ThreadPoolManager --> ExecutorService : wraps +App --> ThreadPoolManager : uses +App --> Task : creates + +@enduml \ No newline at end of file diff --git a/thread-pool-executor/pom.xml b/thread-pool-executor/pom.xml new file mode 100644 index 000000000000..f77cd92c67aa --- /dev/null +++ b/thread-pool-executor/pom.xml @@ -0,0 +1,83 @@ + + + + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + thread-pool-executor + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.threadpoolexecutor.App + + + + + + + + + diff --git a/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/App.java b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/App.java new file mode 100644 index 000000000000..0c1292b89c3a --- /dev/null +++ b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/App.java @@ -0,0 +1,90 @@ +/* + * 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.threadpoolexecutor; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; + +/** + * The Thread-Pool Executor pattern demonstrates how a pool of worker threads can be used to execute + * tasks concurrently. This pattern is particularly useful in scenarios where you need to execute a + * large number of independent tasks and want to limit the number of threads used. + * + *

In this example, a hotel front desk with a fixed number of employees processes guest + * check-ins. Each employee is represented by a thread, and each check-in is a task. + * + *

Key benefits demonstrated: + * + *

+ */ +@Slf4j +public class App { + + /** + * Program main entry point. + * + * @param args program runtime arguments + */ + public static void main(String[] args) throws InterruptedException, ExecutionException { + + FrontDeskService frontDesk = new FrontDeskService(5); + LOGGER.info("Hotel front desk operation started!"); + + LOGGER.info("Processing 30 regular guest check-ins..."); + for (int i = 1; i <= 30; i++) { + frontDesk.submitGuestCheckIn(new GuestCheckInTask("Guest-" + i)); + Thread.sleep(100); + } + + LOGGER.info("Processing 3 VIP guest check-ins..."); + List> vipResults = new ArrayList<>(); + + for (int i = 1; i <= 3; i++) { + Future result = + frontDesk.submitVipGuestCheckIn(new VipGuestCheckInTask("VIP-Guest-" + i)); + vipResults.add(result); + } + + frontDesk.shutdown(); + + if (frontDesk.awaitTermination(1, TimeUnit.HOURS)) { + LOGGER.info("VIP Check-in Results:"); + for (Future result : vipResults) { + LOGGER.info(result.get()); + } + LOGGER.info("All guests have been successfully checked in. Front desk is now closed."); + } else { + LOGGER.warn("Check-in timeout. Forcefully shutting down the front desk."); + } + } +} diff --git a/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/FrontDeskService.java b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/FrontDeskService.java new file mode 100644 index 000000000000..b80236ee5ecf --- /dev/null +++ b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/FrontDeskService.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.threadpoolexecutor; + +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 lombok.extern.slf4j.Slf4j; + +/** + * FrontDeskService represents the hotel's front desk with a fixed number of employees. This class + * demonstrates the Thread-Pool Executor pattern using Java's ExecutorService. + */ +@Slf4j +public class FrontDeskService { + + private final ExecutorService executorService; + private final int numberOfEmployees; + + /** + * Creates a new front desk with the specified number of employees. + * + * @param numberOfEmployees the number of employees (threads) at the front desk + */ + public FrontDeskService(int numberOfEmployees) { + this.numberOfEmployees = numberOfEmployees; + this.executorService = Executors.newFixedThreadPool(numberOfEmployees); + LOGGER.info("Front desk initialized with {} employees.", numberOfEmployees); + } + + /** + * Submits a regular guest check-in task to an available employee. + * + * @param task the check-in task to submit + * @return a Future representing pending completion of the task + */ + public Future submitGuestCheckIn(Runnable task) { + LOGGER.debug("Submitting regular guest check-in task"); + return executorService.submit(task, null); + } + + /** + * Submits a VIP guest check-in task to an available employee. + * + * @param task the VIP check-in task to submit + * @param the type of the task's result + * @return a Future representing pending completion of the task + */ + public Future submitVipGuestCheckIn(Callable task) { + LOGGER.debug("Submitting VIP guest check-in task"); + return executorService.submit(task); + } + + /** + * Closes the front desk after all currently checked-in guests are processed. No new check-ins + * will be accepted. + */ + public void shutdown() { + LOGGER.info("Front desk is closing - no new guests will be accepted."); + executorService.shutdown(); + } + + /** + * Waits for all check-in processes to complete or until timeout. + * + * @param timeout the maximum time to wait + * @param unit the time unit of the timeout argument + * @return true if all tasks completed, false if timeout elapsed + * @throws InterruptedException if interrupted while waiting + */ + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + LOGGER.info("Waiting for all check-ins to complete (max wait: {} {})", timeout, unit); + return executorService.awaitTermination(timeout, unit); + } + + /** + * Gets the number of employees at the front desk. + * + * @return the number of employees + */ + public int getNumberOfEmployees() { + return numberOfEmployees; + } +} diff --git a/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/GuestCheckInTask.java b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/GuestCheckInTask.java new file mode 100644 index 000000000000..d8a33fdfc8d2 --- /dev/null +++ b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/GuestCheckInTask.java @@ -0,0 +1,52 @@ +/* + * 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.threadpoolexecutor; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * GuestCheckInTask represents a regular guest check-in process. Implements Runnable because it + * performs an action without returning a result. + */ +@Slf4j +@AllArgsConstructor +public class GuestCheckInTask implements Runnable { + + private final String guestName; + + @Override + public void run() { + String employeeName = Thread.currentThread().getName(); + LOGGER.info("{} is checking in {}...", employeeName, guestName); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.error("Check-in for {} was interrupted", guestName); + } + LOGGER.info("{} has been successfully checked in!", guestName); + } +} diff --git a/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTask.java b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTask.java new file mode 100644 index 000000000000..3948c114f0d6 --- /dev/null +++ b/thread-pool-executor/src/main/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTask.java @@ -0,0 +1,52 @@ +/* + * 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.threadpoolexecutor; + +import java.util.concurrent.Callable; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * VipGuestCheckInTask represents a VIP guest check-in process. Implements Callable because it + * returns a result (check-in confirmation). + */ +@Slf4j +@AllArgsConstructor +public class VipGuestCheckInTask implements Callable { + + private final String vipGuestName; + + @Override + public String call() throws Exception { + String employeeName = Thread.currentThread().getName(); + LOGGER.info("{} is checking in VIP guest {}...", employeeName, vipGuestName); + + Thread.sleep(1000); + + String result = vipGuestName + " has been successfully checked in!"; + LOGGER.info("VIP check-in completed: {}", result); + return result; + } +} diff --git a/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/AppTest.java b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/AppTest.java new file mode 100644 index 000000000000..13e3a5beec3c --- /dev/null +++ b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/AppTest.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.threadpoolexecutor; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void appStartsWithoutException() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/FrontDeskServiceTest.java b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/FrontDeskServiceTest.java new file mode 100644 index 000000000000..8d0396bf0541 --- /dev/null +++ b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/FrontDeskServiceTest.java @@ -0,0 +1,248 @@ +/* + * 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.threadpoolexecutor; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +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 java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +class FrontDeskServiceTest { + + /** + * Tests that the constructor correctly sets the number of employees (threads). This verifies the + * basic initialization of the thread pool. + */ + @Test + void testConstructorSetsCorrectNumberOfEmployees() { + int expectedEmployees = 3; + + FrontDeskService frontDesk = new FrontDeskService(expectedEmployees); + + assertEquals(expectedEmployees, frontDesk.getNumberOfEmployees()); + } + + /** + * Tests that the submitGuestCheckIn method returns a non-null Future object. This verifies the + * basic task submission functionality. + */ + @Test + void testSubmitGuestCheckInReturnsNonNullFuture() { + FrontDeskService frontDesk = new FrontDeskService(1); + + Runnable task = + () -> { + // Task that completes quickly + }; + + Future future = frontDesk.submitGuestCheckIn(task); + + assertNotNull(future); + } + + /** + * Tests that the submitVipGuestCheckIn method returns a non-null Future object. This verifies + * that tasks with return values can be submitted correctly. + */ + @Test + void testSubmitVipGuestCheckInReturnsNonNullFuture() { + FrontDeskService frontDesk = new FrontDeskService(1); + Callable task = () -> "VIP Check-in complete"; + + Future future = frontDesk.submitVipGuestCheckIn(task); + + assertNotNull(future); + } + + /** + * Tests that the shutdown and awaitTermination methods work correctly. This verifies the basic + * shutdown functionality of the thread pool. + */ + @Test + void testShutdownAndAwaitTermination() throws InterruptedException { + FrontDeskService frontDesk = new FrontDeskService(2); + CountDownLatch taskLatch = new CountDownLatch(1); + + Runnable task = taskLatch::countDown; + + frontDesk.submitGuestCheckIn(task); + frontDesk.shutdown(); + boolean terminated = frontDesk.awaitTermination(1, TimeUnit.SECONDS); + + assertTrue(terminated); + assertTrue(taskLatch.await(100, TimeUnit.MILLISECONDS)); + } + + /** + * Tests the thread pool's behavior under load with multiple tasks. This verifies that the thread + * pool limits concurrent execution to the number of threads, all submitted tasks are eventually + * completed, and threads are reused for multiple tasks. + */ + @Test + void testMultipleTasksUnderLoad() throws InterruptedException { + FrontDeskService frontDesk = new FrontDeskService(2); + int taskCount = 10; + CountDownLatch tasksCompletedLatch = new CountDownLatch(taskCount); + AtomicInteger concurrentTasks = new AtomicInteger(0); + AtomicInteger maxConcurrentTasks = new AtomicInteger(0); + + for (int i = 0; i < taskCount; i++) { + frontDesk.submitGuestCheckIn( + () -> { + try { + int current = concurrentTasks.incrementAndGet(); + maxConcurrentTasks.updateAndGet(max -> Math.max(max, current)); + + Thread.sleep(100); + + concurrentTasks.decrementAndGet(); + tasksCompletedLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + boolean allTasksCompleted = tasksCompletedLatch.await(2, TimeUnit.SECONDS); + + frontDesk.shutdown(); + frontDesk.awaitTermination(1, TimeUnit.SECONDS); + + assertTrue(allTasksCompleted); + assertEquals(2, maxConcurrentTasks.get()); + assertEquals(0, concurrentTasks.get()); + } + + /** + * Tests proper shutdown behavior under load. This verifies that after shutdown no new tasks are + * accepted, all previously submitted tasks are completed, and the executor terminates properly + * after all tasks complete. + */ + @Test + void testProperShutdownUnderLoad() throws InterruptedException { + FrontDeskService frontDesk = new FrontDeskService(2); + int taskCount = 5; + CountDownLatch startedTasksLatch = new CountDownLatch(2); + CountDownLatch tasksCompletionLatch = new CountDownLatch(taskCount); + + for (int i = 0; i < taskCount; i++) { + frontDesk.submitGuestCheckIn( + () -> { + try { + startedTasksLatch.countDown(); + Thread.sleep(100); + tasksCompletionLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + } + + assertTrue(startedTasksLatch.await(1, TimeUnit.SECONDS)); + + frontDesk.shutdown(); + + assertThrows( + RejectedExecutionException.class, + () -> { + frontDesk.submitGuestCheckIn(() -> {}); + }); + + boolean allTasksCompleted = tasksCompletionLatch.await(2, TimeUnit.SECONDS); + + boolean terminated = frontDesk.awaitTermination(1, TimeUnit.SECONDS); + + assertTrue(allTasksCompleted); + assertTrue(terminated); + } + + /** + * Tests concurrent execution of different task types (regular and VIP). This verifies that both + * Runnable and Callable tasks can be processed concurrently, all tasks complete successfully, and + * Callable tasks return their results correctly. + */ + @Test + void testConcurrentRegularAndVipTasks() throws Exception { + FrontDeskService frontDesk = new FrontDeskService(3); + int regularTaskCount = 4; + int vipTaskCount = 3; + CountDownLatch allTasksLatch = new CountDownLatch(regularTaskCount + vipTaskCount); + + List> regularResults = new ArrayList<>(); + for (int i = 0; i < regularTaskCount; i++) { + Future result = + frontDesk.submitGuestCheckIn( + () -> { + try { + Thread.sleep(50); + allTasksLatch.countDown(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + }); + regularResults.add(result); + } + + List> vipResults = new ArrayList<>(); + for (int i = 0; i < vipTaskCount; i++) { + final int guestNum = i; + Future result = + frontDesk.submitVipGuestCheckIn( + () -> { + Thread.sleep(25); + allTasksLatch.countDown(); + return "VIP-" + guestNum + " checked in"; + }); + vipResults.add(result); + } + + boolean allCompleted = allTasksLatch.await(2, TimeUnit.SECONDS); + + frontDesk.shutdown(); + frontDesk.awaitTermination(1, TimeUnit.SECONDS); + + assertTrue(allCompleted); + + for (Future result : regularResults) { + assertTrue(result.isDone()); + } + + for (int i = 0; i < vipTaskCount; i++) { + Future result = vipResults.get(i); + assertTrue(result.isDone()); + assertEquals("VIP-" + i + " checked in", result.get()); + } + } +} diff --git a/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/GuestCheckInTaskTest.java b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/GuestCheckInTaskTest.java new file mode 100644 index 000000000000..27bb75efd2db --- /dev/null +++ b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/GuestCheckInTaskTest.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.threadpoolexecutor; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.atomic.AtomicReference; +import org.junit.jupiter.api.Test; + +class GuestCheckInTaskTest { + + /** + * Tests that the task executes in the current thread when called directly. This verifies that the + * thread name inside the task matches the calling thread. + */ + @Test + void testThreadNameInTask() { + String guestName = "TestGuest"; + AtomicReference capturedThreadName = new AtomicReference<>(); + + GuestCheckInTask task = + new GuestCheckInTask(guestName) { + @Override + public void run() { + capturedThreadName.set(Thread.currentThread().getName()); + } + }; + + task.run(); + + assertEquals(Thread.currentThread().getName(), capturedThreadName.get()); + } +} diff --git a/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTaskTest.java b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTaskTest.java new file mode 100644 index 000000000000..d76d90625c95 --- /dev/null +++ b/thread-pool-executor/src/test/java/com/iluwatar/threadpoolexecutor/VipGuestCheckInTaskTest.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.threadpoolexecutor; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +class VipGuestCheckInTaskTest { + + /** + * Tests that the call method returns the expected result string. This verifies that the VIP + * check-in task correctly formats its result message. + */ + @Test + void testCallReturnsExpectedResult() throws Exception { + String vipGuestName = "TestVipGuest"; + VipGuestCheckInTask task = new VipGuestCheckInTask(vipGuestName); + + String result = task.call(); + + assertNotNull(result); + assertEquals("TestVipGuest has been successfully checked in!", result); + } +} From bf164009b4e1c0a3093ebcbaf1d6424d013a4ab4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 15 May 2025 21:55:54 +0300 Subject: [PATCH 017/108] docs: add yybmion as a contributor for code (#3279) * 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 9509bc095ae7..25ecf853dee3 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3520,6 +3520,15 @@ "contributions": [ "translation" ] + }, + { + "login": "yybmion", + "name": "yoobin_mion", + "avatar_url": "https://avatars.githubusercontent.com/u/113106136?v=4", + "profile": "https://github.com/yybmion", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index c2c3a5c7af10..5b003cc394ea 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-386-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-387-orange.svg?style=flat-square)](#contributors-)
@@ -575,6 +575,7 @@ This project is licensed under the terms of the MIT license.
e5LA
e5LA

💻 Maziyar Gerami
Maziyar Gerami

🌍 + yoobin_mion
yoobin_mion

💻 From f6bb51581f6d2f0e5c643e5e1cc93d9987e96b72 Mon Sep 17 00:00:00 2001 From: e5LA <208197507+e5LA@users.noreply.github.com> Date: Sat, 17 May 2025 07:53:25 +0200 Subject: [PATCH 018/108] chore: adding missing license (#3273) Co-authored-by: SP --- .../com/iluwatar/leaderfollowers/App.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java index 28b039cc7738..88ff5c55fa56 100644 --- a/leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java +++ b/leader-followers/src/main/java/com/iluwatar/leaderfollowers/App.java @@ -1,3 +1,27 @@ +/* + * 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.leaderfollowers; import java.security.SecureRandom; From ede37bd05568b1b8b814d8e9a1d2bbd71d9d615d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 17 May 2025 08:55:06 +0300 Subject: [PATCH 019/108] docs: add e5LA as a contributor for doc (#3281) * 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 | 3 ++- README.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 25ecf853dee3..32f5734184c4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3509,7 +3509,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/208197507?v=4", "profile": "https://github.com/e5LA", "contributions": [ - "code" + "code", + "doc" ] }, { diff --git a/README.md b/README.md index 5b003cc394ea..2c2e375bf4f9 100644 --- a/README.md +++ b/README.md @@ -573,7 +573,7 @@ This project is licensed under the terms of the MIT license. ssrijan-007-sys
ssrijan-007-sys

💻 - e5LA
e5LA

💻 + e5LA
e5LA

💻 📖 Maziyar Gerami
Maziyar Gerami

🌍 yoobin_mion
yoobin_mion

💻 From 98d3601b1e5cceebc4b4a00479633e9addda7459 Mon Sep 17 00:00:00 2001 From: Soumik Sarker Date: Sun, 18 Jan 2026 01:28:23 +0600 Subject: [PATCH 020/108] docs: Formatted spacing and updated documentation (#3290) * Refactored redundant spacing in pom.xml * Updated documentation of remove subscriber in publish-subscribe model --- pom.xml | 6 +++--- .../java/com/iluwatar/publish/subscribe/model/Topic.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 8337c97966da..e91832d03358 100644 --- a/pom.xml +++ b/pom.xml @@ -231,7 +231,7 @@ table-module template-method templateview - thread-pool-executor + thread-pool-executor throttling tolerant-reader trampoline @@ -244,8 +244,8 @@ version-number virtual-proxy visitor - backpressure - actor-model + backpressure + actor-model diff --git a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/model/Topic.java b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/model/Topic.java index 4c421afe735a..2011f096a5eb 100644 --- a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/model/Topic.java +++ b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/model/Topic.java @@ -51,7 +51,7 @@ public void addSubscriber(Subscriber subscriber) { } /** - * Remove a subscriber to the list of subscribers. + * Remove a subscriber from the list of subscribers. * * @param subscriber subscriber to remove */ From 0ab60190eaac8c85e52c855b24a52a81a353e667 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 17 Jan 2026 21:31:13 +0200 Subject: [PATCH 021/108] docs: add ronodhirSoumik as a contributor for doc (#3418) * 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 32f5734184c4..90ce80d3a163 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3530,6 +3530,15 @@ "contributions": [ "code" ] + }, + { + "login": "ronodhirSoumik", + "name": "Soumik Sarker", + "avatar_url": "https://avatars.githubusercontent.com/u/46843689?v=4", + "profile": "https://ronodhirsoumik.github.io", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 2c2e375bf4f9..bfcdd0f63dbf 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-387-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-388-orange.svg?style=flat-square)](#contributors-)
@@ -576,6 +576,7 @@ This project is licensed under the terms of the MIT license. e5LA
e5LA

💻 📖 Maziyar Gerami
Maziyar Gerami

🌍 yoobin_mion
yoobin_mion

💻 + Soumik Sarker
Soumik Sarker

📖 From 08651d0a0098ad7d6691afe1150cb8babcd2d32f Mon Sep 17 00:00:00 2001 From: "ilkka.seppala" Date: Sat, 17 Jan 2026 21:45:31 +0200 Subject: [PATCH 022/108] chore: Update presubmit.ai configuration --- .github/workflows/presubmit.yml | 49 ++++++++++++++------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/.github/workflows/presubmit.yml b/.github/workflows/presubmit.yml index cac1250b70e8..bb0ed7e116ae 100644 --- a/.github/workflows/presubmit.yml +++ b/.github/workflows/presubmit.yml @@ -1,35 +1,28 @@ name: Presubmit.ai permissions: - contents: read - pull-requests: write - issues: write + contents: read + pull-requests: write + issues: write on: - pull_request_target: # Handle forked repository PRs in the base repository context - types: [opened, synchronize] - pull_request_review_comment: # Handle review comments - types: [created] + pull_request_target: + types: [opened, synchronize] + pull_request_review_comment: + types: [created] jobs: - review: - runs-on: ubuntu-latest - steps: - - name: Check required secrets - run: | - if [ -z "${{ secrets.LLM_API_KEY }}" ]; then - echo "Error: LLM_API_KEY secret is not configured" - exit 1 - fi - - - name: Check out PR code - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} - - - name: Run AI Reviewer - uses: presubmit/ai-reviewer@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - LLM_API_KEY: ${{ secrets.LLM_API_KEY }} - LLM_MODEL: "gemini-1.5-flash" + review: + runs-on: ubuntu-latest + steps: + - name: Check required secrets + run: | + if [ -z "${{ secrets.LLM_API_KEY }}" ]; then + echo "Error: LLM_API_KEY secret is not configured" + exit 1 + fi + - uses: presubmit/ai-reviewer@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LLM_API_KEY: ${{ secrets.LLM_API_KEY }} + LLM_MODEL: "gpt-5-nano" \ No newline at end of file From 3ba2560e094164bb162168192d49805e29cfb7ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:37:15 +0200 Subject: [PATCH 023/108] build(deps-dev): bump org.htmlunit:htmlunit from 4.7.0 to 4.17.0 (#3334) Bumps [org.htmlunit:htmlunit](https://github.com/HtmlUnit/htmlunit) from 4.7.0 to 4.17.0. - [Release notes](https://github.com/HtmlUnit/htmlunit/releases) - [Commits](https://github.com/HtmlUnit/htmlunit/compare/4.7.0...4.17.0) --- updated-dependencies: - dependency-name: org.htmlunit:htmlunit dependency-version: 4.17.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e91832d03358..661abe365a18 100644 --- a/pom.xml +++ b/pom.xml @@ -48,7 +48,7 @@ 0.8.13 1.4 - 4.7.0 + 4.17.0 2.11.0 6.0.0 1.1.0 From 812e4cd6a246b69941a6a763d89e1e1b4aa8d2b8 Mon Sep 17 00:00:00 2001 From: Naman Srivastava <82610773+naman-sriv@users.noreply.github.com> Date: Mon, 9 Feb 2026 00:10:07 +0530 Subject: [PATCH 024/108] feat: Microservices pattern : Self-Registration (#3245) * Services and information * README.md updated * unit tests added for controllers * pom.xml, clean up, java version update and slf4j logging added * pom files updated * Removed children maven wrappers * Microservice-self-registration added to pom file * POM file updated for self-registration * pom file updated * Update pom.xml correction to mudule name * SonarQube comments addressed * sonarqube comments on coverage addressed * Code coverage for custom health checks * changes for unit tests * changes for unit tests * changes to for code coverage improvement --- microservices-self-registration/README.md | 236 ++++++++++++++++++ .../application.log.2025-04-09.0.gz | Bin 0 -> 5525 bytes .../contextservice/.gitattributes | 2 + .../contextservice/.gitignore | 33 +++ .../application.log.2025-04-05.0.gz | Bin 0 -> 1977 bytes .../application.log.2025-04-07.0.gz | Bin 0 -> 27133 bytes .../application.log.2025-04-09.0.gz | Bin 0 -> 37553 bytes .../contextservice/pom.xml | 73 ++++++ .../ContextserviceApplication.java | 17 ++ .../contextservice/MyCustomHealthCheck.java | 42 ++++ .../client/GreetingServiceClient.java | 11 + .../controller/ContextController.java | 26 ++ .../src/main/resources/application.yml | 25 ++ .../contextservice/ContextControllerTest.java | 49 ++++ .../ContextserviceApplicationTests.java | 17 ++ .../learning/contextservice/TestConfig.java | 17 ++ .../myCustomHealthCheckTest.java | 33 +++ .../eurekaserver/.gitattributes | 2 + .../eurekaserver/.gitignore | 33 +++ .../eurekaserver/pom.xml | 55 ++++ .../eurekaserver/EurekaserverApplication.java | 15 ++ .../src/main/resources/application.yml | 10 + .../EurekaserverApplicationTests.java | 17 ++ .../greetingservice/.gitattributes | 2 + .../greetingservice/.gitignore | 33 +++ .../application.log.2025-04-05.0.gz | Bin 0 -> 1893 bytes .../application.log.2025-04-07.0.gz | Bin 0 -> 6769 bytes .../application.log.2025-04-09.0.gz | Bin 0 -> 18884 bytes .../application.log.2025-04-11.0.gz | Bin 0 -> 121657 bytes .../greetingservice/pom.xml | 69 +++++ .../GreetingserviceApplication.java | 17 ++ .../greetingservice/MyCustomHealthCheck.java | 41 +++ .../controller/GreetingsController.java | 13 + .../src/main/resources/application.yml | 22 ++ .../GreetingserviceApplicationTests.java | 17 ++ .../MyCustomHealthCheckTest.java | 22 ++ .../controller/GreetingControllerTest.java | 36 +++ microservices-self-registration/pom.xml | 63 +++++ pom.xml | 1 + 39 files changed, 1049 insertions(+) create mode 100644 microservices-self-registration/README.md create mode 100644 microservices-self-registration/application.log.2025-04-09.0.gz create mode 100644 microservices-self-registration/contextservice/.gitattributes create mode 100644 microservices-self-registration/contextservice/.gitignore create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-05.0.gz create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-07.0.gz create mode 100644 microservices-self-registration/contextservice/application.log.2025-04-09.0.gz create mode 100644 microservices-self-registration/contextservice/pom.xml create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java create mode 100644 microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java create mode 100644 microservices-self-registration/contextservice/src/main/resources/application.yml create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java create mode 100644 microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java create mode 100644 microservices-self-registration/eurekaserver/.gitattributes create mode 100644 microservices-self-registration/eurekaserver/.gitignore create mode 100644 microservices-self-registration/eurekaserver/pom.xml create mode 100644 microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java create mode 100644 microservices-self-registration/eurekaserver/src/main/resources/application.yml create mode 100644 microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java create mode 100644 microservices-self-registration/greetingservice/.gitattributes create mode 100644 microservices-self-registration/greetingservice/.gitignore create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-07.0.gz create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-09.0.gz create mode 100644 microservices-self-registration/greetingservice/application.log.2025-04-11.0.gz create mode 100644 microservices-self-registration/greetingservice/pom.xml create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java create mode 100644 microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/controller/GreetingsController.java create mode 100644 microservices-self-registration/greetingservice/src/main/resources/application.yml create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java create mode 100644 microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java create mode 100644 microservices-self-registration/pom.xml diff --git a/microservices-self-registration/README.md b/microservices-self-registration/README.md new file mode 100644 index 000000000000..bfc837817c57 --- /dev/null +++ b/microservices-self-registration/README.md @@ -0,0 +1,236 @@ +--- +title: "Microservices Self-Registration Pattern in Java with Spring Boot and Eureka" +shortTitle: Microservices Pattern - Self-Registration +description: "Dynamically register and discover Java microservices using Spring Boot and Eureka for resilient, scalable communication." +category: Service Discovery +language: en +tag: + - Microservices + - Self-Registration + - Service Discovery + - Eureka + - Spring Boot + - Spring Cloud + - Java + - Dynamic Configuration + - Resilience +--- + +## Intent of Microservices Self-Registration Pattern + +The intent of the Self-Registration pattern is to enable microservices to automatically announce their presence and location to a central registry (like Eureka) upon startup, simplifying service discovery and allowing other services to find and communicate with them without manual configuration or hardcoded addresses. This promotes dynamic and resilient microservices architectures. + +## What's in the Project + +This project demonstrates the Microservices Self-Registration pattern using Java, Spring Boot (version 3.4.4), and Eureka for service discovery. It consists of three main components: a Eureka Server and two simple microservices, a Greeting Service and a Context Service, which discover and communicate with each other. + +### Project Structure +* **`eureka-server`:** The central service registry where microservices register themselves. +* **`greeting-service`:** A simple microservice that provides a greeting. +* **`context-service`:** A microservice that consumes the greeting from the Greeting Service and adds context. + + The **Eureka Server** acts as the discovery service. Microservices register themselves with the Eureka Server, providing their network location. + + package com.example.eurekaserver; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + + @SpringBootApplication + @EnableEurekaServer + public class EurekaServerApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaServerApplication.class, args); + } + } + + The **Greeting Service** is a simple microservice that exposes an endpoint to retrieve a greeting. + + package com.example.greetingservice; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + + @SpringBootApplication + @EnableDiscoveryClient + public class GreetingServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingServiceApplication.class, args); + } + } + + Greeting Controller + + package com.example.greetingservice.controller; + + import org.springframework.web.bind.annotation.GetMapping; + import org.springframework.web.bind.annotation.RestController; + + @RestController + public class GreetingController { + + @GetMapping("/greeting") + public String getGreeting() { + return "Hello"; + } + } + +The **Context Service** consumes the greeting from the Greeting Service using OpenFeign and adds contextual information. + + package com.example.contextservice; + + import org.springframework.boot.SpringApplication; + import org.springframework.boot.autoconfigure.SpringBootApplication; + import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + import org.springframework.cloud.openfeign.EnableFeignClients; + + @SpringBootApplication + @EnableDiscoveryClient + @EnableFeignClients + public class ContextServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(ContextServiceApplication.class, args); + } + } + + Feign Client : Spring Cloud OpenFeign is a declarative HTTP client that makes it easier to consume RESTful web services in your Spring Cloud applications. Instead of writing the boilerplate code for making HTTP requests, you simply declare interface with annotations that describe the web service you want to consume. + + package com.example.contextservice.client; + + import org.springframework.cloud.openfeign.FeignClient; + import org.springframework.web.bind.annotation.GetMapping; + + @FeignClient(name = "greeting-service") + public interface GreetingServiceClient { + + @GetMapping("/greeting") + String getGreeting(); + } + + Context Controller + + package com.example.contextservice.controller; + + import com.example.contextservice.client.GreetingServiceClient; + import org.springframework.beans.factory.annotation.Autowired; + import org.springframework.beans.factory.annotation.Value; + import org.springframework.web.bind.annotation.GetMapping; + import org.springframework.web.bind.annotation.RestController; + + @RestController + public class ContextController { + + @Autowired + private GreetingServiceClient greetingServiceClient; + + @Value("${user.region}") + private String userRegion; + + @GetMapping("/context") + public String getContext() { + String greeting = greetingServiceClient.getGreeting(); + return "The Greeting Service says: " + greeting + " from " + userRegion + "!"; + } + } + + 1. Both the Greeting Service and the Context Service register themselves with the Eureka Server upon startup using the _@EnableDiscoveryClient_ annotation. + 2. The Context Service, annotated with _@EnableFeignClients_, uses the GreetingServiceClient interface with _@FeignClient(name = "greeting-service")_ to declare its intent to communicate with the service named "greeting-service" in Eureka. + 3. When the /context endpoint of the Context Service is accessed, it calls the _getGreeting()_ method of the GreetingServiceClient. + 4. OpenFeign, leveraging the service discovery information from Eureka, resolves the network location of an available instance of the Greeting Service and makes an HTTP GET request to its /greeting endpoint. + 5. The Greeting Service responds with "Hello", and the Context Service then adds the configured user.region to the response. + + This project utilizes Spring Boot Actuator, which is included as a dependency, to provide health check endpoints for each microservice. These endpoints (e.g., /actuator/health) can be used by Eureka Server to monitor the health of the registered instances. + +## Steps to use for this Project + +Prerequisites: + - Java Development Kit (JDK): Make sure you have a compatible JDK installed (ideally Java 17 or later, as Spring Boot 3.x requires it). + - Maven or Gradle: You'll need either Maven (if you chose Maven during Spring Initializr setup) or Gradle (if you chose Gradle) installed on your system. + - An IDE (Optional but Recommended): IntelliJ IDEA, Eclipse, or Spring Tool Suite (STS) can make it easier to work with the project. + - Web Browser: You'll need a web browser to access the Eureka dashboard and the microservice endpoints. + +Step : + - You'll need to build each microservice individually. Navigate to the root directory of each project in your terminal or command prompt and run the appropriate build command: + _cd eurekaserver + mvn clean install + cd ../greetingservice + mvn clean install + cd ../contextservice + mvn clean install_ +Step : + - Navigate to the root directory of your eurekaserver project in your terminal or command prompt + _mvn spring-boot:run_ + - Wait for the Eureka Server application to start. You should see logs in the console indicating that it has started on port 8761 (as configured). + - Open your web browser and go to http://localhost:8761/. You should see the Eureka Server dashboard. Initially, the list of registered instances will be empty. +Step : + - Run the Greeting Service + - Open a new terminal or command prompt. + - Navigate to the root directory of your greetingservice project. + - Run the Spring Boot application: _mvn spring-boot:run_ + - Wait for the Greeting Service to start. You should see logs indicating that it has registered with the Eureka Server. + - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see GREETINGSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". +Step : + - Run the Context Service + - Open a new terminal or command prompt. + - Navigate to the root directory of your contextservice project. + - Run the Spring Boot application: _mvn spring-boot:run_ + - Wait for the Context Service to start. You should see logs indicating that it has registered with the Eureka Server. + - Go back to your Eureka Server dashboard in the browser (http://localhost:8761/). You should now see CONTEXTSERVICE listed under the "Instances currently registered with Eureka". Its status should be "UP". +STEP : + - Test the Greeting Service Directly: Open your web browser and go to http://localhost:8081/greeting. You should see the output: Hello. + - Test the Context Service (which calls the Greeting Service): Open your web browser and go to http://localhost:8082/context. You should see the output: The Greeting Service says: Hello from Chennai, Tamil Nadu, India!. This confirms that the Context Service successfully discovered and called the Greeting Service through Eureka. + +Optional: Check Health Endpoints + +You can also verify the health status of each service using Spring Boot Actuator: + - Greeting Service Health: http://localhost:8081/actuator/health (should return {"status":"UP"}) + - Context Service Health: http://localhost:8082/actuator/health (should return {"status":"UP"}) + - Eureka Server Health: http://localhost:8761/actuator/health (should return {"status":"UP"}) + +## When to use Microservices Self-Registration Pattern + + - **Dynamic Environments:** When your microservices are frequently deployed, scaled up or down, or their network locations (IP addresses and ports) change often. This is common in cloud-based or containerized environments (like Docker and Kubernetes). + - **Large Number of Services:** As the number of microservices in your system grows, manually managing their configurations and dependencies becomes complex and error-prone. Self-registration automates this process. + - **Need for Automatic Service** Discovery: When services need to find and communicate with each other without hardcoding network locations. This allows for greater flexibility and reduces coupling. + - **Implementing Load Balancing:** Service registries like Eureka often integrate with load balancers, enabling them to automatically distribute traffic across available instances of a service that have registered themselves. + - **Improving System Resilience:** If a service instance fails, the registry will eventually be updated (through heartbeats or health checks), and other services can discover and communicate with the remaining healthy instances. + - **DevOps Automation:** This pattern aligns well with DevOps practices, allowing for more automated deployment and management of microservices. + +## Real-World Applications of Self-Registration pattern + + - E-Commerce platforms have numerous independent services for product catalogs, order processing, payments, shipping, etc. Self-registration allows these services to dynamically discover and communicate with each other as the system scales during peak loads or as new features are deployed. + - Streaming services rely on many microservices for user authentication, content delivery networks (CDNs), recommendation engines, billing systems, etc. Self-registration helps these services adapt to varying user demands and infrastructure changes. + - Social media These platforms use microservices for managing user profiles, timelines, messaging, advertising, and more. Self-registration enables these services to scale independently and handle the massive traffic they experience. + +## Advantages + + - Microservices can dynamically locate and communicate with each other without needing to know their specific network addresses beforehand. This is crucial in dynamic environments where IP addresses and ports can change frequently. + - Reduces the need for manual configuration of service locations in each microservice. Services don't need to be updated every time another service's location changes. + - Scaling microservices up or down becomes easier. New instances automatically register themselves with the service registry, making them immediately discoverable by other services without manual intervention. + - If a service instance fails, it will eventually stop sending heartbeats to the registry and will be removed. Consumers can then discover and connect to other healthy instances, improving the system's overall resilience. + - Services are less tightly coupled as they don't have direct dependencies on the physical locations of other services. This makes deployments and updates more flexible. + - Service registries often integrate with load balancers. When a new service instance registers, the load balancer can automatically include it in the pool of available instances, distributing traffic effectively. + - Microservices can be deployed across different environments (development, testing, production) without significant changes to their discovery mechanism, as long as they are configured to connect to the appropriate service registry for that environment. + +## Trade-offs + + - Introducing a service registry adds another component to your system that needs to be set up, managed, and monitored. This increases the overall complexity of the infrastructure. + - The service registry itself becomes a critical component. If the service registry becomes unavailable, it can disrupt communication between microservices. High availability for the service registry is therefore essential. + - Microservices need to communicate with the service registry for registration, sending heartbeats, and querying for other services. This can lead to increased network traffic. + - There might be a slight delay between when a microservice instance starts and when it becomes fully registered and discoverable in the service registry. This needs to be considered, especially during scaling events. + - You need to consider how your microservices will behave if they fail to register with the service registry upon startup. Robust error handling and retry mechanisms are often necessary. + - Microservices need to include and configure client libraries (like the Eureka Discovery Client) to interact with the service registry. This adds a dependency to your application code. + - In distributed service registries, ensuring consistency of the registry data across all nodes can be a challenge. Different registries might have different consistency models (e.g., eventual consistency). + +## References + + - Microservices Patterns: https://microservices.io/ + - Eureka Documentation: https://github.com/Netflix/eureka | https://spring.io/projects/spring-cloud-netflix + - Spring Boot Documentation: https://spring.io/projects/spring-boot + - Spring Cloud OpenFeignDocumentation: https://spring.io/projects/spring-cloud-openfeign + - Spring Boot Actuator Documentation: https://www.baeldung.com/spring-boot-actuators \ No newline at end of file diff --git a/microservices-self-registration/application.log.2025-04-09.0.gz b/microservices-self-registration/application.log.2025-04-09.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..d51965d73d7a6d06bba18c80c7aeedb468916013 GIT binary patch literal 5525 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 literal 0 HcmV?d00001 diff --git a/microservices-self-registration/contextservice/.gitattributes b/microservices-self-registration/contextservice/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/contextservice/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/contextservice/.gitignore b/microservices-self-registration/contextservice/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/contextservice/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/contextservice/application.log.2025-04-05.0.gz b/microservices-self-registration/contextservice/application.log.2025-04-05.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..6ceb03b833a731820dda00c3b027f16241335466 GIT binary patch literal 1977 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 BD#8E& literal 0 HcmV?d00001 diff --git a/microservices-self-registration/contextservice/application.log.2025-04-09.0.gz b/microservices-self-registration/contextservice/application.log.2025-04-09.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..bd773dc8ba59d123795a9ea1518f8adf1e9e6e2e GIT binary patch literal 37553 zcmb@uWmsI>mNpvPA!u+2?(XjH?(XjHF2RCRxVyVML4sS*;O_2UWuM*Wbf4~f`@7F` z>&IJjjk$^iHHXc2jsZb5^rydGAE#X}&Z`pN`5$j&2VarW5be@X>U{t1#s&X~ym3 zTWv#0a_kG%9YK&qk&Qq9{_?3v&HnWLEcNaabi4;TO#J8M1{^zN3Kdh+u6ic^^fLE5 z!IISr7xI>Nx5cxpBjF})toP0JKFyj63IhI~kNjJ&fx6ivm!!?&YSegs&>Rn>#iZBj z*JcKq19#K%m1C7IiB2AUI$LWi@RSpZnUBdNK<_2!c$<2?bdAsRyZ&%+-l6Z_4D9~c z!ialj)O|<8g?`GQqTO0DJL%>JLJ=3)Rh4&114~eVN9>2Mp)9Yu%Bj1L(G(YcTgz*& zF@lf${WiCPi+s?9^6I7UHZ@;SeA?K0;x;DSfFg}}S@%NE#~r;F>qbO;syW4g%aK#swNV)ol`!e?5>%m;zy6JE-cC$Xhld@RHfJf?0Ocdxg=87!oZ zoymzzOJV2Sqp%rSVyAq!7hg}Ji+S;6n)3)t6lH`p2nN+I(~l>ybGzSQ+loX_#Ay_2 z23XB^@)K_i@HHu?771(A?D4A1+UF1|O&@!Ci4GP3nG_+zZJ@ygk zvvut95%<{TPA)VH50k$;9j$32{?d3#;sb!g8q!ZCZBA;U2SxK+>#8byC&I%v)!piV zWgMa?4pdk4{5qenJ*bxdcz=4Z2=sv;iBoL5J@oINQ8(x{K9QnnrNJh5V&R*;%Z2S0 zVYcqz%)MH14R+C*T)c^+e=F!%rDI-kb&%O-Hu}FkO}URN-SO>#s1` zkoASl7|QG{*p#B#IxUNPAPnkKOZFtP+RfDadNQaAD(!8s?4!Q0lKIs6VgsssvhoFe zvpbJGl{)T~AxYoPz6MPXJC=%rp*oUa4dr(eay(7_a6x>f{lQXB^k~$It#6QBk7*a# zMkphgANMX`i!*2K#e3OzvOm&G@IjeWPpi(ywEdcgaNbV|UpKBU*;WRGro|yOr~aMbjLQW|S*#2@j1XVWOONQZ zr=a@OXAAgHw+e$(Uf0N{^ls8fXQ(P291{6~$oQIDVEUQudrCd-0{Eh5`PE^Ck8x|Q zI-i6efOy=$p&(cpJ+@}bt`pV8ulT1ojP1W6Ay62K&gHk;6lgBh#0lvpDLoG0VqF`Jk#7Z0OB~jkXjP%(6QS#1ogfe8`}R6IPVTiI1eYHU~f-A2QM~aOaZnyWQVGmlESOxN1MlA)wlY z-U;W>cL=X|mXr&+PJeRK@r0PK`G-G5*JQu#qj#NTzP&n=nC8TY3!j;9l;nIIu&QvA z%1nCQTpiGNT0yKlI(Wjp{-#yN+9_G{`nEUw@l?WGF7A*^eybo)TT@x|mc!~>=(hFI zxHR@`_(1dSzj9HVA%MbEkYV{?C=JR8nZ2Ia>t4dYW-1WZcZAfsCO-;b5e$j?q&%#c zj1Qw?@4%OZve^UgjTF9obM~(PaqZt1)6%+QJ?e2B=pxMIF(Zdo^qkxf$@kjfLtX4W zN=7SLQP&|IL(b$n&?+FL!*Lf@W zWhENEyEQ${@Rt^E2TZB?~kDg|Y3LSp&+R z_rpf_=H$++WD5c{R7Cbwmb-;d&O{!Gocyg!34L+ugU!D*C7w;?^H*CA?SQu1h^J(5 z=cU&n2N`XNAck?;gT6Px6;9Irvi5bfw{gfaDywjRf<;Qdx(lcQK}6vTXc|M;VOPWQ z9Ja%1!q9YVq@&++RakmW`E%q?WF$o&?apsN~&}N{AL;*{RduOz|(= z8CiEaIh(&Ql5!+)_s!viV?n=6M)ASl*++`aZQKm89ICD_tCx?+UUPRmb-%80_Y{!r zQfhm~)w0ojBh~F-9IyakC8hcdHKE`qmr|Ok|9Y6Hu&$F$VygrvS?rCBteTP5r{H%k zQCGr4`h1==NR6tUdgMoV>M3nqg1*E3TKb4P*1X?h;hR&5mCh$?d;OC+MY^AaaPh)p zw6>`;RB0Z&ila!$mZdDj7P;rTwdqADPTfs^K0dpGiD9j1Y>U>Yr+9O-9tw9%2=PwVvU% zsuW|$aGbB)xvxT7<&F!EOI#|3@;-eb;PdrawQ_AKe&j!=EZC}L{Lqv=0kuTa16v5a zauFvQr;)6z{8_JaKEXY5PdJF0Qr6iV?m1=<*?eS}WfL$(6Gm)vkh&%FgF89Dh!hdV z&?7Q-mYQqm7lu(gyy3zm-B&xSHXiy_9cr)JK4*35nbn|Xs2N&5+u#>yFtH&#*L|mWw|)+aV4hk>QT#Z_mn<-!#}q+M`>!``RncR6YG^OWjUddoDk?#n(%FQk3C0Csk#)X&sRgtb}^tvB%`e8X_q>gn730EzLW;&B_0m4QiFw| zxPs{+-i;i!WHDh|pQP(Em;9ANw5N)_Q1z&Nb;=|XE>^g!hD_&Z`Ev=Q_>?U~lY}Q$ z$U5u`^{?4gQa&_uhYj10%Wq?>qbX$O)A|e-7ee{nx4J*MW|IPVjI(?3_GT`VlLyuu z0?hMTqS2v8I(jHu=3$WRTvM#Il=oA8FWRU_zK!uI>5p#Gv(8&bgWgRjW2 zzwv#32KRTsfptKA` zfwJg3&gNp}XshBhEudP0%N#Q>aNJ^o&{)IEc@^_q?zwyV3F+qdbO`fMG;NXsk%Dqu zW_S5X(N5X8OWTnkY)$u?M6k*CU`HuNxExmYT|<4${!5Op@Wiw#j<1}z80b?~M3#5&EZGuC}` zexp{KHK3ST+5;bb5;1RRi-ET6zvjK{ik*$B1$5f7f?W)i_{ZZ5)o$$y>N4#`PSz#c z7L}<2AiMiC5pGB-+^V=KM+=kquG%%(>yHVnu;!UhAU~+o1b2lwh1l&}cEtV(b_(Xx zF)zy@1vu>Oj{k!34#yL(SR8l#g(Xj-Xaizy?S862ka&L$2LbN?sMfFg!H)m_ z8A?U{D3Fl5vQXn{FBxc9nPt|8xOBafm{Lrm?(*%gI{g=+z_K66IV(Ljc0A(_d>f{` zf2UWrK;6=;ib^Ri(m}CNzX*?|Z&&P`9mrjskGD*@J{;6$V|4K;bl*4T;(dG4^68Sg zsgFOgbG}nWkprt7FT$&on$XyHL}}0P$t}JAHHH{nWqumkq4C*V>Zs#OD4KqfQnGy* zdPv1jgFFPGugfJ~vIYmUWFVu5Q=hX4vjNwbS%lLtpjm_&(8FTn5ntj)#K|Lw8Sws= z{x$VC5TSZ}lly!K9{4v{zvrTYa|!+hohIZFg{1IVgt2?ziklojSr8F2T4b&SxF`_? zieN$sY?R6Mz^5$2%g&J-{3&mqi!0#ZeRt|**7FO;bUUh0NfE;`0bAgbXz%gNC3N+t z%dZ1L%%JSiCIKtr0@juoYU0+j2*iM9NmDv>S*W6(j#n2?@3tJSnoO_bq}~(yAZutR ze>%bk%H-rzl+W%}+PsrrM4G>=NBy9P#eBg2y=a7j7SlJ0$A1lOLDc_NsJS8G<4uaY z*(p(z`O1ASGVYGD{7R9u$ZT~|Y?9|2i`A8Axtq=uZ{AechP2tIx!WdxFr%Dta}QgX zkc8GP2|DIWD*zhILnE0Cj$Mq586}>qIm5*L*~0UNlOu1bA2LO{B&rF zh3%G}V_0t6>IvH%rqMtHJ39uOtkROr7@_w}+R88?U)4$f<<*Gomh7z)LX}V6!v^+w z=xEfH)*Vlp<%B81)-igewfc4UD@@T%VjR`+OQXq@Gdk$eQ^yW0`^IFO@$4hos$>_c z=+FxGo`eK}Ax@#QVrawdY}(}N3|Keg?z!yHU@;lKd>*6IVZwrOfjrK0W8Oc3wS@U_ z&dsKOrUb!vW%{46>$~E$gPYR~?okX4M+=c%wib658o+Tqa(MmxJbq``tB(HEnqHW= zy&tA$XDzr(QTi~O@@v3&!}Qx;geU)N?zvH1O=F)?a2L<-PQGYA7zbz0xpy&9gyt)- zqRe_k;!rR7HZP9LigFAT|}bkOCp$ zelSJimn=8O#@!gb5PFozn6UlcLE7FRdpAecw{lroQO3)Alw2A!?A0@St2Ted&~ZCf za`6FytCp)<+}Zj3C>KBD=YF4+k)4FIuYZ??C<4VMcd~Ir6BD4v_I3ehecYCB*0Y1^ zouZKHEAO_$9sh@xoLCg~Ii?t4a#-i3jICqP=&w4~e)ERB@%Hka_&5!Vj7rJoZm`LJ zB=M-4fCmr>Byk%*2UD4|4(*y7X`ISDN%A~V#vEst-;sY;Y3MYBU~0B*|+@(xHC~e!m2;P`|=5p1k(O23oE6X;QbJ}p5N`FTg>X0rT zWj}6nRcOBVO4lvDd4Neg$LZakWQZ#0i3kFBO?4H*<-=5uc*U+UN60ssW>V@ca0P>j zmblCE2p^Nt+b9T3tJ6SKnyj>jJKSBIUKTDm1L8TuCkif#jw+OjW6BE@r^2 zvN`9E%BIoog{8gOk$ruTg3V%=sD$P zfZTP^$Aq@ZIx(3ALeBhiqIs`-vV#c|p0uOhkm3Z&d&(WawDqL3)H79DIXn%#qPb40Sevlk1v^E0w`BARu7EgKO?k$i`=F_VIK zo+N(68QqaJCY3Ub1!(6|6nf`1dYp_VEN{EhZ-c;^r1;BPt8m1wQCIu_fiM(r_y=Jq zn>;g=GRUtwz(sdx9B5NWs{mPBK!AAdxmYUOm?eiOOnS9JYEo|NG_V z9)Wb~old+BI-fCQohU;E^o1Q`<6!CFAVw#3IJ?TgGEU%m`=e zigs|ZUN4^Lu4qd*ef8#KH7BT-tWE>jpcxRTmY*-YK=#KcpVItwk6aqe48PBF>T{pbj+LjqaK(`#fpE$^ ziJOpNZP*loz%PcWQ!YSMy!$4}^Cb#mgDSBd`yrB}=64po$Kp(^*bG!%T|c@_SDBb| zGz4{~=Xp?;k`WY40=i|R-0_;J{Xr6oKgM?xCv;|`*n zbfCB+Z-(ab*ErY)UjFGhSh*5CvIOq4_dOvcvrd;RcN4*(l!aMv#RSCe7ij9?0)B&N zWef~J>f4ya21p*7RPz-MEd!^NQPm~MVpm@+61bzGlQPdIkXc<$2hvfa?%Ub#KiK{7 z;GCO;o3CorRcCyDWNzDVgay0G0Wa&mZRbU#cvThaQui1DaKO54j2veUuIQ8%gKIg z9*cZPkXrKbyc9QfHlzx#vAX!NF+W1m>gh0NH9REtHSE-9Z_Ww9s;=#!8E)JkwQWung@Ug z39&_T+=aL7$^jG<(hwkhf|&8@VxfR8@nBgo4P=3b73#<@^F5N(VMi00W{o9bMuea& zgv%ow2?@GX#Bp)w=0pU8KxT=BPQ6Lfg&+rrkf|H>}NX=B(fTB9 zu8iY-a^HmlHzup$4cD8Fg|TZ+ddrWPnOAk<_2&<{Mz4|1z>87uR;mz=Z@172S}i%7 z13zn)O(}XNM-}KK7x+sj{}V%tFA86kU)?E!Q6^5JymD11$5#6m6h8d}t}J~;s1p$u zM#h3wd+GIi*M_A>pU785RR6ijD*2GD8Rct-1$06hVr_w6tp-nR;!47?YYamaO8^Lr zmK7yyg0{H+C9N6h+2iILzR&f^KK1FHQpP|18-m&tPOkjEC@11Hy3rd+IS{!Am9Qf+ z$A{lK5%cQg&on;xFd|$FXR4}U%sN~=lQUE7qJgY>0dydu*q4+hY-KBZ2^Fd)9 zDx8O+r%Sgl+V=rqIu>BB?%V~RF66E(Y<>_55nxhrgvy{iNNKRY?VWG3sLDzqJKiLu z1dKKLwbAYtHfE;)jya|NCq7kFs;CpM)nVN~Uo+*Obm}zd|4gSc5x~};Ye*p{EECDk zB-@;CZ#17zu9Kd~oUA7r(^MX{JsCU=eha#7VEp3Wf~p^q_gvIKi6(!f7Cit;$LI6> z*t~FTCwt|;rYtsKX#C!gvB*yNe%$ZTPMi>#LZY^4rb*|%pJnX*8AVim($YJv1U|)r zd*DdQ^swK}4{H)U9X>>nN7yl`T6i&oE?B3jK{^7UMK?9h)`E!h`cDE?OUlS1GR;Y~ zHWGO(m;pnf;(&aPc0KCbP0*TVLaXaMVAw-vLRp07M)cQ{Ryo)X_>brv9k2bw#E z%OBQ3;}?ZZYT1)Gc@AHmUapUpAlY(dAmt@N7l}}i3Q^`T{{HmO3uLKC1*s4vq9m06 zQA7?~#1mvFmYD?TYu6AVH5lm+5MMj|4R@mSHNjNY3B|BM^RkBllDO%((x?x}dC>zo zufu>Nl$_9?EV@>FF#Bp^gfdcIF;+}=L_fd#%5E-0x6OG(8?&i$i)?n@{q2QR z9Lpc_P7v8j(8K0G5j@dw#7ubPM201b)No%MI+^9jaYzf3MPU%gI@n?pkfIr-aiSJZ z6-)8yUDGJ12Lr;%CvU}qZm71O$Si2e+0bR#VrjCDnu_3TW&BgFq-4f?dbOWhXuDds z&k1#NrfgyegQHdfUX&`>eka%_+U-7*vc^~n>aqj>po$d3q)*M7F4RH3O;&Av7!(fs z!Je6g37?wrvd?icsuNbPO$xR%l&xAwC{cU0%xFxq=ik}ElF(J%CBfzf+B>KX@Qjx0 zYIo>Msc&w(HrSag@XI*b>jA7D)$3q|%tg$mg=<`HrNsXU_EP54)Neq-NS({8=wC4I zU3B8rt^Qotss21!Tsx+_l+$*!9}ni};Qrv@bn8H2+Bx{~oSNt^uKxbO&d1E{W9aUZ zrseB#kyY2@$6u^=|9eofZ0sbz8dmrD2(hA*&97$vUSVlz+D_8fZ#0Ek{ZY6h)^Q(m z@0dRCDYc@O4K)B4t78@P-nOJtk+3IA=tSW3h6cn)13;pVc;>}Tj&HbSr!i@n))DQ> z^h^OqC+&A4y15-T8`6T*<$fL8G<`pdnYJQ-gb9K2m-b3(=uAiMP z^Njm2O@mM*aTx>^C3O%k`}fd9t?zeHXHW7xE{pEKG7u7e4aSEq1}5W5sL8Qrz^}lE zYAB}%_`}uPLu-~zR6YW}9s33tM7&7@+2I{js_r}TJl@Ad4>~lsPE}#<&j%cL=V+N1 z7P4f|U@&Q$C=${q()%k@DI09*J5*gEu1zh*}Iw+}I1Y`Mv6^UB=UI4mytHiP9V3AS%XKC{G84;`dk9@yu&A?KWj*}?yW zIgazCgdRoc#d$^&W-44A}yu>ei z#OA5uu&j8xH=VOK>aj_ldh6ozpu@_AOXVg=3yrBf37xguiL2IE%(a z)q;aQi}PY?YTmwfxT>P&nn6|!i69a|`J~r2Bo>=BU?Gf*fLcZ8Cr5$UM`}M-_LpOQFDo{@t#KspV$``N8kjzCgcO|gb z&rKM-ch)eaS>QT~M{on{4UJBWd{2ycJKhrB9?uC2Xu|^owGAw>F zgi5+#fsw-iD0HrM@Z>c2TM{5WY`JmSS&&?@&iHcRhyA1sQ>;?LqgupvOo&0#6a zWHEY0_hK)vqRuxQ?$9fWC~)X3(g^0 zhM=Y)ELlEun`T7ma+yaloe74Zd;7Yk41rAlNn8HX5TP|igb?EMzsG+mlZq**sbSqL z@R6ti60Qi~WD0ipDu*u0?}lU}iMVQ>MVw|%gEF!7jB7es*D8I_z2IXWr`vVjQUg(c z6vg8d1HS`IcR}pAZrx)yzmqLs{|$(_U>zc!wx51EDeB<}T>1fV8sv$h27$1BjG|^5 zuWNM#c;T)%L{W3-bxEUx#4u*P5{g~W$u>Z`UBn^BKF7XYa5FYUiUbjA)S`)lIR){#RjuSFDWQ9MRb?}4S?l*Goq9pe1>Bs&{>4;M*p z)XM#tMp$~&x$c&9ZZwsl(vn*oZ%pmrVXXXyoLl>Dx?0UfM`AKGC=Zi=$#Yr+u=2;j zo>{6g`K_|;#gD*KxVx}Yn#V_(3>aCfv=sh=u2Qs!5wb?pDwxI&U8HCf%VUN8cM&ft z@YYIJSZ73hs`;gCA9`bmO1`xfI0gy4NpqA$VLk(=A7Pwcxv2B!;=dq6grglVcNOFh2zq(CaC5L_;QzVd z_g*WW$*|pKqnIK5RWYVmIU7z2eEp`t_|^^VoPHbnrKc+at=H60ehab(4;Qxd@;%B! zl-CbR;o;h6jYp_R;W#$23CU?2?wvojZX5HLt>-qORTWv#ids`@NzZ6SEh;sp)s#E$J4U zsODb8O(|&tZJx(`z;#&G8Qdpg`%>2y@l(`>&d3=VpbfV5&vEphX|;3#O^wPh;74Ho zU)ENHcY)%6T-&WW?rBwD2EOKs3LVfr$mvdfAi5Z&f{!5(YSRTefkAK31Cfg`N1zQv zL_J*~-OXG@JnE^Kn~bN10TB}hPZudW^aMmqNWMeCnB>;1RircNH_^}A7!S%d`@%%< zFt@&GI?NS_F52l;&@S3p3ITh#+vdL^8t790o|s@gPL`_NhLOL3y^P%gJ-Ut5rQ>n`XB}}jmR6kvb=%aXTl2%`{ zKdX}&k7`^6w4qKR3ds<++I)<0b2Raqx*n$g@wml$rn$|5PDAYHmz99ik&1it^ z<9>auIG6Qx1{IxGamh8GoNDF0qW-NUr?PAG93&zG6HZnS5OgFmXSH9+ z#GVZk|M37UKtGV~Zm{NS1~d`DW*MM^_}nQEL>B?zV~8WF=>nNfpp;p;8p+o{<(^*%r&5{mFdpS%CKS z|KRxlvx;Eb#f-`1(o`yTjFk6g26Kl#uK+I6TAw+cE3C6hC;jS8YgSPCVNV(Y%=6((I&K*oYjTLm6I7$j+9!7<7i77 z`y|^+YMtm?Sg?MxTwHRCLt4y?_+5lbal`j;a^$?DI6KApSGr(x<2=X){Ch-LbN-|Y zpc(SObYWi02$(LEy#UjNe-8v=pIw3J!ast--%6khOc(6xuw8(W0JXRMuY5u5H?o-% zkKzOnfr-K$)i&}SNu*b~Vm6fq0Z@bfEVR6(#y=K)z2De9x1wvqu_3EF5g1i07PB4y zS9ej;^MV*zw~B-P0Ak!y;6E_>%x-Y%cI)IJi9856I=)2V*p%=GMu`oD5-1mLfflfT zLNFO}tR2*$TfiTP*8>KD*qCDRKR0-A+Cg#Ftv)o0B?CVw5Ilbq^{&_Ecm#|92%=L% z3XRB9Tq};!Y2Q$`t$25nz8Y)zM%)F5u#3;3hqc=`KOO%`PsnIwSOOv;r=i2eI9U4g zkP%}XEJB2dak01lU8M6*w=(*Jg7@pGvJmaRBW!0++bivNB zEtUj2h6Pb5$mP_4QNl;Q301y68YW5J-G-Fc2pAsT4+w@?5~D2_32yb(KuuQ;u08>+ zpe5iQ_&q!BOd+$!0z*QM?{%9G0A`%ev6x-S8kkQ4O3nws$Nt@pfuWxDbL@W#`@q$1 zf=NmQ?jCY|WNPhzy9eM8^9V`Dl}B?1B4eU)SCoecuVj9tgUOH$T~eN* zZsw)@Upz&*=U81!Q+s}9y~s}{aZUW1wmO(}1@m&D;U*ERV95J(T&66uHPPNvtL|bJ zoHr#AmHzbTF3I z4s3@Nyj46e_L#X$Y!mD^ss`zY5T`|TbK%|y zGP!HqoqM-FxBHgE*?%0>d`;Kg@YwYjju*i16ZkKcUyAG`6zv+_Gh%Pu)pz2-eDUvE z$YlBKjo~$0A%sXN9oL&aUC+KB?`&VrHMFi#e9u)mErFdfX^nv$0iefF*xlfA9kt6| zvwE%35RS!3z21rvSE7`vPi7i61bKv7#$!Ir5MBc%y&AuPwKjeCWE5N~@~wdVvBdn< zy}M)|53a8RMPlaz`wr*`;d*`?RBOV&h1o(eLjj^p7y}Y#lBLw;#B6QB=BVtYHbwY; zOaPM80u;b_8Prjom)F<*y3t~`9L{r_L=a0f`FTHj$vQr4GvrPNns6#58&wWdG5Q^$ zoO(S+hiy+AI`dS$r`xxlZ&1QBtW6b&k0AbcS9m3bZ|A4ncO1%g8XSceXoJ&?k@oA{ zSw+YS1ZW>G{TW`>rE3?DgW0az+S3mv^4(yn4(N{5EOo*?E&#(zYkid1>5=UrDlG8%1v~D_2$T z`Xpj4$k3R?859LV)7wanp|*P$8N2fM!Ds9vx1j0ihL|=FGd73^wpxXU-FM___!+o% z4Bgk#)0u585Lwn4np260>-jOqQAcCH58*M&Mj7ppkI}wNu{(|I5HUVw@CHSKmUI~o zEXcGjDf|HR-^Z}s1^&W!miy&EB%OXa8zPp+Ir53kOC)q}FD=X*7KFQP_pgG2MccMI z3?;fO@A0oV6*;p|tBFF(p0fG2Zu z?={vhPwvs_s7uijpsGxIBGA#ABRB;;tgP8knX>B$`_;y56D+y9nh$YXSQ1PAo%a_9S`WjICc_->hj&q( zIwan$CH1}3)m3Uy+!kst0}@>DxzUW<{GZ`li*WxpeMlL4S3^THeoCb+#I#=m7Y1~* zi#$KQPaQ>mo;E=`jTFKgPdD~0qzm3q@=Vt=lW84TIse`r7RZzwpl7K^t#&yE<>)^~ zC+f1$>j|n)`E|>10TIu`c_{O7{=-TA64wq=V8vyU-;h_z=QacXN0{X-JBB^WLXXC& z*sC&YWw5292qx+ZsOcx}%dN+3bA%NUCA4kwFpyNFV^!>7>?adW{#RMR?4Mc!SEcAm z$uYc4KYkzXl7&Mt&v??l``Xo>at{FZV_8hc(lQ_fsIM7nATrQ>}cA; z7tCppZ!MZ;8sfedx^3^q;0BS5?(~p>g%OI~^SNX0gb>QP;Vp(sp@Sn>6PI!UK;yX- zT)X%-B$wg9X}^CFNXH}UWD_}JPWt>q@NNLn6MUnO#3xrA4Og;@2HU$HN7S>V_giZ9 zO)O1mZauJi7H2lWoxrfp;}*)scC6pX*-0CjilW*+q#!(x1gED1G@4jC1VxJ|3=Gfi zvy9hT610Gki#no?K)uFhYIj328@BF+In%ROvZ#}9zBGi{SIlpI{95x!={_LZpP#JONS!e48TDc{({%Q_51L>}6GwxniSx;$RDqV$-zWNODG?VoJWz^1tE>>h%+@|cwK!!?XR_t5 zN|lQt94<-MZ0t`uVhv!O+_kEE%~$)sm9FXO3<(`IzW85Qpz1D!8LKKcoo_@j8-Pr> zwz_)fbzl5pzKzjUHjs04fB0^cw##aYi5DK7r|NZ~&-o%N-;ufmuzWFZU#Ss?_%`bv z4EgB+e3ZN9)OhDUL*RpsePu_P*8S*AQgTuj?2I+g&vHT!HKO|3OV*p2!WM>`$;jSi zabbS6l%-7;>h$V8>B}!b$P&&8wgO$~QsSANGsNO-D$~r~tW;oe!JUY|6kHXQP?cjn zS&`}N{v=I$Mf{=bQNv-HLKkuut4oKf?RqlN9f$26ddCz-DLI#x*B$P6B2P2 zenwDNkP^t8cza#;$Azr-&+UP%MijD~!rZC(xt__Q>l)eZgn1nj_6*89-vuKU7p#dz zcIZdZC#5F$4dI@OEEnVW?6Hj?DfcE=O(2Ue>$v>in5fv`|=7Dz1{zwmq zD#JQGmzG0s?k%a?lRf&9<&ERjM2`h|+STDCv&X+Anz-DQwcN%@(Ge%f#UF;VOxjkI z$l88HuAz1WNnrX-_-%zlWlphpfL9`Mv%noJcxvLxA{WUUkLg5~yKAd;6H8vEi-3NnWuyxi-;ZwWjJ>vWfeG=*vN|)W7#B7pE||n5lqS|Mt*oed$~0e;s{Kxg{mKWmt+a%C%`(0j4EQX#r%=qx4<2_*an)plCgWi z4W+8YAd@D~&iQyrJiv=^Jsw`Kuqb&hJej7+KZx;*3w^G4#Tcg=#xa4=}m$~*GzTQ!D+o>yT$>t=kDb%H$BIM z7oq>&5Ets}414tBEvrpmbU&x~zqY@99i%QQxtVEyd&Rf&8#)(!a+M2vT3y%||H#b< z^DkanSh_avkYxkS!D&zlE=i8vlnJqgy={?Nq)@HbCls-@59Ebgn^FMuWWGJRD6{Ome z>@rwmO{RfEhKTcSg69P^YihUO8{5x1kwR>e$+^drk*(hW=o6t#aSt778Eb2+-pI;9 zsBNe`U5;siwHK9#0}3B07A$AH`ZB?K3o*V$UTY*h4S=biZP^<>X_J8JPH_#KFT>xf z*VC>_0y0q0Bf!ik_{pVJCh7fdB}?t-!t+z{K{VB-(QfRPU;HMMQ_S`>OnavyV)z!D3a>q`O(9w}6QxYG zAeJb#jB!OBr`tXsJig46M1va2t&XWyTt~q*WIR#-~nuC12a1#UB$l9J+ju#B! zW0<#xO(!`IZnJwHU+>xaVON5N%uZklQ>t^4x+)|mb+U5FLV}Z`f0dyQ+GRXVq8QCV z!KQx=!#24Z2)Fb`?*1H{c4~h!=KSFiwFTDCXHzr(-fE#%;~%QRA7SScBK4FkW%`-n zuj-7+N5|}Z>R)R^UAF649ny>Giyh=68X9xXH+|QUqb}Ae1*5|{uj_I?U#kp`3Yo;Db==vP~2O!AH4m+&2)W&HfXB4ez7+egQYrmI)3!0pACn;DsH=sXp-Ea(%Qk1 zqFdP@(_`kisR8yT@B9GIMMfyC3Kwy_J&3HyDfk3! zT?|jYUZdvj=AzZqb5rUypLQ6MC-@2CVdQ$C8~?&rtRoh(sna#fB6{a`Fzm;)=Rq9g zn#WFZH*lj-GCYF`lJHc&TjFE9aN~9@b@)ABe0;qE<<)=_E{ z<+RhoEjR?D8Z5Y_6@YTcLqELe<@o~r$K>V3Y>*^f%FZ5vK+}{Rb2R~U(au<$tRxooZDi){ z*Kt2j>%o3UaC(t;;*9(vya>Uh|@)%Kqk7ra@oLG5Z5AY1?^|yf*~Y62kgfS!CZvwi}pj%`cteNX5wXu7$hWZTRBDF5MJq7w(^F zp24HFQC-CriIi)GV#((o3BEA8bjP^$|0IZ}1)n2($35tN`i7)iDqLwjfzqi^RG7=MrIYCgBq5Tnu?WLp8(3P0*Akvtl(pjy~R4R@@H?8*Zgk zKIrRjEhRsqTN?C3&TbYH-n-dTeLws^%)N7PW^KFen~plRZQD-ANyoNrCmna}q+@h! z+qP}nwsF$k@AtmnTIa02_F1*7&iUu6dEXOH&8qq6ca1S_6}o~Il;>>-^$|<4c}VrF zJ~y)WwOdcPYwGvS(v+WZ$Z+r3gfp?HJ#M-Xm?sJ@Y$VIfWvlkNgOY`o6Vz!xO>1T4 zCBHg)buobzb`m}V!4H89y ztMUgVuDe^S67lqQ~{2`m}#QUcyA9Y3(Xa|iRA94 zmT})Tqn*k>iQXbdLbVKNUhZz53ZhISA)rjWnAwli4>*>L0!6;w;F+o>o>@_#28KJK zTp1>nLAO}<;Kzqowz4wk3IVQdew zjbTV?xWbbS3()y!3A_mr)_)CPW2epldO;N({uU6CPwzI$a*tyBR6wSKFA_)e&n1hqJjhY?oHto0CUX zl)|o#3HK3cgyT;=T95VX!SqhxmE=SCY|vvl|+*M;)4~{^i1b%W1p7EE}3{;tC&8 z6r_JV>wa-m9%k-@f|k<%LFeFo1s2_*L9e+*IU_sgP^fP~7l<)qWUG855ZxFTGfDp;Sd z-PB`p z2n}3a5Mb*zt=53iA6zPDLtggwZk`^`m)C*o_h*Zsx2ZR#YrmYevPfe{v@B;^;YCI# z8Ls7&%{P{cJqRD4M{s%)J+gYsh$TrrT}=GG96m-uKR|O^ccT3P^I83cE52hQD(V*u z%}7arI)Vf_{Em^|9d2==rIdnwHks6!T(iLG ziZkU>Z^F|&Bg$}$dG8#|3T*D1`k5R#!fq917-VKCWCq^lbtircdx3X;^M{Y5RU(mKogb`#0jRT zs7PMA;7dlxw>I>7k|Gx7jZwC)keuIsU_1)N9= z&^OxO@QB8WyS=Bs;vV*MJ$6iI(s-)>)_98j(s(X^XgnPrGv{ZIqqm1TS*-Va2&u3m zGpV>y^Ui!iZ8}o~H-sPbg{yD;*0)^VOJG5{&VMOAe_LFi1JdsaTd90pC=X6X-H{V* zSf&6f<=#GNV_WmWdOK^kd6YHt20GyY49$-L)%eoidzUMtM*tzLT9!45jM-+eo?+|y zZ3^sN2)3`C)I^J!x2q3dWOxBQeg3DMc-Fh6$pgFs!HhZFzbkggapmMA71k4 z`}XMo_xrDM(e(=Sw951JnW=*}BhU8Z+#W~*Ex1dcAXLE?ye$xEG+LExtiZQVfBend zY4^W2)?2RMY)p=GyuPqBsZpkeW(L*e5f-g$dN#GRu1KRQO4Zwa9XLkqWEM2xMfJOj z#kp|;cfaF+H1NNw&{D#QplSk}DEmZ7MZ!0UcCvCwDE*zJt6DmFHyqelx$AONePd{_ z9Z#yp-S2r%qz qnWt)g5{eGweFh#@=@3xUVzylPM3FHJ6eQkDB^5*75-i<+_Hyt zbD^j^>|cNLU)osC_OO(kfrX_~!Jm1j4d}sDa$WY;CYiF%rd@7ssAJmzO$B#U{McUx zlcNr&XGnfqd8t->x$p%4la+TENc2RkqDkZ3Rs0LtZfseiAE{8@+OY3E(IC_`QMWY9lIXj9uSC&7ZkUJm#zpAj#Lt^+ z6orOZ!DW0s^1Nht)#okwi4Q9oWI06Ru}YR|!lpo|`ixzqW-v-V@$ztMz;sQgSy^&u zz5Q9@IuxbJJ}NRJM>nJ2ATh4)btdB%f5ekN2H#DbD%?tmY;~W$fzN_Ux4~922cZ6c zm)VrD49uBIa1mBA2VefbOSH4^QTWwr#@vrMf`<|$gIv4$d{n^H0o?52<73+SKyNO^ z9TdZ8sSsl%4&hResBC~-@nr#6*qC^FSwe}Y3*V+tiREg7S2^{WpWB{j*I24YVZpE@bWDy&0`kQL4=MoR%T%I|yKq%>akDM*bBLwD7}k%Fkn^j7x7z-_Ii##p)3U?SM;Uh=oMDNl^n0cO zQojmXgdY3QM@Zq!Q1%Ml=d5!F8;%MQ)q5#pQ{Wq|eJ^bl`Eg{wXYBNaYCoeRw<>e5 zaXra)o;i0XkDlGoNCo)`Un654Z-KC!yo4v5U+-9KdQVKcT)|xP zk-XT3 z#B{Q9EyE~M&UKAEy1oHx4|bZzS9V3O>LuqLX5{+ zKkf&aCAK`Esg{jTG#2ytYnw^v95Doo^@iG1!TlMlAraG~FebDrKgWLeH$&{sewB%t z@oPck)nBGJ41Ir2iq-~jQaAY_4_fNtNB+~4gvR^{Bdt4cM-^81%R^++E*i@VczTzN z-wlK&p9#|Ac<8tCx|c`+Pgvr|QItofx*pTdg69X)O`KEelo!wc!q&9W?rZ+(KeMZz zGjbSn%BAmAxm34*dPW<@SzSdbu|}G4OgYr@9-LOlqaF$a&sP47(@U~8+WW>d@nO(Q zy3I>nvspP0Bh6bw#|WUGG1{(VZxqkBV~AaCahc-B>rH}3Gr#42W&MPl(L+zM-o51F zcn;4`n)#VD6<$!Y;t$Z1s7tbX#JR1oBU-P_&Y=37mv#8Qmc~`Z7J_Fa*PD5@?tD znDvq-4Bci0e_iMPac6D4np--E5!GRd>~bn(H?R=?l+<5K(WH^=MBV|3z99O_Qp(tq zE+2Q26vAJSUNjL7;DChBi1O!YAc+fJU2{&kZh=G{?^8K4=3OB zXSS<7bA(%hu4enbt zl)wy+>`t)Ai%SZZvEi~v2Fw^;;&sLKqWO`LpOqpAR?I37kx9sKeg&iaAOEpN;D`S> zvHW2!-7or{^iqQiB4i_TPpfS&bIa^c1`stPth9}LC;j~z8*AzHEG z<+0~414>t$##a>K%>zZ0=h#it zagYo3jEblMQp`W?*8PZ?a#dR?*(Y19P=J_kK{&wnr3_Z<;j4U%mafnsz36g$4;KE; z@ZoEY+kd-65`gscSkNkbwVf={dWR_Vgj;<8i@TzX8`9A=SgnjDAUF{Iuem-t2%L^S z&6^cz8(24(sE8|B+Egh@Ac%(h!_B2-@$72y)_X&KSl&XZm(uhTv=>GrAyrsDCqj~m zn4Y0!{H~qx8hhPme9T}Mxn-O^a$n-5ygho^o-kBEbzr`nEKPV%?K4PsB=L`CpF9Y>^Mg<=z{9d`7(6cJ8gL zg<{VmaE&808%(b=L<}OWTC0yQ=I{W6j!{D;aPk zhuP_{h^->|RQOYlL8aF5{<`h(Ra@Lc?dEw*=Znv?{-dsThB#e2cK?yb>6R+DO; zn5DdueYWe~#y3+?U0hFKUcEIQWv=0t0ZJqa{))X_@59b0O6V*TGR{5zE$f+&^640q zW$FuXD9U}LIls4kMa`0I;g2J$;7dsVji8FcW_O?MVN2`Q%`LuqVA?t!kDD;!l7P^c zrso(0$9ze)xQ`Y+1WXxb)3Q9GZ!7m{)<9+R=pKV)*w>Mh(y~BgV>+Sp(<+UuWz)V9 zOo;%+6K0{G5}PoLMGpO;C*pMTWmDssa|Pc?JgPj1WEW8B9N-ayQ72o6C|A{i1+wGzNt?5Ghg5`<7Ss@ND^D|-?CD*Bs3<8T_uh;Lw0X)AWbWCYZ=8M zghn!wAc(ep>o? z&tH`9tHbtq`e@P{*2q~og{OU6T*b_HEN|a7nJ!Z3&YlEN`7fD$4Odo!!) zf$p-Pp2!Bm~h%$ zDb2`&mts+ncMu99s28|nEiLrS;bC~`V-xEJ5B>7$RM9?RLZZ)8*}(YJ5MlrK#P?F7&g3tyg=k$Tq7B!v*L zAz|W{^$1SK+Nk&Ha`K5_R!o91&NE-!=AZdS>R$ru?W~lPzPv<6$jH|rp8Jzi5gV%p z4|UTomf4=BQA%2Uwe+>RT#+aaPd1Y)I%Zr2+AHsUsZDH0xt`a1QybA<{(vcOOCK=h z(VX6k`k$Rc`{f{wG=$!kXc^W-=^;4+AV*G8Z=%i5k2DkS3eh-Swp|%ZlQ%cMheE-_h#ioiz3i)gD-wyw8 zCQJ0zbW%!&oVb2p)9e(mZ}9Ik0I;CGSG)a01K39b-1znA09zrBVrB+dBGyvd|2`gO z0q5V2PbmpZ-ZH@MJXFfSi-V&opbKO-+-rn1JXD1Q!m$mM)BXm7il92T+Qbz#qWXbm z-@3V+KG1A06s*+t4?6b`G+Xr-npONjv*y3iEYwus>h^`QLk^N#pqd900~g8eMM?** za}OAHnC3YYnDan(mrNJz1ne-cyz43z!E=?MT*7lugG~SHWK!e2AEB^@G&p+F@0djY z&BP%yQ;bitP|HrZ!G$spbdFa_DDgmol&@6Lu$vQQLHSC+>@3JS4B;Lisek1p;*H-v zw{9kWhKDmmrc`(l7^Wm;ldnqTjW%rifV9{Ea4plDgCP&N;m#elLk`hs=2Vf<4wL(S z_HYdE>J39)twUKZGTS8|lorkJN67yJr487Yv|tnV{h+jjy2yVhEqBy^qO{dbEEKD? z&{v#?@~zjnd!60nDdbufJH42Sqf4TsQ<#Nj#RO$4Hw*#D`dtwS%Q-r$NJx2=7&B)k zNCD6M-(Xk+F=J=@)B4TNdnHT^{Pvup}V9|%k*g;e0+74Zpz z)-dry0{L#=II)s{C0#38X+*udK+lHQAXp<@ij{q&EPf^v8!IFXpbQ3C_$H5K5#SPL zo1Uj)5k9>s%o0XRc>v>lHlib`hKIuqd()zBlCEh+lyn>Z+zgECQ`;Hg7YiZMh!eJ( zWo`*_8ie)TPW%$)6ibnaGcQ<)C2vrt%6yyMO%rKg>`?;8IuU7QjFQGG^>LEpjxe|3 z)z(NCCJZCUT{w9T;j}bCtc(!XI+QJ<;!licBdkv0DRXhurNlMT z?YP9)$4!^1cFV(FWan!evJW%}j z_r(ChfvQ!BXXdZ+U&gNRhAaOS+_>3Cjw7D)5>4Yt=)~B9=gsB=xU!X);RUOUOgpBPdbBRY=EMK%n zPczHPGgqUZUZSa$%Ps<)u(wC(hi0|;uW6NaElB{_8Jy}tPL`!qv%h$9`pFVNpW>WU!x68+3TLsG{B*bhymOA@ftB1OFvNKJd8gXd}QJi1tP<`b6s3^ zSl@Z`9>fLCS@&kNCY1vs!iZqdDh)|*{7PaZzxb8JSnGT+AqD*9X({;o9o?Sr#Vtj* zx6TA+8{20ezV?;`d4GKd4u6QznO zyTl9-&`U&y;hW0oxdT2S7prsQf={^}Go=otp zdYk5E5_IfP*G;cq_1Os#B=sF=GUel2M)$kZxPilK`1?2i7Nu+2x(ayJn0QRaKJ0mm z;vQ?amH{~ z%P=ZJJ3LV_{DLGFnwk8g6km-Z)TgEjP<6J{7%D5l6PyMrkP}fh0Me5l(>2C(%?BbO z+Jw`Ox>tdbAW+*K;^{QSZc`EePdMWb6WdU=vr5Xztr`Qj#(A4$DV0%0`%9-W?CYPp zAg3=`dcwvHfpm>KgcdvwpanKQni$hAoUVB8f_H@RhYsQsXzV@%6ugtD5FVKmf0yKG z^c#N;mdyi5|2CO_%2k_8t85vq0#vnJP)1x=iNe|Y4SxmVqp!oS0EDM61^FTF*%DJ? zwvqhj1+`>$NEHsIp$D6pQw+jpeqV7tWt=O0m6voXGc|DXHPVS&fl2C8#5}UIK$qvd z<)l;t;b+i`nmBY;jJ>c6fRLBgBIh#AEUy(Evk{hGb%V%tm)BE&a9F&Xo2i^)%ev*m z)|iA*+|A=CAnO3%k!FBW@$JUss+Dxo55)8m%n0f`s`zI!R8qxn25C?QJ1*#R79&E! zFDvx~$ieC|m;?h&5_#t@1ZE|}p;kTuLp!+QiP(!Jzs3>Hq5v@riPppsFgl$LYiXGa zlsW^KGn@H+_wY@GXr;Y$z(2E)FRd1{wFZpNS~_<`L^|%aYESA!09S zr@5ig0@7{93i>pz0&XEW2`|Xs3&kkF&J0$NiZPF7I^=^M@p~YdpHovMXs;f^9+3mZ ze02aT$Ww+Jt|;Xt4{s^qcN5uVCrlg*CgqXUYAuRx`A**Fp;e!}wuR#29}9JqZP1EU z`h%nl&L6zwV^x*#oXn+J!z99HIMafnnXWI&(z7Cji2)O_zk=D?Whp8kIbzclKEpO+ zR-5F*m){!%2Ua7nHMI=`ihaP^iGN`2%P&~#*i2&c0c(eU!&=ARuyzt-!s>5Wi!J*B zYezm{tsDLBU$C}L?Jrncm~1Ni2iBJTCs?cU0c$1sOc4LTTC5)ep3+2*qe>sJw(l=k z%RR;UU%^^~j6nvXO4q7B)>pJ)iq(Z{sE6!x$C3T({Jd+6oI8(LRcNYJN>dHm|NnrY04=hVxd8BT$2x_~7ME*4T}Q-uh{(q_asiXU4eU}3c%3()-h z4lc8W7I&_@+R}6nmWe1cbN%(v^)=X%vt!`%Fi~ESd$omnCOd4x+|B1*j-NUN6q6q- z&#;^nrg8!qtdMKkA8MjI8zxK!{CM<7--dc#X}*tH?n~+lNB$EO38$^>03@MO%Xn}^ z8b06aAOu~1pnLUiF_9J5zhWX6JxL9cAUP~!f2Ty=1bw7L(vsI`Al;C21fWTXJ+kC8 z@_sBVbAagIm5GKWk@Du?i&q^tddDBb1-Gm@HBYBNvW)rqDZ>|eYb3*G5g`)Tpedzf4Mqt>xNw!k<*KGu~Ba-0oJEbKB8=tV4i2V z%x9dUtIiYzh$W^V@T=0P_5-DTK^N#I`J?u(B6Ejb3xzIeV>wlJzeMntJ3tUid>A`Q z@{wzUa=-fMI}%VIh?t77>yY7ylCDS*REAyvNASaF(27RYOkZS!Sy6T(SszK86F=PE56bbs-NB$!ya%13n5FTtRSzu$7Ax!33kdGASa^LnU zCC(Dpn}e-eXRLe7xV-Que3K$}q`vJUl9SO;5`kF`GvIDvBZ`sZ!iB!yV~F*u7@3O~ z!nnVlcRdHFqpemar}jljHgr@VxG=zAfazCQQ-y zz(xev>%=PIghllSjHq9bD>+i-?GHmhRorL*Qmw``)b>Z>4GN1oa$>s{k z1In>V?20{}1`HJ-D2Vc15jk`EN3Knb8%=xS?(YD-hGuuOuL^KmR=fKK z!9$O|kv!nYQ@dhQB(*;bno!|obA!>LcK0KY+=k?{&ZWd!7%Cl;&OUdg)z>(w(YJN) zTm5YIo;Y`@HpRPH5f$^_uq$ALR^f?`gi7p-4AOR4S@Ov2r);J*BjW|g+@zW9xHuDQ z(4IcGUIen5&xgKPKMezH;q1+>#PV4xtwR4> zoedvE_`k}|gQ)mdb{KjU6mePgGgOGHln# zc#gH~`y|32fO%PSZJw&)ukbcAV#J}hYP|0e>hbrbJ>}4_8BlwuE4ah3&#o=^=%*YQGgott zS=14`h?oQd7pc4$HrwIKPZ0|{X&55PFdD-HPqS#!6@E*vF@z%_`VH@rCaOm+(v}+6L)6V3d#Jdp zfSsljqC5)|0jZs(rDfps4birkOGjh%TFSepJYMf142&O~O=a8d+h%Cq0g61FeyaA% zi#j=Fr%V*}sY@zJq_~BoGY9kDQaPzMX4ov&<3%KmIGVf?$XQK?sdxH{s@HI2aSUZ#gJZMJTeZ@N=C=DqvNFXKw*^i7|-3H6>mp=U3_8y zDm;6)J~wk)o{PG@2f5?5LDiZ;EpQ}k?}cFrm7K2054FPVArA?)AN$;!g=mR9_~T?} zhsw$88M|#TT2eNen%#=yRi+1lnGq|x8=w7p!Y`-}msJ}C!%arod^uC|i9C6-H z)y=7A!`i8tZ>*@yz?!Cet3h!5!<9ymk{xSBYur4#@EAR7Dm9K77U;N;Oh71aq8nje z`)%+M;igvnm1~BB=0_ptT1vFa0%|C^0zbL)K8(^QDW+DS{l0nxMz1jhf&4<3j8Ye3 zCEr@K7r9%SB1a=P~o?Cgin$F$5FtT?Zg>?vyR`--$kbK5YAqw#YoD#g4kuHu#2;*wS7 zTT8uL+0n#g77^;T{$7d)) zjNV3oqdnd=6W&R|eE}{lEse$#4zqpVti|`aBOi`@vReQd4)RIr4uxU^3cpdSU_6zc zQvrc;7)o{rscjV-K)x};<#0XVD{{-DHzpX{NdMemUD2py9kjMUquX6Hw3I$BNIcI# zsjWhsCprsm+UiPg@QatU*8@^x36G)TM9$5`p+Gqv&t<1rb&WfSfSNN%rQ%h)@ll7~ z4Oi~Mo?J>p9&YPMstJ2Im|)Y$HU`GCUBbWg&otXm>AP$c5keA}?zD|r^iYs1-e zqufTsLB%YKISpUOOR35NmNp6+td9yRvoW9>dDh(?+Rkd2iC4G5S-*p$@V#H=so(h4PQ7LwdcVB& zTK9WX{nbHw3K{dR_mSdwa|jS>shIEcrZRwDH^BWbh!vMo>uxv%lLB zH4)r(`T#SKVL)6eYSUWmcGUV+bz#m4p}=^XE?jizz&0u?TtQw7OsAYpYd-Q>qGTpo zmox2~+A_5Zp$UqQ5&oYN&&DkT`suX&3QWHQAUcDwMy6z{1gphlC1!YMD{rd2kl zloRb;Za@Y3^`rg}xd1r}!kkL1P*7zxD69plPmhCLwMl}qJ;hS@el^7Q?DM14_J-$988&>` zqQ+g!;i2lZY};MFb9DqsDwiY(xNRI5F;x;YDiDA4FTS(K;mE>3rsMwld^%S~QSex{ z`UZ~d{1Ig+-Byq6bzkib>4bnuP(!_!z93KPhS(gyh01`ZI#aw_gXG>@&oXHfyx+vZ zOYZQNdzbY5U>nVd*6>VI2p}GG$^rUBE{1QBg3>*D5lbI66AL*1Eh%|0@^IL913oE@ z-E6A!%0Uu-V)@gng+SEa6y|NcH-Qg*_x@+-PJMk2efE-4Xy8a9%mJ0J3MS@3QSRRn zo2fbmby}$HeW4|EPJN_rY`ZkK>Ixe)e3COcoe*;q-v`3(Dv?)))TC5ADQ94BtI}yI zC_7|O4ZtOvH#3g>$2_EeTm zGfoOAmjjO0l&Fh}ym$gD|1XOdSP1{OS0FT8&aPwUW?_d{-Fo+${<(g`T7ir948l|o zmLX4_=WL|4M6+QElY6h1?$E$l()U+YhtUYM#Z;P`Ql6GbsR!+Lo_&$O-1 zM~jm76{FHN=61wp?7K6}4Rt&FcB1_y=XY=GjTB%h_9x>(%j4R-%vzZq z`KaFyif;gwx)ppn6NXb}e6}G}5kJ?B%Tw2GeEar-1r3RNWkGg#>#8W$R)KtlN9Vf% zz^X{^3&05Wu{lAQMDM#12y4_24x$V7{p`4!PN!* z1d8Mt8D)$n^FZ(u83=+t0}cqnnG@fHE5pV@AN13&TiW)E{Bv*ZFW~L>P_~PUP(CYc zCs7^>KWzeW++OdtwtH`TtuW;RxZ{8pi;KAFp8I7mg)O~kWtZhy7N3dr>XeHvcmCFaq`JxT4-Jxp8*7-RlQ~@dj9ydTx;U)LEHc}653N~8R4q^P8Khv z1H-&}yMD$x9Mj)Yp_f{T8SYJ0jZd&~LrQAn!JZv3xEd0GFtxHT2y2h3bqT*tnS7O? zQJo|eZB15_!W?4@;LaNQ42{xUbw=GB%jC`>p4R3)m9UXCfQgw2>vdz~@Wga$s`TM) zAC5WmCdbQ?`h-2N$|fiHSO~{iMp9u35xXF(W8U_38{mUWN~CFLT^^mdnnpfCN}1Q> zfX=~rVT_Upuc-d1Y-3@r9eE^-Mi$w~g4s;RAX0J&wJpJ+pBk;f-mEqMQwd5w;$3#{ z0kP(mIWUh$k>_EwoxYC2lrB6gkZ!Z_mF=+=*76R(J{=I8yJj5~wl`vpneN1Y2-ws6cf{Sz$=qN(|TS zHq$SKnM5wd1GzJMVJ*OPt03ETnJH=%X#KVzb@-8p)O#k85l5SB)Pv&V4rf zo%>Wa?Hp@amNXP@4pISN_u@R?FLk*)e9%w2lGbWtKI^ezQ1e$-xGUHDg^AIK&Ynt3 zgm=x5{Zl^6XVWo5{9TUlko*f}KhyCzNrWF^W6Ea>J3W3|`U+1~n=kN6=8g2EbTp*Y z)X?rtu{m_Z-J`Z!(U<4LByFg)uV8hZ!nid!h}pj`W}-I z<3&AHlThOYz0s2}oQc&W+4yosLKv||z{Lo(m83}&f(j=DvI6v|g>S%69NZV#{-mSt z4Bu*d@zD*rmelka>&k|ulFSL4-=UJsPYynvfI5P!(+0Z7H zsfkb3BXu*hi)OFV5o*FBqlLTjq8%I+iHR;qV_fOci8NXOem3Z# z$n;7Lr0>S?9_R4XfjZ6h8L(2Vsz4sExyI_BLqjEa1x#C0DT8vvmB5LP#^a@JyR|c- z3#oRQ^}nzi)3;_vz4*1b#t~}O7s&~<)sNJ5>+>y7*{{Hr%S2n*N0$U-=NlkkW=(iE z@9>Pln=*Yw{xLLASnB?OEZH&vUWHR>q&FS!4T=7a43)^UIK~MDfn!pH=*d*JR7I!k zBdlz$3TL{v`t^|~AVNHw7IHkYktd-|d||B&QZ1DxT9AKpqMj#Nc;z!AB*==JMg6Z2|i_aRld`sxp`Q zdms_8US0VUC||W2z zdubzcj~}^UdX&`<-Gyh#4-6c^I3@R8Eh+Pc@5b>gJcb<_ucUZlB#-wgwJR%{dFtzQ zmIcLf)aDVSxpCNw^!uJw%xC_A#!sn}3#U#25!+CwizYh})=Y9R5me31aj_^t2qR=Q zwYL$k>EJLrT_3?eoeeIIn6g7089CP>?u}0aqcCJwo%V(1QRQjph)#rCD?dH;)%LL^ z2oSkHp7YK;Co8NA+kA_W!(s-E8ww@E(ZQDy*lnzLs;2O2qiw&SZiuVt+gswOv*T#= zjuBO-2#xF$;;CLc;xKg!2AA$*$!vRLPz=}ueMAAN;`BQ% zVoKA^mN~gt=3U8)PqG&sQZ0uQ ztU(IaG6ZkN3!W%GL({^6GcK6IwO` zEHpZ^1IWP`MD0=r5 zaWorRK2*mFvPJQ~caM)o5%hmMFgS&csIM{n47qyqmc{Vn!P~EU7N-B^wFnSDz6~`f zS3Q~MG&rVX8zE7=zprLjt%sbjPsTL2@1ae1@qwqg{?@WH=v4uWx?v3)LS5fnA!Gjx zG7t>tHrwPK4?fdO>CF|3f)KX>@gc3vm)I|aV6wk>N#xZG735kdI%)5l3iQZPxdrW( zwX2%P^2&4Z#L?a8JhXDQA#lrtWRyFjbd6(t=N=^dh5pxd_GTXIC{KK=ungyb+JnHdMi ztKO>Wv0uFoh(rOt=o57hroX+CRNlXuluOR{rFT{7Jcc+Z)F0O^izR0`)F2WQeh_*b zG4m@VBbw4VXWWduR`l6jbWX6?^lrd8xz}3Na+6+H7v|`m6W>9-Pbm%9YEYa4ng)!Y zqxWwAY~?4%C(#?jsku8KZpo9npeS^o3Gn^7u3)Res`-;=^S3W4$Bdv`&Ybz*3#4q# zOCIs;(q$~&zozd{AY)hPy*}<~L&=E93zoT4xP94e(6-=U$2j9)Dm|a9-b|p<04I>) z#OWd`90=BX%{|cRbGYcTeUH-RYkaZ3XMpf>`zi!qz+n+F^HxxxT<%F;h-<*i10Y+O zQ}wL`O;b@qUa-qLk)^5XWX#&*e2*&SdZ=cN2V|_3mD?V-C9w%S7Qov6(V6qw9}uY^ z>``VVSDhN3#^&v9JCL<>Zc-Ta{g_&wDRloyoqL6J%QQN}=A3JFV&@>gyGQUAScL(1?H$_35>2EZXi=96PVFeHVXFhtI2GM}@!Jrq#m4vm4yngm(;G5z*~ zPl&nhSbx-|Mh@V50a3s1xPq)loe;nKb@&O6aEUshB)JC8VH>(UM_>&Nz90JJ4 zjmn5()}utjF$I`v<2jYPRGZ1|l8e6~MYw6!HcpoXdeB7aaWfbSe&?yd;124VtJ`)a z+PuGKKa0ZiY^5eO%BTKlg)0T?`%&|iswQhg&r(BxU9xtaSCzI!<o)l2#^9F!#t>!c1%cQoY+=W0`7H{PtW?!dNpIhr^Us%jiXF*7Ygw+U=8Tt3yn zNIuOj-HqyZH1>X$CVlJMhu*_Sp&u_{OjZ`IuVI*b(cw|Me#iZ>%y3E(~5r6K*XvXAzdiyy61$C z^3fbHzyV)3d-rKOr0P2dn%ZfO0>Y1IpyE^%b@t9+ooSml;A!QBwQqzgzS#&(3lBH+ zc6)RfW1}_C+Xyv|*kf6+5$%4#=3OP+oO&0m&8v9Eipo{23A&lyDztOq{~x2=AOFWt z?)d*-P_7l~e}{6_{*R;FzB4l>$a4BaoV!l4^Er?o6~Cj;b=WBNbKG{PREUxUSSaS>j?n3=S4qq4@3KU0$|80cT_9 z@l_zo?rXZRKi0|;csT3THg6`j{&xn8kZ%l@?4O}}OaF(}ig5oP{!fZx3FZgv9o_nk zf0@-l{&^X}Za$`zQx^h^G4U_me1AFso3(#B0PMfm@Ep$LU(onBKAsa0$WUcZs_V|) zW3V(tB9iU&@gp6HQbk&eaoJhrybvXd?PG9kkQu0YoZI!^86@aIz6&%yq1mSlcHv?J zBG|kH*@1WW=G+QkBB4^8gH|;=*@7WcamiX9&(>CrvO79uAtj9LH^6AizUYT`RPeDy zOZ~p_$%BaN>%*s`&0f+R=UCF6jG`Y@`#kVcr?y^TMw`gU@PxX8u>`fW-5b=c&VUJ2 z`(@P`J(sT+QB8jSu+>D?cIO~?Oo#iyTuTBdoKe!PL^}(_83v%9AaPCUh|dk{=S$i8 znDLK>LOjZ1^riyl09fVkW&P<^VP=x0{24Z~EUq6G$aFA{ZkN3skv0 z^4q}sQN6_%UTM=@8=SE&6sL-K`)1@MuCaGg6W@3vCtVotzf6L7UD;1zHK)TM4+EV_gY5U|*cl}tWZUW+z`&tj z7gY}J%xF0*n$kd*fcGBk)yrU!5pqZ*z~bm3P~hKB{raxXclfH#Jen}T>tQJPA?Gp2 zqogO2Vk{s^NGFZc6|2HN{PN|i92jPPuMH!Yp#%|gZU?hgp3#;5(-qz~!93%LWQPha zO?luOr!TzAGC7Sm!mpMYK{_KBk9-0b3yEVYFduORorHs+4DkraOBi}YxEnn*kTwix z*2610K!_^M8;Bk$HVF-u6f_ALMh6kAg5-O=4A~wQAoW%8i1F(Xw*svv`H&|NbTdM^ z?O+<2$qsE1&M`k`0XM^<(Ga+qTN(RVz3sFHrA+&dCcT!AP!M?-KytrZQ=pQ@b65te zD{ov^ZQAc~*w=LexB0D0X%%Z4$*}l|~mIG&&e^{aLwX*NJLC(3U+Tu4WdGGN)z5dN2MXvQi`TJIJ_B?-~e<$wB&zNy_ zyT!x$>&DD}KlC?679KjzDX;$L@VpQ0qE2(oFJ!8hpKj%ztn55#?G(oksvTvg6)S%K ze7*db_Llcwm;`F4#vRC-;brinXy)XofTjB&gR}_|iZ53lYis4NG!yw>j;Ge1QLxy; z)3i*A6{r_9E(;!<1rzZx4i62}1RlUfW%Nr0u+#hv%JYd=q+AZpPo_6}*eL?VrBlt>)}Ee}xQhueMgr{?fTSwf51I z6!GS5(jD^C<}O&lyKUVM zdiN{;`|PJDlj9;bp1aX|%wgJ10l|V_lZAKen-h5WNuH}SXXd-&MeRGe*Z=5vFY5c# zd)-YR^^@izQRilzv|!jb`{-Y`?%2rh(_+1(?B=Ta-*U9J`BWuIvwE?lT>$)-r?_f2cJlO& z7O}R&Yg;uIx9*7G-CKCyWWkkyNqa({1Z5Sw#WBrz*Hm~rz)x4S=kX4v+Y^p=iWP5h zcmG;2XWEnWm^R>bk-CrFravea+W|Zu?z#&;EQ7X`N=*kMvyvs7TuYG4% z2Cn9qb_jKVR_f$%AE3>fnZ5X + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + contextservice + 0.0.1-SNAPSHOT + contextservice + contextservice + + + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + 1.18.38 + provided + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.cloud + spring-cloud-starter-openfeign + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + \ No newline at end of file diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java new file mode 100644 index 000000000000..eb22d094ffce --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java @@ -0,0 +1,17 @@ +package com.learning.contextservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.cloud.openfeign.EnableFeignClients; + +@SpringBootApplication +@EnableDiscoveryClient +@EnableFeignClients +public class ContextserviceApplication { + + public static void main(String[] args) { + SpringApplication.run(ContextserviceApplication.class, args); + } + +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java new file mode 100644 index 000000000000..0226fc50e803 --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -0,0 +1,42 @@ +package com.learning.contextservice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + + +@Component("myCustomHealthCheck") +public class MyCustomHealthCheck implements HealthIndicator { + + private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); + + private volatile boolean isHealthy = true; + + @Scheduled(fixedRate = 5000) // Run every 5 seconds + public void updateHealthStatus() { + // Perform checks here to determine the current health + // For example, check database connectivity, external service availability, etc. + isHealthy = performHealthCheck(); + log.info("Update health status : {}", isHealthy); + } + + boolean performHealthCheck() { + boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + log.debug("Performing health check, current status: {}", current); + return current; // Simulate fluctuating health + } + + @Override + public Health health() { + if (isHealthy) { + log.info("Health check successful, service is UP"); + return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + } else { + log.warn("Health check failed, service is DOWN"); + return Health.down().withDetail("error", "Scheduled health checks failed").build(); + } + } +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java new file mode 100644 index 000000000000..367a3bdd496c --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/client/GreetingServiceClient.java @@ -0,0 +1,11 @@ +package com.learning.contextservice.client; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +@FeignClient(name = "greetingservice") +public interface GreetingServiceClient { + + @GetMapping("/greeting") + String getGreeting(); +} diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java new file mode 100644 index 000000000000..5ad8969e0871 --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java @@ -0,0 +1,26 @@ +package com.learning.contextservice.controller; + +import com.learning.contextservice.client.GreetingServiceClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ContextController { + + private final GreetingServiceClient greetingServiceClient; + private final String userRegion; + + @Autowired + public ContextController(GreetingServiceClient greetingServiceClient, @Value("${user.region}") String userRegion) { + this.greetingServiceClient = greetingServiceClient; + this.userRegion = userRegion; + } + + @GetMapping("/context") + public String getContext() { + String greeting = greetingServiceClient.getGreeting(); + return "The Greeting Service says: "+greeting+" from "+userRegion; + } +} diff --git a/microservices-self-registration/contextservice/src/main/resources/application.yml b/microservices-self-registration/contextservice/src/main/resources/application.yml new file mode 100644 index 000000000000..dfef73bbbeec --- /dev/null +++ b/microservices-self-registration/contextservice/src/main/resources/application.yml @@ -0,0 +1,25 @@ +server: + port: 8082 + +spring: + application: + name: contextservice + +eureka: + client: + service-url.defaultZone: http://localhost:8761/eureka + +user: + region: Chennai, Tamil Nadu, India + +management: + endpoint: + health: + show-details: always + web: + exposure: + include: health + +logging: + file: + name: application.log diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java new file mode 100644 index 000000000000..f11da867cda0 --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -0,0 +1,49 @@ +package com.learning.contextservice; + +import com.learning.contextservice.client.GreetingServiceClient; +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@SpringBootTest(classes = ContextserviceApplication.class) +@AutoConfigureMockMvc +@Import(TestConfig.class) +class ContextControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockitoBean + private GreetingServiceClient greetingServiceClient; + + @Value("${user.region}") + private String userRegion; + + @Test + void shouldReturnContextGreeting() throws Exception{ + Mockito.when(greetingServiceClient.getGreeting()).thenReturn("Mocked Hello"); + + mockMvc.perform(MockMvcRequestBuilders.get("/context") + .accept(MediaType.TEXT_PLAIN)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); + } + + @Test + void shouldReturnContextServiceHealthStatusUp() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"status\":\"UP\""))); + } +} diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java new file mode 100644 index 000000000000..a5d5c869c664 --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java @@ -0,0 +1,17 @@ +package com.learning.contextservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ContextserviceApplicationTests { + + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. + } + +} diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java new file mode 100644 index 000000000000..f378f46f59df --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/TestConfig.java @@ -0,0 +1,17 @@ +package com.learning.contextservice; + +import com.learning.contextservice.client.GreetingServiceClient; +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TestConfig { + + @Bean + public GreetingServiceClient greetingServiceClient() { + GreetingServiceClient mockClient = Mockito.mock(GreetingServiceClient.class); + Mockito.when(mockClient.getGreeting()).thenReturn("Mocked Hello"); + return mockClient; + } +} diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java new file mode 100644 index 000000000000..129209469827 --- /dev/null +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -0,0 +1,33 @@ +package com.learning.contextservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.boot.actuate.health.Status; +import static org.junit.jupiter.api.Assertions.*; + +class MyCustomHealthCheckTest { + + @Test + void testHealthUp() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate a healthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", true); + Health health = healthCheck.health(); + assertEquals(Status.UP, health.getStatus()); + assertTrue(health.getDetails().containsKey("message")); + assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + } + + @Test + void testHealthDown() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate an unhealthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", false); + Health health = healthCheck.health(); + assertEquals(Status.DOWN, health.getStatus()); + assertTrue(health.getDetails().containsKey("error")); + assertEquals("Scheduled health checks failed", health.getDetails().get("error")); + } + +} \ No newline at end of file diff --git a/microservices-self-registration/eurekaserver/.gitattributes b/microservices-self-registration/eurekaserver/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/eurekaserver/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/eurekaserver/.gitignore b/microservices-self-registration/eurekaserver/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/eurekaserver/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml new file mode 100644 index 000000000000..b1a4b26cf4f4 --- /dev/null +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + eurekaserver + 0.0.1-SNAPSHOT + eurekaserver + eurekaserver + + + 2024.0.1 + + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-server + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + \ No newline at end of file diff --git a/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java new file mode 100644 index 000000000000..80b3d904ff4c --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java @@ -0,0 +1,15 @@ +package com.learning.eurekaserver; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; + +@SpringBootApplication +@EnableEurekaServer +public class EurekaserverApplication { + + public static void main(String[] args) { + SpringApplication.run(EurekaserverApplication.class, args); + } + +} diff --git a/microservices-self-registration/eurekaserver/src/main/resources/application.yml b/microservices-self-registration/eurekaserver/src/main/resources/application.yml new file mode 100644 index 000000000000..51f8a815d251 --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/main/resources/application.yml @@ -0,0 +1,10 @@ +server: + port: 8761 + +eureka: + client: + register-with-eureka: false + fetch-registry: false + server: + enable-self-preservation: true + diff --git a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java new file mode 100644 index 000000000000..b5150fefa940 --- /dev/null +++ b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java @@ -0,0 +1,17 @@ +package com.learning.eurekaserver; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class EurekaserverApplicationTests { + + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. + } + +} diff --git a/microservices-self-registration/greetingservice/.gitattributes b/microservices-self-registration/greetingservice/.gitattributes new file mode 100644 index 000000000000..3b41682ac579 --- /dev/null +++ b/microservices-self-registration/greetingservice/.gitattributes @@ -0,0 +1,2 @@ +/mvnw text eol=lf +*.cmd text eol=crlf diff --git a/microservices-self-registration/greetingservice/.gitignore b/microservices-self-registration/greetingservice/.gitignore new file mode 100644 index 000000000000..549e00a2a96f --- /dev/null +++ b/microservices-self-registration/greetingservice/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz b/microservices-self-registration/greetingservice/application.log.2025-04-05.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..93d6a2e62ac144ee4c35e079906a0fdd82f04492 GIT binary patch literal 1893 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 literal 0 HcmV?d00001 diff --git a/microservices-self-registration/greetingservice/application.log.2025-04-09.0.gz b/microservices-self-registration/greetingservice/application.log.2025-04-09.0.gz new file mode 100644 index 0000000000000000000000000000000000000000..59f2cbc3c8dfad5a5f90f9187eca0e58b6a796f2 GIT binary patch literal 18884 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%0DM?2 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 e0rKw!aGb> + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + com.learning + greetingservice + 0.0.1-SNAPSHOT + greetingservice + greetingservice + + + 2024.0.1 + + + + org.springframework.boot + spring-boot-starter-web + + + org.projectlombok + lombok + 1.18.38 + provided + + + org.springframework.cloud + spring-cloud-starter-netflix-eureka-client + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java new file mode 100644 index 000000000000..7a549a084284 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java @@ -0,0 +1,17 @@ +package com.learning.greetingservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@EnableDiscoveryClient +@ComponentScan("com.learning.greetingservice.controller") +public class GreetingserviceApplication { + + public static void main(String[] args) { + SpringApplication.run(GreetingserviceApplication.class, args); + } + +} diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java new file mode 100644 index 000000000000..218a4ad002d4 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -0,0 +1,41 @@ +package com.learning.greetingservice; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component("myCustomHealthCheck") +public class MyCustomHealthCheck implements HealthIndicator { + + private static final Logger log = LoggerFactory.getLogger(MyCustomHealthCheck.class); + + private volatile boolean isHealthy = true; + + @Scheduled(fixedRate = 5000) // Run every 5 seconds + public void updateHealthStatus() { + // Perform checks here to determine the current health + // For example, check database connectivity, external service availability, etc. + isHealthy = performHealthCheck(); + log.info("Update health status : {}", isHealthy); + } + + boolean performHealthCheck() { + boolean current = System.currentTimeMillis() % 10000 < 5000; // Simulate fluctuating health + log.debug("Performing health check, current status: {}", current); + return current; // Simulate fluctuating health + } + + @Override + public Health health() { + if (isHealthy) { + log.info("Health check successful, service is UP"); + return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + } else { + log.warn("Health check failed, service is DOWN"); + return Health.down().withDetail("error", "Scheduled health checks failed").build(); + } + } +} diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/controller/GreetingsController.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/controller/GreetingsController.java new file mode 100644 index 000000000000..ea385beb1abe --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/controller/GreetingsController.java @@ -0,0 +1,13 @@ +package com.learning.greetingservice.controller; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class GreetingsController { + + @GetMapping("/greeting") + public String getGreeting() { + return "Hello"; + } +} diff --git a/microservices-self-registration/greetingservice/src/main/resources/application.yml b/microservices-self-registration/greetingservice/src/main/resources/application.yml new file mode 100644 index 000000000000..adcfac884c2b --- /dev/null +++ b/microservices-self-registration/greetingservice/src/main/resources/application.yml @@ -0,0 +1,22 @@ +server: + port: 8081 + +spring: + application: + name: greetingservice +eureka: + client: + service-url.defaultZone: http://localhost:8761/eureka + +management: + endpoint: + health: + show-details: always + web: + exposure: + include: health + +logging: + file: + name: application.log + diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java new file mode 100644 index 000000000000..945898278aa9 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java @@ -0,0 +1,17 @@ +package com.learning.greetingservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class GreetingserviceApplicationTests { + + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads successfully. + // If the context loads without any exceptions, the test is considered passing. + // It is often left empty as the act of loading the context is the primary verification. + // You can add specific assertions here if you want to verify the presence or state of certain beans. + } + +} diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java new file mode 100644 index 000000000000..8ba8b2a30f93 --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java @@ -0,0 +1,22 @@ +package com.learning.greetingservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.boot.actuate.health.Status; +import static org.junit.jupiter.api.Assertions.*; + +class MyCustomHealthCheckTest { + + @Test + void testHealthUp() { + MyCustomHealthCheck healthCheck = new MyCustomHealthCheck(); + // Simulate a healthy state + ReflectionTestUtils.setField(healthCheck, "isHealthy", true); + Health health = healthCheck.health(); + assertEquals(Status.UP, health.getStatus()); + assertTrue(health.getDetails().containsKey("message")); + assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + } + +} \ No newline at end of file diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java new file mode 100644 index 000000000000..5ae98c8b6aeb --- /dev/null +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java @@ -0,0 +1,36 @@ +package com.learning.greetingservice.controller; + +import com.learning.greetingservice.GreetingserviceApplication; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +@SpringBootTest(classes = GreetingserviceApplication.class) +@AutoConfigureMockMvc +@ActiveProfiles("test") +class GreetingControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + void shouldReturnGreeting() throws Exception{ + mockMvc.perform(MockMvcRequestBuilders.get("/greeting") + .accept(MediaType.TEXT_PLAIN)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string("Hello")); + } + + @Test + void shouldReturnHealthStatusUp() throws Exception{ + mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().string(org.hamcrest.Matchers.containsString("\"status\":\"UP\""))); + } +} diff --git a/microservices-self-registration/pom.xml b/microservices-self-registration/pom.xml new file mode 100644 index 000000000000..4b708cb0eb12 --- /dev/null +++ b/microservices-self-registration/pom.xml @@ -0,0 +1,63 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + microservices-self-registration + pom + + eurekaserver + greetingservice + contextservice + + + + 21 + ${java.version} + ${java.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + ${maven.compiler.source} + ${maven.compiler.target} + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 661abe365a18..a7fdcb7064d9 100644 --- a/pom.xml +++ b/pom.xml @@ -167,6 +167,7 @@ microservices-distributed-tracing microservices-idempotent-consumer microservices-log-aggregation + microservices-self-registration model-view-controller model-view-intent model-view-presenter From fecf7e7a8265116c358a4c7cd14c833b72d11b3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:11:22 +0200 Subject: [PATCH 025/108] build(deps-dev): bump io.projectreactor:reactor-test (#3377) Bumps [io.projectreactor:reactor-test](https://github.com/reactor/reactor-core) from 3.8.0-M1 to 3.8.0-RC1. - [Release notes](https://github.com/reactor/reactor-core/releases) - [Commits](https://github.com/reactor/reactor-core/compare/v3.8.0-M1...v3.8.0-RC1) --- updated-dependencies: - dependency-name: io.projectreactor:reactor-test dependency-version: 3.8.0-RC1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- backpressure/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backpressure/pom.xml b/backpressure/pom.xml index fcc15892fb8a..8f6a54178799 100644 --- a/backpressure/pom.xml +++ b/backpressure/pom.xml @@ -55,7 +55,7 @@ io.projectreactor reactor-test - 3.8.0-M1 + 3.8.0-RC1 test From f92e6829c3664ac569cdbef86d68db11eff8b36d Mon Sep 17 00:00:00 2001 From: Thanh Nguyen Duc Date: Mon, 9 Feb 2026 02:11:47 +0700 Subject: [PATCH 026/108] feat: Implement DAO Factory pattern (#3282) * feat: implement dao factory * feat: done implement dao factory * test: Add unit test dao-factory * doc: add document for dao-factory * fix: h2 inmemory database to pass CI * fix: unit test pipeline * add license * fix SonarQube * add pom.xml * fix: throw exception + refactor --- dao-factory/README.md | 360 +++++++++++++ dao-factory/etc/dao-factory.png | Bin 0 -> 113583 bytes dao-factory/etc/dao-factory.puml | 74 +++ dao-factory/pom.xml | 82 +++ .../java/com/iluwatar/daofactory/App.java | 124 +++++ .../iluwatar/daofactory/CustomException.java | 36 ++ .../com/iluwatar/daofactory/Customer.java | 47 ++ .../com/iluwatar/daofactory/CustomerDAO.java | 85 +++ .../com/iluwatar/daofactory/DAOFactory.java | 45 ++ .../daofactory/DAOFactoryProvider.java | 62 +++ .../iluwatar/daofactory/DataSourceType.java | 32 ++ .../daofactory/FlatFileCustomerDAO.java | 175 ++++++ .../daofactory/FlatFileDataSourceFactory.java | 43 ++ .../iluwatar/daofactory/H2CustomerDAO.java | 179 +++++++ .../daofactory/H2DataSourceFactory.java | 48 ++ .../iluwatar/daofactory/MongoCustomerDAO.java | 106 ++++ .../daofactory/MongoDataSourceFactory.java | 51 ++ dao-factory/src/main/resources/logback.xml | 12 + .../java/com/iluwatar/daofactory/AppTest.java | 94 ++++ .../iluwatar/daofactory/DAOFactoryTest.java | 54 ++ .../daofactory/FlatFileCustomerDAOTest.java | 500 ++++++++++++++++++ .../daofactory/H2CustomerDAOTest.java | 300 +++++++++++ .../daofactory/MongoCustomerDAOTest.java | 163 ++++++ pom.xml | 1 + 24 files changed, 2673 insertions(+) create mode 100644 dao-factory/README.md create mode 100644 dao-factory/etc/dao-factory.png create mode 100644 dao-factory/etc/dao-factory.puml create mode 100644 dao-factory/pom.xml create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/App.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/CustomException.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/Customer.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/CustomerDAO.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactory.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactoryProvider.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/DataSourceType.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileCustomerDAO.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileDataSourceFactory.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/H2CustomerDAO.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/H2DataSourceFactory.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/MongoCustomerDAO.java create mode 100644 dao-factory/src/main/java/com/iluwatar/daofactory/MongoDataSourceFactory.java create mode 100644 dao-factory/src/main/resources/logback.xml create mode 100644 dao-factory/src/test/java/com/iluwatar/daofactory/AppTest.java create mode 100644 dao-factory/src/test/java/com/iluwatar/daofactory/DAOFactoryTest.java create mode 100644 dao-factory/src/test/java/com/iluwatar/daofactory/FlatFileCustomerDAOTest.java create mode 100644 dao-factory/src/test/java/com/iluwatar/daofactory/H2CustomerDAOTest.java create mode 100644 dao-factory/src/test/java/com/iluwatar/daofactory/MongoCustomerDAOTest.java diff --git a/dao-factory/README.md b/dao-factory/README.md new file mode 100644 index 000000000000..c3ee3c5e893d --- /dev/null +++ b/dao-factory/README.md @@ -0,0 +1,360 @@ +--- +title: "DAO Factory Pattern: Flexible Data Access Layer for Seamless Data Source Switching" +shortTitle: DAO Factory +description: "Learn the Data Access Object Pattern combine with Abstract Factory Pattern in Java with real-world examples, class diagrams, and tutorials. Understand its intent, applicability, benefits, and known uses to enhance your design pattern knowledge." +category: Structural +language: en +tag: + - Abstraction + - Data access + - Layer architecture + - Persistence +--- + +## Also known as + +* DAO Factory +* Factory for Data Access Object strategy using Abstract Factory + + +## Intent of Data Access Object Factory Design Pattern + +The DAO Factory combines the Data Access Object and Abstract Factory patterns to seperate business logic from data access logic, while increasing flexibility when switching between different data sources. + +## Detailed Explanation of Data Access Object Factory Pattern with Real-World Examples + +Real-world example + +> A real-world analogy for the DAO Factory pattern is a multilingual customer service center. Imagine a bank that serves customers speaking different languages—English, French, and Spanish. When a customer calls, an automated system first detects the customer's preferred language, then routes the call to the appropriate support team that speaks that language. Each team follows the same company policies (standard procedures), but handles interactions in a language-specific way. +> +> In the same way, the DAO Factory pattern uses a factory to determine the correct set of DAO implementations based on the data source (e.g., MySQL, MongoDB). Each DAO factory returns a group of DAOs tailored to a specific data source, all conforming to the same interfaces. This allows the application to interact with any supported database in a consistent manner, without changing the business logic—just like how the customer service system handles multiple languages while following the same support protocols. + +In plain words + +> The DAO Factory pattern abstracts the creation of Data Access Objects (DAOs), allowing you to request a specific DAO from a central factory without worrying about its underlying implementation. This makes the code easier to maintain and flexible to change, especially when switching between databases or storage mechanisms. + +Wikipedia says + +> The Data Access Object (DAO) design pattern is a structural pattern that provides an abstract interface to some type of database or other persistence mechanism. By mapping application calls to the persistence layer, the DAO provides some specific data operations without exposing details of the database. The DAO Factory is an extension of this concept, responsible for generating the required DAO implementations. + +Class diagram + +![Data Access Object Factory class diagram](./etc/dao-factory.png "Data Access Object Factory class diagram") + +## Programmatic Example of Data Access Object Factory in Java + +In this example, the persistence object represents a Customer. + +We are considering a flexible storage strategy where the application should be able to work with three different types of data sources: an H2 in-memory relational database (RDBMS), a MongoDB (object-oriented database), and a JSON flat file (flat file storage). + +``` java +public enum DataSourceType { +H2, +Mongo, +FlatFile +} +``` + +First, we define a Customer class that will be persisted in different storage systems. The ID field is generic to maintain compatibility with both relational and object-oriented databases. + +``` java +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class Customer implements Serializable { +private T id; +private String name; +} +``` + +Next, we define a CustomerDAO interface that outlines the standard CRUD operations on the Customer model. This interface will have three concrete implementations, each corresponding to a specific data source: H2 in-memory database, MongoDB, and JSON file. + +``` java +public interface CustomerDAO { + + void save(Customer customer); + + void update(Customer customer); + + void delete(T id); + + List> findAll(); + + Optional> findById(T id); +} +``` + +Here is the implementations + +``` java +@Slf4j +@RequiredArgsConstructor +public class H2CustomerDAO implements CustomerDAO { +private final DataSource dataSource; +private final String INSERT_CUSTOMER = "INSERT INTO customer(id, name) VALUES (?, ?)"; +private final String UPDATE_CUSTOMER = "UPDATE customer SET name = ? WHERE id = ?"; +private final String DELETE_CUSTOMER = "DELETE FROM customer WHERE id = ?"; +private final String SELECT_CUSTOMER_BY_ID = "SELECT * FROM customer WHERE id= ?"; +private final String SELECT_ALL_CUSTOMERS = "SELECT * FROM customer"; +private final String CREATE_SCHEMA = +"CREATE TABLE IF NOT EXISTS customer (id BIGINT PRIMARY KEY, name VARCHAR(255))"; +private final String DROP_SCHEMA = "DROP TABLE IF EXISTS customer"; + + @Override + public void save(Customer customer) { + // Implement operation save for H2 + } + + @Override + public void update(Customer customer) { + // Implement operation save for H2 + } + + @Override + public void delete(Long id) { + // Implement operation delete for H2 + } + + @Override + public List> findAll() { + // Implement operation find all for H2 + } + + @Override + public Optional> findById(Long id) { + // Implement operation find by id for H2 + } +} +``` + +``` java +@Slf4j +@RequiredArgsConstructor +public class MongoCustomerDAO implements CustomerDAO { +private final MongoCollection customerCollection; + + // Implement CRUD operation with MongoDB data source +} +``` + +``` java +@Slf4j +@RequiredArgsConstructor +public class FlatFileCustomerDAO implements CustomerDAO { + private final Path filePath; + private final Gson gson; + Type customerListType = new TypeToken>>() { + }.getType(); + + // Implement CRUD operation with Flat file data source +} +``` + +After that, we create an abstract class DAOFactory that defines two key methods: a static method getDataSource() and an abstract method createCustomerDAO(). + +- The getDataSource() method is a factory selector—it returns a concrete DAOFactory instance based on the type of data source requested. + +- Each subclass of DAOFactory will implement the createCustomerDAO() method to provide the corresponding CustomerDAO implementation. + +``` java +public abstract class DAOFactory { + public static DAOFactory getDataSource(DataSourceType dataSourceType) { + return switch (dataSourceType) { + case H2 -> new H2DataSourceFactory(); + case Mongo -> new MongoDataSourceFactory(); + case FlatFile -> new FlatFileDataSourceFactory(); + }; + } + + public abstract CustomerDAO createCustomerDAO(); +} +``` + +We then implement three specific factory classes: + +H2DataSourceFactory for H2 in-memory RDBMS +``` java +public class H2DataSourceFactory extends DAOFactory { + private final String DB_URL = "jdbc:h2:~/test"; + private final String USER = "sa"; + private final String PASS = ""; + + @Override + public CustomerDAO createCustomerDAO() { + return new H2CustomerDAO(createDataSource()); + } + + private DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + dataSource.setUser(USER); + dataSource.setPassword(PASS); + return dataSource; + } +} +``` + +MongoDataSourceFactory for MongoDB +``` java +public class MongoDataSourceFactory extends DAOFactory { + private final String CONN_STR = "mongodb://localhost:27017/"; + private final String DB_NAME = "dao_factory"; + private final String COLLECTION_NAME = "customer"; + + @Override + public CustomerDAO createCustomerDAO() { + try { + MongoClient mongoClient = MongoClients.create(CONN_STR); + MongoDatabase database = mongoClient.getDatabase(DB_NAME); + MongoCollection customerCollection = database.getCollection(COLLECTION_NAME); + return new MongoCustomerDAO(customerCollection); + } catch (RuntimeException e) { + throw new RuntimeException("Error: " + e); + } + } +} +``` + +FlatFileDataSourceFactory for flat file storage using JSON +``` java +public class FlatFileDataSourceFactory extends DAOFactory { + private final String FILE_PATH = System.getProperty("user.home") + "/Desktop/customer.json"; + @Override + public CustomerDAO createCustomerDAO() { + Path filePath = Paths.get(FILE_PATH); + Gson gson = new GsonBuilder() + .setPrettyPrinting() + .serializeNulls() + .create(); + return new FlatFileCustomerDAO(filePath, gson); + } +} +``` + +Finally, in the main function of client code, we will demonstrate CRUD operations on the Customer using three data source type. +``` java + // Perform CRUD H2 Database + LOGGER.debug("H2 - Create customer"); + performCreateCustomer(customerDAO, + List.of(customerInmemory1, customerInmemory2, customerInmemory3)); + LOGGER.debug("H2 - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateInmemory); + LOGGER.debug("H2 - Delete customer"); + performDeleteCustomer(customerDAO, 3L); + deleteSchema(customerDAO); + + // Perform CRUD MongoDb + daoFactory = DAOFactory.getDataSource(DataSourceType.Mongo); + customerDAO = daoFactory.createCustomerDAO(); + LOGGER.debug("Mongo - Create customer"); + performCreateCustomer(customerDAO, List.of(customer4, customer5)); + LOGGER.debug("Mongo - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateMongo); + LOGGER.debug("Mongo - Delete customer"); + performDeleteCustomer(customerDAO, idCustomerMongo2); + deleteSchema(customerDAO); + + // Perform CRUD Flat file + daoFactory = DAOFactory.getDataSource(DataSourceType.FlatFile); + customerDAO = daoFactory.createCustomerDAO(); + LOGGER.debug("Flat file - Create customer"); + performCreateCustomer(customerDAO, + List.of(customerFlatFile1, customerFlatFile2, customerFlatFile3)); + LOGGER.debug("Flat file - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateFlatFile); + LOGGER.debug("Flat file - Delete customer"); + performDeleteCustomer(customerDAO, 3L); + deleteSchema(customerDAO); +``` + +The program output +``` java +17:17:24.368 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - H2 - Create customer +17:17:24.514 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Green) +17:17:24.514 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Red) +17:17:24.514 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=3, name=Blue) +17:17:24.514 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - H2 - Update customer +17:17:24.573 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Yellow) +17:17:24.573 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Red) +17:17:24.573 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=3, name=Blue) +17:17:24.573 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - H2 - Delete customer +17:17:24.632 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Yellow) +17:17:24.632 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Red) +17:17:24.747 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Mongo - Create customer +17:17:24.834 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=68173eb4c840286dbc2bc5c1, name=Masca) +17:17:24.834 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=68173eb4c840286dbc2bc5c2, name=Elliot) +17:17:24.834 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Mongo - Update customer +17:17:24.845 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=68173eb4c840286dbc2bc5c1, name=Masca) +17:17:24.845 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=68173eb4c840286dbc2bc5c2, name=Henry) +17:17:24.845 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Mongo - Delete customer +17:17:24.850 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=68173eb4c840286dbc2bc5c1, name=Masca) +17:17:24.876 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Flat file - Create customer +17:17:24.895 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Duc) +17:17:24.895 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Quang) +17:17:24.895 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=3, name=Nhat) +17:17:24.895 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Flat file - Update customer +17:17:24.897 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Thanh) +17:17:24.897 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Quang) +17:17:24.897 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=3, name=Nhat) +17:17:24.897 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Flat file - Delete customer +17:17:24.898 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=1, name=Thanh) +17:17:24.898 [main] DEBUG c.i.d.App com.iluwatar.daofactory.App - Customer(id=2, name=Quang) +``` +## When to Use the Data Access Object Factory Pattern in Java + +Use the DAO Factory Pattern when: + +* The application needs to support multiple types of storage (RDBMS, NoSQL, file system, etc.) with minimal changes to business logic. +* You want to abstract and isolate persistence logic from the core application logic. +* You aim to make your data access layer pluggable and easy to extend with new storage technologies. +* You want to enable easier unit testing and dependency injection by providing mock implementations of DAOs. +* Runtime configuration (e.g., via environment variables or application settings) determines which data source to use. + +## Data Access Object Factory Pattern Java Tutorials + +* [Core J2EE Patterns - Data Access Object (Oracle)](https://www.oracle.com/java/technologies/dataaccessobject.html) +* [DAO Factories: Java Design Patterns (Youtube)](https://www.youtube.com/watch?v=5HGe9s9qM-o) +* [Java Design Patterns and Architecture (CaveofProgramming)](https://caveofprogramming.teachable.com/courses/2084/lectures/39549) + +## Real-World Applications of Data Access Object Factory Pattern in Java + +* Enterprise Java Applications: Where switching between test, dev, and production databases is common (e.g., MySQL ↔ MongoDB ↔ In-Memory). +* Spring Data JPA & Repository Abstraction: Though Spring provides its own abstraction, the concept is similar to DAO factory for modular and pluggable persistence. +* Microservices with Varying Storage Backends: Different microservices might store data in SQL, NoSQL, or even flat files; using a DAO Factory per service ensures consistency. +* Data Integration Tools: Tools that support importing/exporting from various formats (CSV, JSON, databases) often use DAO factories behind the scenes. +* Framework-Level Implementations: Custom internal frameworks where persistence layers need to support multiple database types. + +## Benefits and Trade-offs of Data Access Object Factory Pattern + +Benefits: + +* Abstraction of Data Source Logic: Client code interacts only with DAO interfaces, completely decoupled from how and where the data is stored. +* Flexibility in Persistence Strategy: Easily switch between databases (e.g., H2, MongoDB, flat files) by changing the factory configuration. +* Improved Maintainability: Storage logic for each data source is encapsulated within its own DAO implementation and factory, making it easier to update or extend. +* Code Reusability: Common data access logic (e.g., CRUD operations) can be reused across different implementations and projects. +* Testability: DAOs and factories can be mocked or stubbed easily, which supports unit testing and dependency injection. + +Trade-offs: +* Increased Complexity: Introducing abstract DAOs and multiple factory classes adds structural complexity to the codebase. +* Boilerplate Code: Requires defining many interfaces and implementations, even for simple data access needs. +* Less Transparent Behavior: Since clients access DAOs indirectly via factories, understanding the concrete data source behavior may require deeper inspection. + +## Related Java Design Patterns + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): DAO Factory is a concrete application of the Factory Pattern, used to create DAO objects in a flexible way. +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): When supporting multiple data sources (e.g., MySQLDAO, OracleDAO), DAO Factory can act as an Abstract Factory. +* [Data Access Object (DAO)](https://java-design-patterns.com/patterns/data-access-object/): The core pattern managed by DAO Factory, it separates data access logic from business logic. +* [Singleton](https://java-design-patterns.com/patterns/singleton/): DAO Factory is often implemented as a Singleton to ensure only one instance manages DAO creation. +* [Service Locator](https://java-design-patterns.com/patterns/service-locator/): Can be used alongside DAO Factory to retrieve DAO services efficiently. +* [Dependency Injection](https://java-design-patterns.com/patterns/dependency-injection/): In frameworks like Spring, DAOs are typically injected into the service layer instead of being retrieved from a factory. + + +## References and Credits + +* [DAO Factory - J2EE Design Patterns Book](https://www.oreilly.com/library/view/j2ee-design-patterns/0596004273/re15.html) +* [DAO Factory patterns with Hibernate](http://www.giuseppeurso.eu/en/dao-factory-patterns-with-hibernate/) +* [Design Patterns - Java Means DURGA SOFT](https://www.scribd.com/document/407219980/2-DAO-Factory-Design-Pattern) +* [Generic DAO pattern - Hibernate](https://in.relation.to/2005/09/09/generic-dao-pattern-with-jdk-50/) + \ No newline at end of file diff --git a/dao-factory/etc/dao-factory.png b/dao-factory/etc/dao-factory.png new file mode 100644 index 0000000000000000000000000000000000000000..d93547d799575ecf42efa9c27aac4e16c437723b GIT binary patch literal 113583 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 { + T id + String name + } + + interface CustomerDAO { + void save(Customer customer) + void update(Customer customer) + void delete(ID id) + List> findAll() + Optional> findById(ID id) + void deleteSchema() + } + + abstract class DAOFactory { + {static} DAOFactory getDataSource(DataSourceType dataType) + {abstract} CustomerDAO createCustomerDAO() + } + + enum DataSourceType { + H2 + Mongo + FlatFile + } + + class FlatFileCustomerDAO implements CustomerDAO { + void save(Customer customer) + void update(Customer customer) + void delete(Long id) + List> findAll() + Optional> findById(Long id) + void deleteSchema() + } + + class H2CustomerDAO implements CustomerDAO { + void save(Customer customer) + void update(Customer customer) + void delete(Long id) + List> findAll() + Optional> findById(Long id) + void deleteSchema() + } + + class FlatFileDataSourceFactory extends DAOFactory { + CustomerDAO createCustomerDAO() + } + + class H2DataSourceFactory extends DAOFactory { + CustomerDAO createCustomerDAO() + } + + class MongoCustomerDAO implements CustomerDAO { + void save(Customer customer) + void update(Customer customer) + void delete(ObjectId id) + List> findAll() + Optional> findById(ObjectId id) + void deleteSchema() + } + class MongoDataSourceFactory extends DAOFactory { + CustomerDAO createCustomerDAO() + } + + DataSourceType ..+ DAOFactory + DAOFactory ..+ App + App --> Customer + } +@enduml \ No newline at end of file diff --git a/dao-factory/pom.xml b/dao-factory/pom.xml new file mode 100644 index 000000000000..2e771e736688 --- /dev/null +++ b/dao-factory/pom.xml @@ -0,0 +1,82 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + dao-factory + + + 21 + 21 + UTF-8 + + + + + com.h2database + h2 + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.mongodb + mongodb-driver-legacy + + + com.google.code.gson + gson + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + org.mockito + mockito-core + test + + + + \ No newline at end of file diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/App.java b/dao-factory/src/main/java/com/iluwatar/daofactory/App.java new file mode 100644 index 000000000000..b80d3c5ac56a --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/App.java @@ -0,0 +1,124 @@ +/* + * 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.daofactory; + +import java.io.Serializable; +import java.util.List; +import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; + +@Slf4j +public class App { + + public static void main(String[] args) { + var daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.H2); + CustomerDAO customerDAO = daoFactory.createCustomerDAO(); + + // Perform CRUD H2 Database + if (customerDAO instanceof H2CustomerDAO h2CustomerDAO) { + h2CustomerDAO.deleteSchema(); + h2CustomerDAO.createSchema(); + } + Customer customerInmemory1 = new Customer<>(1L, "Green"); + Customer customerInmemory2 = new Customer<>(2L, "Red"); + Customer customerInmemory3 = new Customer<>(3L, "Blue"); + Customer customerUpdateInmemory = new Customer<>(1L, "Yellow"); + + LOGGER.debug("H2 - Create customer"); + performCreateCustomer( + customerDAO, List.of(customerInmemory1, customerInmemory2, customerInmemory3)); + LOGGER.debug("H2 - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateInmemory); + LOGGER.debug("H2 - Delete customer"); + performDeleteCustomer(customerDAO, 3L); + deleteSchema(customerDAO); + + // Perform CRUD MongoDb + daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.MONGO); + customerDAO = daoFactory.createCustomerDAO(); + ObjectId idCustomerMongo1 = new ObjectId(); + ObjectId idCustomerMongo2 = new ObjectId(); + Customer customer4 = new Customer<>(idCustomerMongo1, "Masca"); + Customer customer5 = new Customer<>(idCustomerMongo2, "Elliot"); + Customer customerUpdateMongo = new Customer<>(idCustomerMongo2, "Henry"); + + LOGGER.debug("Mongo - Create customer"); + performCreateCustomer(customerDAO, List.of(customer4, customer5)); + LOGGER.debug("Mongo - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateMongo); + LOGGER.debug("Mongo - Delete customer"); + performDeleteCustomer(customerDAO, idCustomerMongo2); + deleteSchema(customerDAO); + + // Perform CRUD Flat file + daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.FLAT_FILE); + customerDAO = daoFactory.createCustomerDAO(); + Customer customerFlatFile1 = new Customer<>(1L, "Duc"); + Customer customerFlatFile2 = new Customer<>(2L, "Quang"); + Customer customerFlatFile3 = new Customer<>(3L, "Nhat"); + Customer customerUpdateFlatFile = new Customer<>(1L, "Thanh"); + LOGGER.debug("Flat file - Create customer"); + performCreateCustomer( + customerDAO, List.of(customerFlatFile1, customerFlatFile2, customerFlatFile3)); + LOGGER.debug("Flat file - Update customer"); + performUpdateCustomer(customerDAO, customerUpdateFlatFile); + LOGGER.debug("Flat file - Delete customer"); + performDeleteCustomer(customerDAO, 3L); + deleteSchema(customerDAO); + } + + public static void deleteSchema(CustomerDAO customerDAO) { + customerDAO.deleteSchema(); + } + + public static void performCreateCustomer( + CustomerDAO customerDAO, List> customerList) { + for (Customer customer : customerList) { + customerDAO.save(customer); + } + List> customers = customerDAO.findAll(); + for (Customer customer : customers) { + LOGGER.debug(customer.toString()); + } + } + + public static void performUpdateCustomer( + CustomerDAO customerDAO, Customer customerUpdate) { + customerDAO.update(customerUpdate); + List> customers = customerDAO.findAll(); + for (Customer customer : customers) { + LOGGER.debug(customer.toString()); + } + } + + public static void performDeleteCustomer( + CustomerDAO customerDAO, T customerId) { + customerDAO.delete(customerId); + List> customers = customerDAO.findAll(); + for (Customer customer : customers) { + LOGGER.debug(customer.toString()); + } + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/CustomException.java b/dao-factory/src/main/java/com/iluwatar/daofactory/CustomException.java new file mode 100644 index 000000000000..9559e765c7d4 --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/CustomException.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.daofactory; + +/** Customer exception */ +public class CustomException extends RuntimeException { + public CustomException(String message) { + super(message); + } + + public CustomException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/Customer.java b/dao-factory/src/main/java/com/iluwatar/daofactory/Customer.java new file mode 100644 index 000000000000..95b675487d27 --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/Customer.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.daofactory; + +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +/** + * A customer generic POJO that represents the data that can be stored in any supported data source. + * This class is designed t work with various ID types (e.g., Long, String, or ObjectId) through + * generic, making it adaptable to different persistence system. + */ +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class Customer implements Serializable { + private T id; + private String name; +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/CustomerDAO.java b/dao-factory/src/main/java/com/iluwatar/daofactory/CustomerDAO.java new file mode 100644 index 000000000000..34316b4c49af --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/CustomerDAO.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.daofactory; + +import java.io.Serializable; +import java.util.List; +import java.util.Optional; + +/** + * The Data Access Object (DAO) pattern provides an abstraction layer between the application and + * the database. It encapsulates data access logic, allowing the application to work with domain + * objects instead of direct database operations. + * + *

Implementations handle specific storage mechanisms (e.g., in-memory, databases) while keeping + * client code unchanged. + * + * @see H2CustomerDAO + * @see MongoCustomerDAO + * @see FlatFileCustomerDAO + */ +public interface CustomerDAO { + /** + * Persist the given customer + * + * @param customer the customer to persist + */ + void save(Customer customer); + + /** + * Update the given customer + * + * @param customer the customer to update + */ + void update(Customer customer); + + /** + * Delete the customer with the given id + * + * @param id the id of the customer to delete + */ + void delete(T id); + + /** + * Find all customers + * + * @return a list of customers + */ + List> findAll(); + + /** + * Find the customer with the given id + * + * @param id the id of the customer to find + * @return the customer with the given id + */ + Optional> findById(T id); + + /** + * Delete the customer schema. After executing the statements, this function will be called to + * clean up the data and delete the records. + */ + void deleteSchema(); +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactory.java b/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactory.java new file mode 100644 index 000000000000..e7d33186bec5 --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactory.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.daofactory; + +/** + * An abstract factory class that provides a way to create concrete DAO (Data Access Object) + * factories for different data sources types (e.g., H2, Mongo, FlatFile). + * + *

This class follows the Abstract Factory design pattern, allowing applications to retrieve the + * approriate DAO implementation without being tightly coupled to a specific data source. + * + * @see H2DataSourceFactory + * @see MongoDataSourceFactory + * @see FlatFileDataSourceFactory + */ +public abstract class DAOFactory { + /** + * Retrieves a {@link CustomerDAO} implementation specific to the underlying data source.. + * + * @return A data source-specific implementation of {@link CustomerDAO} + */ + public abstract CustomerDAO createCustomerDAO(); +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactoryProvider.java b/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactoryProvider.java new file mode 100644 index 000000000000..08585622d00d --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/DAOFactoryProvider.java @@ -0,0 +1,62 @@ +/* + * 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.daofactory; + +/** + * {@code DAOFactoryProvider} is a utility class responsible for providing concrete implementations + * of the {@link DAOFactory} interface based on the specified data source type. + * + *

This class acts as an entry point to obtain DAO factories for different storage mechanisms + * such as relational databases (e.g., H2), document stores (e.g., MongoDB), or file-based systems. + * It uses the {@link DataSourceType} enumeration to determine which concrete factory to + * instantiate. + * + *

Example usage: + * + *

{@code
+ * DAOFactory factory = DAOFactoryProvider.getDataSource(DataSourceType.H2);
+ * }
+ */ +public class DAOFactoryProvider { + + private DAOFactoryProvider() {} + + /** + * Returns a concrete {@link DAOFactory} intance based on the specified data source type. + * + * @param dataSourceType The type of data source for which a factory is needed. Supported values: + * {@code H2}, {@code Mongo}, {@code FlatFile} + * @return A {@link DAOFactory} implementation corresponding to the given data source type. + * @throws IllegalArgumentException if the given data source type is not supported. + */ + public static DAOFactory getDataSource(DataSourceType dataSourceType) { + return switch (dataSourceType) { + case H2 -> new H2DataSourceFactory(); + case MONGO -> new MongoDataSourceFactory(); + case FLAT_FILE -> new FlatFileDataSourceFactory(); + default -> throw new IllegalArgumentException("Unsupported data source type"); + }; + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/DataSourceType.java b/dao-factory/src/main/java/com/iluwatar/daofactory/DataSourceType.java new file mode 100644 index 000000000000..da01d451f09e --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/DataSourceType.java @@ -0,0 +1,32 @@ +/* + * 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.daofactory; + +/** Enumerates the types of data sources supported by the application. */ +public enum DataSourceType { + H2, + MONGO, + FLAT_FILE +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileCustomerDAO.java b/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileCustomerDAO.java new file mode 100644 index 000000000000..8f1f1f144f77 --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileCustomerDAO.java @@ -0,0 +1,175 @@ +/* + * 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.daofactory; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * A Flat File implementation of {@link CustomerDAO}, which store the customer data in a JSON file + * at path {@code ~/Desktop/customer.json}. + */ +@Slf4j +@RequiredArgsConstructor +public class FlatFileCustomerDAO implements CustomerDAO { + private final Path filePath; + private final Gson gson; + Type customerListType = new TypeToken>>() {}.getType(); + + protected Reader createReader(Path filePath) throws IOException { + return new FileReader(filePath.toFile()); + } + + protected Writer createWriter(Path filePath) throws IOException { + return new FileWriter(filePath.toFile()); + } + + /** {@inheritDoc} */ + @Override + public void save(Customer customer) { + List> customers = new LinkedList<>(); + if (filePath.toFile().exists()) { + try (Reader reader = createReader(filePath)) { + customers = gson.fromJson(reader, customerListType); + } catch (IOException ex) { + throw new CustomException("Failed to read customer data", ex); + } + } + customers.add(customer); + try (Writer writer = createWriter(filePath)) { + gson.toJson(customers, writer); + } catch (IOException ex) { + throw new CustomException("Failed to write customer data", ex); + } + } + + /** {@inheritDoc} */ + @Override + public void update(Customer customer) { + if (!filePath.toFile().exists()) { + throw new CustomException("File not found"); + } + List> customers; + try (Reader reader = createReader(filePath)) { + customers = gson.fromJson(reader, customerListType); + } catch (IOException ex) { + throw new CustomException("Failed to read customer data", ex); + } + customers.stream() + .filter(c -> c.getId().equals(customer.getId())) + .findFirst() + .ifPresentOrElse( + c -> c.setName(customer.getName()), + () -> { + throw new CustomException("Customer not found with id: " + customer.getId()); + }); + try (Writer writer = createWriter(filePath)) { + gson.toJson(customers, writer); + } catch (IOException ex) { + throw new CustomException("Failed to write customer data", ex); + } + } + + /** {@inheritDoc} */ + @Override + public void delete(Long id) { + if (!filePath.toFile().exists()) { + throw new CustomException("File not found"); + } + List> customers; + try (Reader reader = createReader(filePath)) { + customers = gson.fromJson(reader, customerListType); + } catch (IOException ex) { + throw new CustomException("Failed to read customer data", ex); + } + Customer customerToRemove = + customers.stream() + .filter(c -> c.getId().equals(id)) + .findFirst() + .orElseThrow(() -> new CustomException("Customer not found with id: " + id)); + customers.remove(customerToRemove); + try (Writer writer = createWriter(filePath)) { + gson.toJson(customers, writer); + } catch (IOException ex) { + throw new CustomException("Failed to write customer data", ex); + } + } + + /** {@inheritDoc} */ + @Override + public List> findAll() { + if (!filePath.toFile().exists()) { + throw new CustomException("File not found"); + } + List> customers; + try (Reader reader = createReader(filePath)) { + customers = gson.fromJson(reader, customerListType); + } catch (IOException ex) { + throw new CustomException("Failed to read customer data", ex); + } + return customers; + } + + /** {@inheritDoc} */ + @Override + public Optional> findById(Long id) { + if (!filePath.toFile().exists()) { + throw new CustomException("File not found"); + } + List> customers = null; + try (Reader reader = createReader(filePath)) { + customers = gson.fromJson(reader, customerListType); + } catch (IOException ex) { + throw new CustomException("Failed to read customer data", ex); + } + return customers.stream().filter(c -> c.getId().equals(id)).findFirst(); + } + + /** {@inheritDoc} */ + @Override + public void deleteSchema() { + if (!filePath.toFile().exists()) { + throw new CustomException("File not found"); + } + try { + Files.delete(filePath); + } catch (IOException ex) { + throw new CustomException("Failed to delete customer data"); + } + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileDataSourceFactory.java b/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileDataSourceFactory.java new file mode 100644 index 000000000000..f423376703b5 --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/FlatFileDataSourceFactory.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.daofactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** FlatFileDataSourceFactory concrete factory. */ +public class FlatFileDataSourceFactory extends DAOFactory { + private static final String FILE_PATH = + System.getProperty("user.home") + "/Desktop/customer.json"; + + @Override + public CustomerDAO createCustomerDAO() { + Path filePath = Paths.get(FILE_PATH); + Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls().create(); + return new FlatFileCustomerDAO(filePath, gson); + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/H2CustomerDAO.java b/dao-factory/src/main/java/com/iluwatar/daofactory/H2CustomerDAO.java new file mode 100644 index 000000000000..fe027426391c --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/H2CustomerDAO.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.daofactory; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import javax.sql.DataSource; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +/** + * An implementation of {@link CustomerDAO} that uses H2 database (http://www.h2database.com/) which + * is an in-memory database and data will lost after application exits. + */ +@Slf4j +@RequiredArgsConstructor +public class H2CustomerDAO implements CustomerDAO { + private final DataSource dataSource; + private static final String INSERT_CUSTOMER = "INSERT INTO customer(id, name) VALUES (?, ?)"; + private static final String UPDATE_CUSTOMER = "UPDATE customer SET name = ? WHERE id = ?"; + private static final String DELETE_CUSTOMER = "DELETE FROM customer WHERE id = ?"; + private static final String SELECT_CUSTOMER_BY_ID = + "SELECT customer.id, customer.name FROM customer WHERE id= ?"; + private static final String SELECT_ALL_CUSTOMERS = "SELECT customer.* FROM customer"; + private static final String CREATE_SCHEMA = + "CREATE TABLE IF NOT EXISTS customer (id BIGINT PRIMARY KEY, name VARCHAR(255))"; + private static final String DROP_SCHEMA = "DROP TABLE IF EXISTS customer"; + + /** {@inheritDoc} */ + @Override + public void save(Customer customer) { + try (Connection connection = dataSource.getConnection(); + PreparedStatement saveStatement = connection.prepareStatement(INSERT_CUSTOMER)) { + saveStatement.setLong(1, customer.getId()); + saveStatement.setString(2, customer.getName()); + saveStatement.execute(); + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + } + + /** {@inheritDoc} */ + @Override + public void update(Customer customer) { + if (Objects.isNull(customer) || Objects.isNull(customer.getId())) { + throw new CustomException("Custome null or customer id null"); + } + try (Connection connection = dataSource.getConnection(); + PreparedStatement selectStatement = connection.prepareStatement(SELECT_CUSTOMER_BY_ID); + PreparedStatement updateStatement = connection.prepareStatement(UPDATE_CUSTOMER)) { + selectStatement.setLong(1, customer.getId()); + try (ResultSet resultSet = selectStatement.executeQuery()) { + if (!resultSet.next()) { + throw new CustomException("Customer not found with id: " + customer.getId()); + } + } + updateStatement.setString(1, customer.getName()); + updateStatement.setLong(2, customer.getId()); + updateStatement.executeUpdate(); + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + } + + /** {@inheritDoc} */ + @Override + public void delete(Long id) { + if (Objects.isNull(id)) { + throw new CustomException("Customer id null"); + } + try (Connection connection = dataSource.getConnection(); + PreparedStatement selectStatement = connection.prepareStatement(SELECT_CUSTOMER_BY_ID); + PreparedStatement deleteStatement = connection.prepareStatement(DELETE_CUSTOMER)) { + selectStatement.setLong(1, id); + try (ResultSet resultSet = selectStatement.executeQuery()) { + if (!resultSet.next()) { + throw new CustomException("Customer not found with id: " + id); + } + } + deleteStatement.setLong(1, id); + deleteStatement.execute(); + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + } + + /** {@inheritDoc} */ + @Override + public List> findAll() { + List> customers = new LinkedList<>(); + try (Connection connection = dataSource.getConnection(); + PreparedStatement selectStatement = connection.prepareStatement(SELECT_ALL_CUSTOMERS)) { + try (ResultSet resultSet = selectStatement.executeQuery()) { + while (resultSet.next()) { + Long idCustomer = resultSet.getLong("id"); + String nameCustomer = resultSet.getString("name"); + customers.add(new Customer<>(idCustomer, nameCustomer)); + } + } + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + return customers; + } + + /** {@inheritDoc} */ + @Override + public Optional> findById(Long id) { + if (Objects.isNull(id)) { + throw new CustomException("Customer id null"); + } + Customer customer = null; + try (Connection connection = dataSource.getConnection(); + PreparedStatement selectByIdStatement = + connection.prepareStatement(SELECT_CUSTOMER_BY_ID)) { + selectByIdStatement.setLong(1, id); + try (ResultSet resultSet = selectByIdStatement.executeQuery()) { + while (resultSet.next()) { + Long idCustomer = resultSet.getLong("id"); + String nameCustomer = resultSet.getString("name"); + customer = new Customer<>(idCustomer, nameCustomer); + } + } + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + return Optional.ofNullable(customer); + } + + /** Create customer schema. */ + public void createSchema() { + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement()) { + statement.execute(CREATE_SCHEMA); + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + } + + /** {@inheritDoc}} */ + @Override + public void deleteSchema() { + try (Connection connection = dataSource.getConnection(); + Statement statement = connection.createStatement(); ) { + statement.execute(DROP_SCHEMA); + } catch (SQLException e) { + throw new CustomException(e.getMessage(), e); + } + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/H2DataSourceFactory.java b/dao-factory/src/main/java/com/iluwatar/daofactory/H2DataSourceFactory.java new file mode 100644 index 000000000000..dbb39dd98f3b --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/H2DataSourceFactory.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.daofactory; + +import javax.sql.DataSource; +import org.h2.jdbcx.JdbcDataSource; + +/** H2DataSourceFactory concrete factory. */ +public class H2DataSourceFactory extends DAOFactory { + private static final String DB_URL = "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; + private static final String USER = "sa"; + private static final String PASS = ""; + + @Override + public CustomerDAO createCustomerDAO() { + return new H2CustomerDAO(createDataSource()); + } + + private DataSource createDataSource() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + dataSource.setUser(USER); + dataSource.setPassword(PASS); + return dataSource; + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/MongoCustomerDAO.java b/dao-factory/src/main/java/com/iluwatar/daofactory/MongoCustomerDAO.java new file mode 100644 index 000000000000..1870f61e85fd --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/MongoCustomerDAO.java @@ -0,0 +1,106 @@ +/* + * 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.daofactory; + +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import com.mongodb.client.result.DeleteResult; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.types.ObjectId; + +/** An implementation of {@link CustomerDAO} that uses MongoDB (https://www.mongodb.com/) */ +@Slf4j +@RequiredArgsConstructor +public class MongoCustomerDAO implements CustomerDAO { + private final MongoCollection customerCollection; + + /** {@inheritDoc} */ + @Override + public void save(Customer customer) { + Document customerDocument = new Document("_id", customer.getId()); + customerDocument.append("name", customer.getName()); + customerCollection.insertOne(customerDocument); + } + + /** {@inheritDoc} */ + @Override + public void update(Customer customer) { + Document updateQuery = new Document("_id", customer.getId()); + Bson update = Updates.set("name", customer.getName()); + customerCollection.updateOne(updateQuery, update); + } + + /** {@inheritDoc} */ + @Override + public void delete(ObjectId objectId) { + Bson deleteQuery = Filters.eq("_id", objectId); + DeleteResult deleteResult = customerCollection.deleteOne(deleteQuery); + if (deleteResult.getDeletedCount() == 0) { + throw new CustomException("Delete failed: No document found with id: " + objectId); + } + } + + /** {@inheritDoc} */ + @Override + public List> findAll() { + List> customers = new LinkedList<>(); + FindIterable customerDocuments = customerCollection.find(); + for (Document customerDocument : customerDocuments) { + Customer customer = + new Customer<>( + (ObjectId) customerDocument.get("_id"), customerDocument.getString("name")); + customers.add(customer); + } + return customers; + } + + /** {@inheritDoc} */ + @Override + public Optional> findById(ObjectId objectId) { + Bson filter = Filters.eq("_id", objectId); + Document customerDocument = customerCollection.find(filter).first(); + Customer customerResult = null; + if (customerDocument != null) { + customerResult = + new Customer<>( + (ObjectId) customerDocument.get("_id"), customerDocument.getString("name")); + } + return Optional.ofNullable(customerResult); + } + + /** {@inheritDoc} */ + @Override + public void deleteSchema() { + customerCollection.drop(); + } +} diff --git a/dao-factory/src/main/java/com/iluwatar/daofactory/MongoDataSourceFactory.java b/dao-factory/src/main/java/com/iluwatar/daofactory/MongoDataSourceFactory.java new file mode 100644 index 000000000000..5a7b1f1b1ece --- /dev/null +++ b/dao-factory/src/main/java/com/iluwatar/daofactory/MongoDataSourceFactory.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.daofactory; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.bson.types.ObjectId; + +/** MongoDataSourceFactory concrete factory. */ +public class MongoDataSourceFactory extends DAOFactory { + private static final String CONN_STR = "mongodb://localhost:27017/"; + private static final String DB_NAME = "dao_factory"; + private static final String COLLECTION_NAME = "customer"; + + @Override + public CustomerDAO createCustomerDAO() { + try { + MongoClient mongoClient = MongoClients.create(CONN_STR); + MongoDatabase database = mongoClient.getDatabase(DB_NAME); + MongoCollection customerCollection = database.getCollection(COLLECTION_NAME); + return new MongoCustomerDAO(customerCollection); + } catch (CustomException e) { + throw new CustomException("Error: " + e); + } + } +} diff --git a/dao-factory/src/main/resources/logback.xml b/dao-factory/src/main/resources/logback.xml new file mode 100644 index 000000000000..f82341ebb2ab --- /dev/null +++ b/dao-factory/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) %cyan(%logger{15}) %logger{36} - %msg%n + + + + + + + + \ No newline at end of file diff --git a/dao-factory/src/test/java/com/iluwatar/daofactory/AppTest.java b/dao-factory/src/test/java/com/iluwatar/daofactory/AppTest.java new file mode 100644 index 000000000000..12efea42bdc6 --- /dev/null +++ b/dao-factory/src/test/java/com/iluwatar/daofactory/AppTest.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.daofactory; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import org.bson.types.ObjectId; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** {@link App} */ +class AppTest { + /** Test perform CRUD in main class */ + private CustomerDAO mockLongCustomerDAO; + + private CustomerDAO mockObjectIdCustomerDAO; + + @BeforeEach + void setUp() { + mockLongCustomerDAO = mock(CustomerDAO.class); + mockObjectIdCustomerDAO = mock(CustomerDAO.class); + } + + @Test + void testPerformCreateCustomerWithLongId() { + Customer c1 = new Customer<>(1L, "Test1"); + Customer c2 = new Customer<>(2L, "Test2"); + + when(mockLongCustomerDAO.findAll()).thenReturn(List.of(c1, c2)); + + App.performCreateCustomer(mockLongCustomerDAO, List.of(c1, c2)); + + verify(mockLongCustomerDAO).save(c1); + verify(mockLongCustomerDAO).save(c2); + verify(mockLongCustomerDAO).findAll(); + } + + @Test + void testPerformUpdateCustomerWithObjectId() { + ObjectId id = new ObjectId(); + Customer updatedCustomer = new Customer<>(id, "Updated"); + + when(mockObjectIdCustomerDAO.findAll()).thenReturn(List.of(updatedCustomer)); + + App.performUpdateCustomer(mockObjectIdCustomerDAO, updatedCustomer); + + verify(mockObjectIdCustomerDAO).update(updatedCustomer); + verify(mockObjectIdCustomerDAO).findAll(); + } + + @Test + void testPerformDeleteCustomerWithLongId() { + Long id = 100L; + Customer remainingCustomer = new Customer<>(1L, "Remaining"); + + when(mockLongCustomerDAO.findAll()).thenReturn(List.of(remainingCustomer)); + + App.performDeleteCustomer(mockLongCustomerDAO, id); + + verify(mockLongCustomerDAO).delete(id); + verify(mockLongCustomerDAO).findAll(); + } + + @Test + void testDeleteSchema() { + App.deleteSchema(mockLongCustomerDAO); + verify(mockLongCustomerDAO).deleteSchema(); + } +} diff --git a/dao-factory/src/test/java/com/iluwatar/daofactory/DAOFactoryTest.java b/dao-factory/src/test/java/com/iluwatar/daofactory/DAOFactoryTest.java new file mode 100644 index 000000000000..f8aaf199762d --- /dev/null +++ b/dao-factory/src/test/java/com/iluwatar/daofactory/DAOFactoryTest.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, 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.daofactory; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; + +import org.junit.jupiter.api.Test; + +/** {@link DAOFactory} */ +class DAOFactoryTest { + + @Test + void verifyH2CustomerDAOCreation() { + var daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.H2); + var customerDAO = daoFactory.createCustomerDAO(); + assertInstanceOf(H2CustomerDAO.class, customerDAO); + } + + @Test + void verifyMongoCustomerDAOCreation() { + var daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.MONGO); + var customerDAO = daoFactory.createCustomerDAO(); + assertInstanceOf(MongoCustomerDAO.class, customerDAO); + } + + @Test + void verifyFlatFileCustomerDAOCreation() { + var daoFactory = DAOFactoryProvider.getDataSource(DataSourceType.FLAT_FILE); + var customerDAO = daoFactory.createCustomerDAO(); + assertInstanceOf(FlatFileCustomerDAO.class, customerDAO); + } +} diff --git a/dao-factory/src/test/java/com/iluwatar/daofactory/FlatFileCustomerDAOTest.java b/dao-factory/src/test/java/com/iluwatar/daofactory/FlatFileCustomerDAOTest.java new file mode 100644 index 000000000000..470964f4217a --- /dev/null +++ b/dao-factory/src/test/java/com/iluwatar/daofactory/FlatFileCustomerDAOTest.java @@ -0,0 +1,500 @@ +/* + * 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.daofactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +/** {@link FlatFileCustomerDAO} */ +class FlatFileCustomerDAOTest { + private Path filePath; + private File file; + private Gson gson; + + private final Type customerListType = new TypeToken>>() {}.getType(); + private final Customer existingCustomer = new Customer<>(1L, "Thanh"); + private FlatFileCustomerDAO flatFileCustomerDAO; + private FileReader fileReader; + private FileWriter fileWriter; + + @BeforeEach + void setUp() { + filePath = mock(Path.class); + file = mock(File.class); + gson = mock(Gson.class); + fileReader = mock(FileReader.class); + fileWriter = mock(FileWriter.class); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + return fileWriter; + } + }; + when(filePath.toFile()).thenReturn(file); + } + + /** Class test with scenario Save Customer */ + @Nested + class Save { + @Test + void giveFilePathNotExist_whenSaveCustomer_thenCreateNewFileWithCustomer() { + when(file.exists()).thenReturn(false); + flatFileCustomerDAO.save(existingCustomer); + + verify(gson) + .toJson( + argThat( + (List> list) -> + list.size() == 1 && list.getFirst().equals(existingCustomer)), + eq(fileWriter)); + } + + @Test + void givenEmptyFileExist_whenSaveCustomer_thenAddCustomer() { + when(file.exists()).thenReturn(true); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(new LinkedList<>()); + flatFileCustomerDAO.save(existingCustomer); + + verify(gson).fromJson(fileReader, customerListType); + verify(gson) + .toJson( + argThat( + (List> list) -> + list.size() == 1 && list.getFirst().equals(existingCustomer)), + eq(fileWriter)); + } + + @Test + void givenFileWithCustomerExist_whenSaveCustomer_thenShouldAppendCustomer() { + List> customers = new LinkedList<>(); + customers.add(new Customer<>(2L, "Duc")); + customers.add(new Customer<>(3L, "Nguyen")); + when(file.exists()).thenReturn(true); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(customers); + + flatFileCustomerDAO.save(existingCustomer); + + verify(gson).fromJson(fileReader, customerListType); + verify(gson).toJson(argThat((List> list) -> list.size() == 3), eq(fileWriter)); + } + + @Test + void whenReadFails_thenThrowException() { + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + throw new IOException("Failed to read file"); + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + when(file.exists()).thenReturn(true); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.save(existingCustomer)); + } + + @Test + void whenWriteFails_thenThrowException() { + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(new LinkedList<>()); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + throw new IOException("Failed to write file"); + } + }; + when(file.exists()).thenReturn(true); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.save(existingCustomer)); + } + } + + /** Class test with scenario Update Customer */ + @Nested + class Update { + @Test + void givenFilePathNotExist_whenUpdateCustomer_thenThrowException() { + when(file.exists()).thenReturn(false); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.update(existingCustomer)); + } + + @Test + void whenReadFails_thenThrowException() { + when(file.exists()).thenReturn(true); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + throw new IOException("Failed to read file"); + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.update(existingCustomer)); + } + + @Test + void whenWriteFails_thenThrowException() { + when(file.exists()).thenReturn(true); + when(gson.fromJson(any(Reader.class), eq(customerListType))) + .thenReturn( + new LinkedList<>() { + { + add(new Customer<>(1L, "Quang")); + } + }); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + throw new IOException("Failed to write file"); + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.update(existingCustomer)); + } + + @Test + void givenValidCustomer_whenUpdateCustomer_thenUpdateSucceed() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + return fileWriter; + } + }; + flatFileCustomerDAO.update(existingCustomer); + verify(gson) + .toJson( + argThat( + (List> customers) -> + customers.size() == 1 + && customers.stream() + .anyMatch(c -> c.getId().equals(1L) && c.getName().equals("Thanh"))), + eq(fileWriter)); + } + + @Test + void givenIdCustomerNotExist_whenUpdateCustomer_thenThrowException() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(2L, "Quang")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.update(existingCustomer)); + } + } + + /** Class test with scenario Delete Customer */ + @Nested + class Delete { + @Test + void givenFilePathNotExist_whenDeleteCustomer_thenThrowException() { + when(file.exists()).thenReturn(false); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.delete(1L)); + } + + @Test + void whenReadFails_thenThrowException() { + when(file.exists()).thenReturn(true); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + throw new IOException("Failed to read file"); + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.delete(1L)); + } + + @Test + void whenWriteFails_thenThrowException() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) throws IOException { + throw new IOException("Failed to write file"); + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.delete(1L)); + } + + @Test + void givenValidId_whenDeleteCustomer_thenDeleteSucceed() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + existingListCustomer.add(new Customer<>(2L, "Thanh")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + + flatFileCustomerDAO.delete(1L); + assertEquals(1, existingListCustomer.size()); + verify(gson) + .toJson( + argThat( + (List> customers) -> + customers.stream() + .noneMatch(c -> c.getId().equals(1L) && c.getName().equals("Quang"))), + eq(fileWriter)); + } + + @Test + void givenIdNotExist_whenDeleteCustomer_thenThrowException() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + existingListCustomer.add(new Customer<>(2L, "Thanh")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) { + return fileReader; + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.delete(3L)); + } + } + + /** Class test with scenario Find All Customer */ + @Nested + class FindAll { + @Test + void givenFileNotExist_thenThrowException() { + when(file.exists()).thenReturn(false); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.findAll()); + } + + @Test + void whenReadFails_thenThrowException() { + when(file.exists()).thenReturn(true); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + throw new IOException("Failed to read file"); + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.findAll()); + } + + @Test + void givenEmptyCustomer_thenReturnEmptyList() { + when(file.exists()).thenReturn(true); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(new LinkedList<>()); + List> customers = flatFileCustomerDAO.findAll(); + assertEquals(0, customers.size()); + verify(gson).fromJson(fileReader, customerListType); + } + + @Test + void givenCustomerExist_thenReturnCustomerList() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + existingListCustomer.add(new Customer<>(2L, "Thanh")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + List> customers = flatFileCustomerDAO.findAll(); + assertEquals(2, customers.size()); + } + } + + /** Class test with scenario Find By Id Customer */ + @Nested + class FindById { + + @Test + void givenFilePathNotExist_whenFindById_thenThrowException() { + when(file.exists()).thenReturn(false); + assertThrows(CustomException.class, () -> flatFileCustomerDAO.findById(1L)); + } + + @Test + void whenReadFails_thenThrowException() { + when(file.exists()).thenReturn(true); + flatFileCustomerDAO = + new FlatFileCustomerDAO(filePath, gson) { + @Override + protected Reader createReader(Path filePath) throws IOException { + throw new IOException("Failed to read file"); + } + + @Override + protected Writer createWriter(Path filePath) { + return fileWriter; + } + }; + assertThrows(CustomException.class, () -> flatFileCustomerDAO.findById(1L)); + } + + @Test + void givenIdCustomerExist_whenFindById_thenReturnCustomer() { + when(file.exists()).thenReturn(true); + List> existingListCustomer = new LinkedList<>(); + existingListCustomer.add(new Customer<>(1L, "Quang")); + existingListCustomer.add(new Customer<>(2L, "Thanh")); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(existingListCustomer); + Optional> customer = flatFileCustomerDAO.findById(1L); + assertTrue(customer.isPresent()); + assertEquals("Quang", customer.get().getName()); + } + + @Test + void givenIdCustomerNotExist_whenFindById_thenReturnEmpty() { + when(file.exists()).thenReturn(true); + when(gson.fromJson(any(Reader.class), eq(customerListType))).thenReturn(new LinkedList<>()); + Optional> customers = flatFileCustomerDAO.findById(1L); + assertTrue(customers.isEmpty()); + } + } + + /** Clas test with scenario Delete schema */ + @Nested + class DeleteSchema { + @Test + void givenFilePathExist_thenDeleteFile() { + when(file.exists()).thenReturn(true); + + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + flatFileCustomerDAO.deleteSchema(); + mockedFiles.verify(() -> Files.delete(filePath), times(1)); + } + } + + @Test + void givenFilePathNotExist_thenThrowException() { + when(file.exists()).thenReturn(false); + + try (MockedStatic mockedFiles = mockStatic(Files.class)) { + assertThrows(CustomException.class, () -> flatFileCustomerDAO.deleteSchema()); + mockedFiles.verify(() -> Files.delete(filePath), times(0)); + } + } + } +} diff --git a/dao-factory/src/test/java/com/iluwatar/daofactory/H2CustomerDAOTest.java b/dao-factory/src/test/java/com/iluwatar/daofactory/H2CustomerDAOTest.java new file mode 100644 index 000000000000..ce7def36e5bc --- /dev/null +++ b/dao-factory/src/test/java/com/iluwatar/daofactory/H2CustomerDAOTest.java @@ -0,0 +1,300 @@ +/* + * 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.daofactory; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.List; +import javax.sql.DataSource; +import org.h2.jdbcx.JdbcDataSource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +/** Tests {@link H2CustomerDAO} */ +class H2CustomerDAOTest { + private static final String DB_URL = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1"; + private static final String USER = "sa"; + private static final String PASS = ""; + private static final String CREATE_SCHEMA = + "CREATE TABLE IF NOT EXISTS customer (id BIGINT PRIMARY KEY, name VARCHAR(255))"; + private static final String DROP_SCHEMA = "DROP TABLE IF EXISTS customer"; + private final Customer existingCustomer = new Customer<>(1L, "Nguyen"); + private H2CustomerDAO h2CustomerDAO; + + @BeforeEach + void createSchema() throws SQLException { + try (var connection = DriverManager.getConnection(DB_URL, USER, PASS); + var statement = connection.createStatement()) { + statement.execute(CREATE_SCHEMA); + } + } + + @AfterEach + void deleteSchema() throws SQLException { + try (var connection = DriverManager.getConnection(DB_URL, USER, PASS); + var statement = connection.createStatement()) { + statement.execute(DROP_SCHEMA); + } + } + + /** Class test for scenario connect with datasource succeed */ + @Nested + class ConnectionSucceed { + + @BeforeEach + void setUp() { + var dataSource = new JdbcDataSource(); + dataSource.setURL(DB_URL); + dataSource.setUser(USER); + dataSource.setPassword(PASS); + h2CustomerDAO = new H2CustomerDAO(dataSource); + assertDoesNotThrow(() -> h2CustomerDAO.save(existingCustomer)); + var customer = h2CustomerDAO.findById(existingCustomer.getId()); + assertTrue(customer.isPresent()); + assertEquals(customer.get().getName(), existingCustomer.getName()); + assertEquals(customer.get().getId(), existingCustomer.getId()); + } + + @Nested + class SaveCustomer { + @Test + void givenValidCustomer_whenSaveCustomer_thenAddSucceed() { + var customer = new Customer<>(2L, "Duc"); + assertDoesNotThrow(() -> h2CustomerDAO.save(customer)); + var customerInDb = h2CustomerDAO.findById(customer.getId()); + assertTrue(customerInDb.isPresent()); + assertEquals(customerInDb.get().getName(), customer.getName()); + assertEquals(customerInDb.get().getId(), customer.getId()); + List> customers = h2CustomerDAO.findAll(); + assertEquals(2, customers.size()); + } + + @Test + void givenIdCustomerDuplicated_whenSaveCustomer_thenThrowException() { + var customer = new Customer<>(existingCustomer.getId(), "Duc"); + assertThrows(CustomException.class, () -> h2CustomerDAO.save(customer)); + List> customers = h2CustomerDAO.findAll(); + assertEquals(1, customers.size()); + } + } + + @Nested + class UpdateCustomer { + @Test + void givenValidCustomer_whenUpdateCustomer_thenUpdateSucceed() { + var customerUpdate = new Customer<>(existingCustomer.getId(), "Duc"); + assertDoesNotThrow(() -> h2CustomerDAO.update(customerUpdate)); + var customerInDb = h2CustomerDAO.findById(customerUpdate.getId()); + assertTrue(customerInDb.isPresent()); + assertEquals(customerInDb.get().getName(), customerUpdate.getName()); + } + + @Test + void givenIdCustomerNotExist_whenUpdateCustomer_thenThrowException() { + var customerUpdate = new Customer<>(100L, "Duc"); + var customerInDb = h2CustomerDAO.findById(customerUpdate.getId()); + assertTrue(customerInDb.isEmpty()); + assertThrows(CustomException.class, () -> h2CustomerDAO.update(customerUpdate)); + } + + @Test + void givenNull_whenUpdateCustomer_thenThrowException() { + assertThrows(CustomException.class, () -> h2CustomerDAO.update(null)); + List> customers = h2CustomerDAO.findAll(); + assertEquals(1, customers.size()); + } + } + + @Nested + class DeleteCustomer { + @Test + void givenValidId_whenDeleteCustomer_thenDeleteSucceed() { + assertDoesNotThrow(() -> h2CustomerDAO.delete(existingCustomer.getId())); + var customerInDb = h2CustomerDAO.findById(existingCustomer.getId()); + assertTrue(customerInDb.isEmpty()); + List> customers = h2CustomerDAO.findAll(); + assertEquals(0, customers.size()); + } + + @Test + void givenIdCustomerNotExist_whenDeleteCustomer_thenThrowException() { + var customerInDb = h2CustomerDAO.findById(100L); + assertTrue(customerInDb.isEmpty()); + assertThrows(CustomException.class, () -> h2CustomerDAO.delete(100L)); + List> customers = h2CustomerDAO.findAll(); + assertEquals(1, customers.size()); + assertEquals(existingCustomer.getName(), customers.get(0).getName()); + assertEquals(existingCustomer.getId(), customers.get(0).getId()); + } + + @Test + void givenNull_whenDeleteCustomer_thenThrowException() { + assertThrows(CustomException.class, () -> h2CustomerDAO.delete(null)); + List> customers = h2CustomerDAO.findAll(); + assertEquals(1, customers.size()); + assertEquals(existingCustomer.getName(), customers.get(0).getName()); + } + } + + @Nested + class FindAllCustomers { + @Test + void givenNonCustomerInDb_whenFindAllCustomer_thenReturnEmptyList() { + assertDoesNotThrow(() -> h2CustomerDAO.delete(existingCustomer.getId())); + List> customers = h2CustomerDAO.findAll(); + assertEquals(0, customers.size()); + } + + @Test + void givenCustomerExistInDb_whenFindAllCustomer_thenReturnCustomers() { + List> customers = h2CustomerDAO.findAll(); + assertEquals(1, customers.size()); + assertEquals(existingCustomer.getName(), customers.get(0).getName()); + assertEquals(existingCustomer.getId(), customers.get(0).getId()); + } + } + + @Nested + class FindCustomerById { + @Test + void givenValidId_whenFindById_thenReturnCustomer() { + var customerInDb = h2CustomerDAO.findById(existingCustomer.getId()); + assertTrue(customerInDb.isPresent()); + assertEquals(existingCustomer.getName(), customerInDb.get().getName()); + assertEquals(existingCustomer.getId(), customerInDb.get().getId()); + } + + @Test + void givenIdCustomerNotExist_whenFindById_thenReturnEmpty() { + var customerNotExist = h2CustomerDAO.findById(100L); + assertTrue(customerNotExist.isEmpty()); + } + + @Test + void givenNull_whenFindById_thenThrowException() { + assertThrows(CustomException.class, () -> h2CustomerDAO.findById(null)); + } + } + + @Nested + class CreateSchema { + @Test + void whenCreateSchema_thenNotThrowException() { + assertDoesNotThrow(() -> h2CustomerDAO.createSchema()); + } + } + + @Nested + class DeleteSchema { + @Test + void whenDeleteSchema_thenNotThrowException() { + assertDoesNotThrow(() -> h2CustomerDAO.deleteSchema()); + } + } + } + + /** Class test with scenario connect with data source failed */ + @Nested + class ConnectionFailed { + private static final String EXCEPTION_CAUSE = "Connection not available"; + + @BeforeEach + void setUp() throws SQLException { + h2CustomerDAO = new H2CustomerDAO(mockedDataSource()); + } + + private DataSource mockedDataSource() throws SQLException { + var mockedDataSource = mock(DataSource.class); + var mockedConnection = mock(Connection.class); + var exception = new SQLException(EXCEPTION_CAUSE); + doThrow(exception).when(mockedConnection).prepareStatement(Mockito.anyString()); + doThrow(exception).when(mockedConnection).createStatement(); + doReturn(mockedConnection).when(mockedDataSource).getConnection(); + return mockedDataSource; + } + + @Test + void givenValidCustomer_whenSaveCustomer_thenThrowException() { + var customer = new Customer<>(2L, "Duc"); + CustomException exception = + assertThrows(CustomException.class, () -> h2CustomerDAO.save(customer)); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void givenValidCustomer_whenUpdateCustomer_thenThrowException() { + var customerUpdate = new Customer<>(existingCustomer.getId(), "Duc"); + CustomException exception = + assertThrows(CustomException.class, () -> h2CustomerDAO.update(customerUpdate)); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void givenValidId_whenDeleteCustomer_thenThrowException() { + Long idCustomer = existingCustomer.getId(); + CustomException exception = + assertThrows(CustomException.class, () -> h2CustomerDAO.delete(idCustomer)); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void whenFindAll_thenThrowException() { + CustomException exception = assertThrows(CustomException.class, h2CustomerDAO::findAll); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void whenFindById_thenThrowException() { + Long idCustomer = existingCustomer.getId(); + CustomException exception = + assertThrows(CustomException.class, () -> h2CustomerDAO.findById(idCustomer)); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void whenCreateSchema_thenThrowException() { + CustomException exception = assertThrows(CustomException.class, h2CustomerDAO::createSchema); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + + @Test + void whenDeleteSchema_thenThrowException() { + CustomException exception = assertThrows(CustomException.class, h2CustomerDAO::deleteSchema); + assertEquals(EXCEPTION_CAUSE, exception.getMessage()); + } + } +} diff --git a/dao-factory/src/test/java/com/iluwatar/daofactory/MongoCustomerDAOTest.java b/dao-factory/src/test/java/com/iluwatar/daofactory/MongoCustomerDAOTest.java new file mode 100644 index 000000000000..c56e72c30389 --- /dev/null +++ b/dao-factory/src/test/java/com/iluwatar/daofactory/MongoCustomerDAOTest.java @@ -0,0 +1,163 @@ +/* + * 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.daofactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.mongodb.client.FindIterable; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoCursor; +import com.mongodb.client.model.Filters; +import com.mongodb.client.result.DeleteResult; +import com.mongodb.client.result.UpdateResult; +import java.util.List; +import java.util.Optional; +import org.bson.BsonDocument; +import org.bson.Document; +import org.bson.conversions.Bson; +import org.bson.types.ObjectId; +import org.junit.jupiter.api.Test; + +/** Tests {@link MongoCustomerDAO} */ +class MongoCustomerDAOTest { + MongoCollection customerCollection = mock(MongoCollection.class); + MongoCustomerDAO mongoCustomerDAO = new MongoCustomerDAO(customerCollection); + + @Test + void givenValidCustomer_whenSaveCustomer_thenSaveSucceed() { + Customer customer = new Customer<>(new ObjectId(), "John"); + mongoCustomerDAO.save(customer); + verify(customerCollection) + .insertOne( + argThat( + document -> + document.get("_id").equals(customer.getId()) + && document.get("name").equals(customer.getName()))); + } + + @Test + void givenValidCustomer_whenUpdateCustomer_thenUpdateSucceed() { + ObjectId customerId = new ObjectId(); + Customer customerUpdated = new Customer<>(customerId, "John"); + when(customerCollection.updateOne(any(Bson.class), any(Bson.class))) + .thenReturn(UpdateResult.acknowledged(1L, 1L, null)); + mongoCustomerDAO.update(customerUpdated); + verify(customerCollection) + .updateOne( + argThat( + (Bson filter) -> { + Document filterDoc = (Document) filter; + return filterDoc.getObjectId("_id").equals(customerId); + }), + argThat( + (Bson update) -> { + BsonDocument bsonDoc = update.toBsonDocument(); + BsonDocument setDoc = bsonDoc.getDocument("$set"); + return setDoc.getString("name").getValue().equals(customerUpdated.getName()); + })); + } + + @Test + void givenValidObjectId_whenDeleteCustomer_thenDeleteSucceed() { + ObjectId customerId = new ObjectId(); + when(customerCollection.deleteOne(any(Bson.class))).thenReturn(DeleteResult.acknowledged(1)); + mongoCustomerDAO.delete(customerId); + verify(customerCollection) + .deleteOne( + argThat( + (Bson filter) -> { + BsonDocument filterDoc = filter.toBsonDocument(); + return filterDoc.getObjectId("_id").getValue().equals(customerId); + })); + } + + @Test + void givenIdNotExist_whenDeleteCustomer_thenThrowException() { + ObjectId customerId = new ObjectId(); + when(customerCollection.deleteOne(any(Bson.class))).thenReturn(DeleteResult.acknowledged(0)); + assertThrows(CustomException.class, () -> mongoCustomerDAO.delete(customerId)); + verify(customerCollection) + .deleteOne( + argThat( + (Bson filter) -> { + BsonDocument filterDoc = filter.toBsonDocument(); + return filterDoc.getObjectId("_id").getValue().equals(customerId); + })); + } + + @Test + void findAll_thenReturnAllCustomers() { + FindIterable findIterable = mock(FindIterable.class); + MongoCursor cursor = mock(MongoCursor.class); + Document customerDoc1 = new Document("_id", new ObjectId()).append("name", "Duc"); + Document customerDoc2 = new Document("_id", new ObjectId()).append("name", "Thanh"); + when(customerCollection.find()).thenReturn(findIterable); + when(findIterable.iterator()).thenReturn(cursor); + when(cursor.hasNext()).thenReturn(true, true, false); + when(cursor.next()).thenReturn(customerDoc1, customerDoc2); + List> customerList = mongoCustomerDAO.findAll(); + assertEquals(2, customerList.size()); + verify(customerCollection).find(); + } + + @Test + void givenValidId_whenFindById_thenReturnCustomer() { + FindIterable findIterable = mock(FindIterable.class); + ObjectId customerId = new ObjectId(); + String customerName = "Duc"; + Document customerDoc = new Document("_id", customerId).append("name", customerName); + when(customerCollection.find(Filters.eq("_id", customerId))).thenReturn(findIterable); + when(findIterable.first()).thenReturn(customerDoc); + + Optional> customer = mongoCustomerDAO.findById(customerId); + assertTrue(customer.isPresent()); + assertEquals(customerId, customer.get().getId()); + assertEquals(customerName, customer.get().getName()); + } + + @Test + void givenNotExistingId_whenFindById_thenReturnEmpty() { + FindIterable findIterable = mock(FindIterable.class); + ObjectId customerId = new ObjectId(); + when(customerCollection.find(Filters.eq("_id", customerId))).thenReturn(findIterable); + when(findIterable.first()).thenReturn(null); + Optional> customer = mongoCustomerDAO.findById(customerId); + assertTrue(customer.isEmpty()); + verify(customerCollection).find(Filters.eq("_id", customerId)); + } + + @Test + void whenDeleteSchema_thenDeleteCollection() { + mongoCustomerDAO.deleteSchema(); + verify(customerCollection).drop(); + } +} diff --git a/pom.xml b/pom.xml index a7fdcb7064d9..2816ef0ca636 100644 --- a/pom.xml +++ b/pom.xml @@ -107,6 +107,7 @@ converter curiously-recurring-template-pattern currying + dao-factory data-access-object data-bus data-locality From 4caa0bfdbcf7bcb851b66ed6101ac2a0d68d49ac Mon Sep 17 00:00:00 2001 From: Maziyar Gerami <122622721+maziyar-gerami@users.noreply.github.com> Date: Sun, 8 Feb 2026 22:55:16 +0330 Subject: [PATCH 027/108] docs: Persian translation: Abstract Factory (#3280) * Persian Translation: Add persian translation to abstract-document * Persian Translation: Add abstract-document.png to abstract-document folder * Persian Translation: Add codes to README.md of abstract-document * Persian Translation: some improvements in abstract-document * Persian Translation: Add refrence links in abstract-document * Persian Translation: add rtl tag in abstract-document * -added persian translation of factory pattern * -renamed file * -changed wikipedia definition * -fixed table problem * active-object : translate * active-object: improve when to use * active-object: improve when to use * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets (test) * active-object: improve bullets * active-object: Fix all bullets * -fixed problems in bullet alignments * Update README.md -fixed alignment in bullets * Update README.md -changed tags to English * -added persian translation of factory pattern * -renamed file * -changed wikipedia definition * -fixed table problem * -fixed problems in bullet alignments * Update README.md -fixed alignment in bullets * Update README.md -changed tags to English * abstract-factory: added persian translation * abstract-factory: fixed bullets problems * "Minor improvement Co-authored-by: keivanshir " --------- Co-authored-by: Seyyed Keivan Shirkoubian --- localization/fa/abstract-factory/README.md | 223 ++++++++++++++++++ .../etc/abstract-factory.urm.png | Bin 0 -> 82368 bytes 2 files changed, 223 insertions(+) create mode 100644 localization/fa/abstract-factory/README.md create mode 100644 localization/fa/abstract-factory/etc/abstract-factory.urm.png diff --git a/localization/fa/abstract-factory/README.md b/localization/fa/abstract-factory/README.md new file mode 100644 index 000000000000..85dce3437ba4 --- /dev/null +++ b/localization/fa/abstract-factory/README.md @@ -0,0 +1,223 @@ +--- +title: "الگوی طراحی Abstract Factory در جاوا: مهارت در ایجاد شیء با ظرافت" +shortTitle: Abstract Factory +description: "با مثال‌های دنیای واقعی، دیاگرام‌های کلاس و آموزش‌ها، الگوی Abstract Factory را در جاوا بیاموزید. منظور، کاربرد، مزایا و نمونه‌های واقعی آن را درک کنید و دانش طراحی الگوهایتان را افزایش دهید." +category: Creational +language: fa +tag: + - Abstraction + - Decoupling + - Gang of Four + - Instantiation + - Polymorphism +--- + +## همچنین به این عنوان شناخته می‌شود + +* کیت + +## هدف از الگوی طراحی Abstract Factory + +الگوی Abstract Factory در جاوا یک واسط برای ایجاد خانواده‌هایی از اشیای مرتبط یا وابسته فراهم می‌کند بدون آنکه کلاس‌های مشخص آن‌ها را تعیین کند، و این کار موجب افزایش مدولاریتی و انعطاف‌پذیری در طراحی نرم‌افزار می‌شود. + +## توضیح دقیق الگوی Abstract Factory با مثال‌های دنیای واقعی + +مثال دنیای واقعی + +> تصور کنید یک شرکت مبلمان وجود دارد که از الگوی Abstract Factory در جاوا برای تولید سبک‌های مختلف مبلمان استفاده می‌کند: مدرن، ویکتوریایی و روستایی. هر سبک شامل محصولاتی مانند صندلی‌ها، میزها و کاناپه‌ها است. برای اطمینان از یکنواختی در هر سبک، شرکت از یک الگوی Abstract Factory استفاده می‌کند. +> +> در این سناریو، Abstract Factory یک واسط برای ایجاد خانواده‌هایی از اشیای مبلمان مرتبط (صندلی‌ها، میزها، کاناپه‌ها) است. هر Factory مشخص (کارخانه‌ی مبلمان مدرن، کارخانه‌ی مبلمان ویکتوریایی، کارخانه‌ی مبلمان روستایی) این واسط را پیاده‌سازی می‌کند و مجموعه‌ای از محصولات مطابق با سبک خاص ایجاد می‌کند. به این ترتیب، مشتریان می‌توانند یک مجموعه کامل از مبلمان مدرن یا ویکتوریایی ایجاد کنند بدون اینکه نگران جزئیات ساخت آن‌ها باشند. این باعث حفظ یکنواختی سبک می‌شود و امکان تغییر آسان سبک مبلمان را فراهم می‌کند. + +به زبان ساده + +> کارخانه‌ای از کارخانه‌ها؛ یک Factory یا کارخانه که مجموعه‌ای از کارخانه‌های مرتبط یا وابسته را بدون مشخص کردن کلاس‌های concrete آن‌ها گروه‌بندی می‌کند. + +ویکی‌پدیا می‌گوید + +> الگوی Abstract Factory راهی برای کپسوله کردن مجموعه‌ای از کارخانه‌های منحصر به فرد با یک تم مشترک بدون تعیین کلاس‌های concrete آن‌ها فراهم می‌کند. + +دیاگرام کلاس + +![Abstract Factory class diagram](./etc/abstract-factory.urm.png "Abstract Factory class diagram") + +## مثال برنامه‌نویسی از Abstract Factory در جاوا + +برای ایجاد یک پادشاهی با استفاده از الگوی Abstract Factory در جاوا، ما به اشیایی با یک تم مشترک نیاز داریم. یک پادشاهی اِلف (Elf) به یک پادشاه اِلف، یک قلعه‌ی اِلف، و یک ارتش اِلف نیاز دارد، در حالی که یک پادشاهی اورک (Orc) به یک پادشاه اورک، یک قلعه‌ی اورک، و یک ارتش اورک نیاز دارد. بین اشیای موجود در پادشاهی وابستگی وجود دارد. + +ترجمه‌ی مثال پادشاهی بالا. ابتدا ما برخی واسط‌ها و پیاده‌سازی‌هایی برای اشیای موجود در پادشاهی داریم: + +```java +public interface Castle { + String getDescription(); +} + +public interface King { + String getDescription(); +} + +public interface Army { + String getDescription(); +} + +// Elven implementations -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the elven castle!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfKing implements King { + static final String DESCRIPTION = "This is the elven king!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the elven Army!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// Orcish implementations similarly -> ... +``` + +سپس واسط و پیاده‌سازی‌های کارخانه‌ی پادشاهی را داریم: + +```java +public interface KingdomFactory { + Castle createCastle(); + King createKing(); + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + + @Override + public Castle createCastle() { + return new ElfCastle(); + } + + @Override + public King createKing() { + return new ElfKing(); + } + + @Override + public Army createArmy() { + return new ElfArmy(); + } +} + +// Orcish implementations similarly -> ... +``` + +اکنون می‌توانیم یک کارخانه برای کارخانه‌های مختلف پادشاهی طراحی کنیم. در این مثال، ما `FactoryMaker` را ایجاد کردیم که مسئول برگرداندن یک نمونه از `ElfKingdomFactory` یا `OrcKingdomFactory` است. مشتری می تواند از `FactoryMaker` برای ایجاد کارخانه concrete مورد نظر استفاده کند که به نوبه خود اشیاء concrete مختلف (مشتق شده از ارتش، پادشاه، قلعه) را تولید می‌کند. در این مثال، ما همچنین از یک enum برای پارامتری کردن نوع کارخانه پادشاهی که مشتری درخواست خواهد کرد استفاده کردیم. + +```java +public static class FactoryMaker { + + public enum KingdomType { + ELF, ORC + } + + public static KingdomFactory makeFactory(KingdomType type) { + return switch (type) { + case ELF -> new ElfKingdomFactory(); + case ORC -> new OrcKingdomFactory(); + }; + } +} +``` + +نمونه‌ای از تابع اصلی برنامه: + +```java +LOGGER.info("elf kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); + +LOGGER.info("orc kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); +``` + +خروجی برنامه: + +``` +07:35:46.340 [main] INFO com.iluwatar.abstractfactory.App -- elf kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven king! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- orc kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc king! +``` + +## چه زمانی باید از الگوی Abstract Factory در جاوا استفاده کرد؟ + +* زمانی که سیستم باید مستقل از نحوه‌ی ایجاد، ترکیب و نمایش محصولاتش باشد. +* زمانی که نیاز به پیکربندی سیستم با یکی از چند خانواده محصول دارید. +* زمانی که باید خانواده‌ای از اشیای مرتبط با هم استفاده شوند، برای اطمینان از یکنواختی. +* زمانی که می‌خواهید کتابخانه‌ای از محصولات را فراهم کنید و فقط واسط‌های آن‌ها را نمایان کنید، نه پیاده‌سازی‌ها را. +* زمانی که طول عمر وابستگی‌ها کوتاه‌تر از مصرف‌کننده باشد. +* زمانی که نیاز به ساخت وابستگی‌ها با مقادیر یا پارامترهای زمان اجرا باشد. +* زمانی که باید در زمان اجرا انتخاب کنید که کدام خانواده از محصول را استفاده کنید. +* زمانی که افزودن محصولات یا خانواده های جدید نباید نیاز به تغییر در کد موجود داشته باشد. + +## آموزش‌های الگوی Abstract Factory در جاوا + +* [Abstract Factory Design Pattern in Java (DigitalOcean)](https://www.digitalocean.com/community/tutorials/abstract-factory-design-pattern-in-java) +* [Abstract Factory (Refactoring Guru)](https://refactoring.guru/design-patterns/abstract-factory) + +## مزایا و معایب الگوی Abstract Factory + +مزایا: + +> * انعطاف‌پذیری: به راحتی می‌توان خانواده‌های محصول را تعویض کرد بدون تغییر کد. + +> * جداسازی (Decoupling): کد مشتری فقط با واسط‌های انتزاعی کار می‌کند که باعث قابلیت حمل و نگهداری می‌شود. + +> * قابلیت استفاده مجدد: کارخانه‌های انتزاعی و محصولات امکان استفاده مجدد از مؤلفه‌ها را فراهم می‌کنند. + +> * قابلیت نگهداری: تغییرات در خانواده‌های محصول محلی شده و به‌روزرسانی را ساده‌تر می‌کند. + +معایب: + +> * پیچیدگی: تعریف واسط‌های انتزاعی و کارخانه‌های مشخص سربار اولیه ایجاد می‌کند. + +> * غیرمستقیم بودن: کد مشتری از طریق کارخانه‌ها با محصولات کار می‌کند که ممکن است شفافیت را کاهش دهد. + +## نمونه‌های واقعی استفاده از الگوی Abstract Factory در جاوا + +* کلاس‌های `LookAndFeel` در Java Swing برای ارائه گزینه های مختلف look-and-feel +* پیاده‌سازی‌های مختلف در Java AWT برای ایجاد اجزای مختلف GUI +* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) + +## الگوهای طراحی مرتبط با جاوا + +* الگوی [Factory Method](https://java-design-patterns.com/patterns/factory-method/): الگوی کارخانه‌ی انتزاعی از روش‌های کارخانه‌ای برای ایجاد محصولات استفاده می‌کند. +* الگوی [Singleton](https://java-design-patterns.com/patterns/singleton/): کلاس‌های کارخانه‌ی انتزاعی اغلب به صورت Singleton پیاده‌سازی می‌شوند. +* الگوی [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): مشابه کارخانه‌ی انتزاعی اما بر پیکربندی و مدیریت مجموعه‌ای از اشیای مرتبط تمرکز دارد. + +## منابع و ارجاعات + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Design Patterns in Java](https://amzn.to/3Syw0vC) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3HWNf4U) diff --git a/localization/fa/abstract-factory/etc/abstract-factory.urm.png b/localization/fa/abstract-factory/etc/abstract-factory.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..836858a2c652f55723cff879d1058248e1d2799c GIT binary patch literal 82368 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 MUHx3vIVCg!0PQSJ00000 literal 0 HcmV?d00001 From 7c12643b2772a4b96f58db2c88f00d5efa92ea1e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:27:30 +0200 Subject: [PATCH 028/108] docs: add naman-sriv as a contributor for code (#3428) * 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 90ce80d3a163..c0b72d0364f8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3539,6 +3539,15 @@ "contributions": [ "doc" ] + }, + { + "login": "naman-sriv", + "name": "Naman Srivastava", + "avatar_url": "https://avatars.githubusercontent.com/u/82610773?v=4", + "profile": "https://github.com/naman-sriv", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index bfcdd0f63dbf..8a69a33f879d 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-388-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-389-orange.svg?style=flat-square)](#contributors-)
@@ -577,6 +577,7 @@ This project is licensed under the terms of the MIT license.
Maziyar Gerami
Maziyar Gerami

🌍 yoobin_mion
yoobin_mion

💻 Soumik Sarker
Soumik Sarker

📖 + Naman Srivastava
Naman Srivastava

💻 From dc3425dd0e4643658c876304430fe0173e4144e2 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:28:19 +0200 Subject: [PATCH 029/108] docs: add letdtcode as a contributor for code (#3429) * 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 c0b72d0364f8..59c7a7b92a6b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3548,6 +3548,15 @@ "contributions": [ "code" ] + }, + { + "login": "letdtcode", + "name": "Thanh Nguyen Duc", + "avatar_url": "https://avatars.githubusercontent.com/u/92111552?v=4", + "profile": "https://github.com/letdtcode", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 8a69a33f879d..1aeab8760ae0 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-389-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-390-orange.svg?style=flat-square)](#contributors-)
@@ -578,6 +578,7 @@ This project is licensed under the terms of the MIT license. yoobin_mion
yoobin_mion

💻 Soumik Sarker
Soumik Sarker

📖 Naman Srivastava
Naman Srivastava

💻 + Thanh Nguyen Duc
Thanh Nguyen Duc

💻 From a3fcc631672a3e418523af0c61c403caf5c137bf Mon Sep 17 00:00:00 2001 From: e5LA <208197507+e5LA@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:44:17 +0100 Subject: [PATCH 030/108] feat: Implement View Helper pattern (#3278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #1263 - creating new module for view-helper * #1263 - creating Product and ProductViewModel * #1263 - creating interfaces for View and ViewHelper * #1263 - creating ProductViewHelper and its test * #1263 - creating Console View for Product * #1263 - creating ProductController * #1263 - creating main App and its test * #1263 - adding license header * #1263 - keeping module in alphabetical order * #1263 - creating README and diagrams * #1263 apply spotless --------- Co-authored-by: Ilkka Seppälä --- pom.xml | 3 +- view-helper/README.md | 98 ++++++++++++++++++ .../etc/view-helper-sequence-diagram.png | Bin 0 -> 27969 bytes .../etc/view-helper-sequence-diagram.puml | 15 +++ view-helper/etc/view-helper.png | Bin 0 -> 56099 bytes view-helper/etc/view-helper.puml | 45 ++++++++ view-helper/pom.xml | 70 +++++++++++++ .../java/com/iluwatar/viewhelper/App.java | 52 ++++++++++ .../viewhelper/ConsoleProductView.java | 36 +++++++ .../java/com/iluwatar/viewhelper/Product.java | 31 ++++++ .../viewhelper/ProductController.java | 49 +++++++++ .../viewhelper/ProductViewHelper.java | 45 ++++++++ .../iluwatar/viewhelper/ProductViewModel.java | 28 +++++ .../java/com/iluwatar/viewhelper/View.java | 30 ++++++ .../com/iluwatar/viewhelper/ViewHelper.java | 29 ++++++ .../java/com/iluwatar/viewhelper/AppTest.java | 39 +++++++ .../viewhelper/ProductViewHelperTest.java | 60 +++++++++++ 17 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 view-helper/README.md create mode 100644 view-helper/etc/view-helper-sequence-diagram.png create mode 100644 view-helper/etc/view-helper-sequence-diagram.puml create mode 100644 view-helper/etc/view-helper.png create mode 100644 view-helper/etc/view-helper.puml create mode 100644 view-helper/pom.xml create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/App.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/Product.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/View.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java create mode 100644 view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java create mode 100644 view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java diff --git a/pom.xml b/pom.xml index 2816ef0ca636..5926820b7fb4 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,6 @@ Java Design Patterns - abstract-document abstract-factory active-object @@ -244,11 +243,11 @@ update-method value-object version-number + view-helper virtual-proxy visitor backpressure actor-model - diff --git a/view-helper/README.md b/view-helper/README.md new file mode 100644 index 000000000000..fbc93acba6fd --- /dev/null +++ b/view-helper/README.md @@ -0,0 +1,98 @@ +--- +title: "View Helper Pattern in Java: Simplifying Presentation Logic in MVC Applications" +shortTitle: View Helper +description: "Discover the View Helper Design Pattern in Java, a powerful technique for separating view-related logic from business logic in MVC-based web applications. This pattern enhances maintainability, reusability, and testability by delegating complex UI operations to reusable helper components. Ideal for developers aiming to keep views clean and focused on presentation." +category: Architectural +language: en +tag: + - Architecture + - Presentation + - Decoupling + - Code reuse +--- + +## Intent of View Helper Design Pattern +The View Helper Design Pattern separates presentation logic from the view by delegating complex UI tasks — like formatting or conditional display — to reusable helper components. This keeps views clean, promotes reuse, and aligns with the MVC principle of separating concerns between the view and the business logic. + +## Detailed Explanation with Real‑World Analogy +Real‑world example +> Imagine you're putting together a slideshow for a business presentation. You focus on arranging the slides, choosing the layout, and telling the story. But for tasks like resizing images, formatting charts, or converting data into visual form, you use tools or templates that automate those parts. +> +> In this analogy, you are the view, and the tools/templates are the helpers. They handle the heavy lifting behind the scenes so you can concentrate on the presentation. Similarly, in the View Helper pattern, the view delegates logic-heavy tasks—such as formatting or conditionally displaying data—to helper classes, keeping the view layer clean and presentation-focused. + +### In plain words +> The View Helper pattern is about keeping your UI code clean by moving any logic—like formatting, calculations, or decision-making—into separate helper classes. Instead of stuffing all the logic into the HTML or template files, you delegate it to helpers, so the view just focuses on showing the final result. + +### Sequence diagram +![Sequence diagram for View Helper](etc/view-helper-sequence-diagram.png) + +## Programmatic Example of View Helper Pattern in Java +Raw domain object +```java +public record Product(String name, BigDecimal price, LocalDate releaseDate, boolean discounted) {} +``` + +View model object for display +```java +public record ProductViewModel(String name, String price, String releasedDate) {} +``` + +View Helper formats data for display +```java +class ProductViewHelper implements ViewHelper { + + private static final String DISCOUNT_TAG = " (ON SALE)"; + + public ProductViewModel prepare(Product product) { + var displayName = product.name() + (product.discounted() ? DISCOUNT_TAG : ""); + var priceWithCurrency = NumberFormat.getCurrencyInstance(US).format(product.price()); + var formattedDate = product.releaseDate().format(ISO_DATE); + + return new ProductViewModel(displayName, priceWithCurrency, formattedDate); + } +} +``` + +View renders the formatted data +```java +public class ConsoleProductView implements View { + + @Override + public void render(ProductViewModel productViewModel) { + LOGGER.info(productViewModel.toString()); + } +} +``` +The `App.java` class simulates how the View Helper pattern works in a real application. It starts with a raw `Product` object containing unformatted data. +Then it: +1. Initializes a helper (`ProductViewHelper`) to format the product data for display. +1. Creates a view (`ConsoleProductView`) to render the formatted data. +1. Uses a controller (`ProductController`) to coordinate the flow between raw data, helper logic, and view rendering. + +Finally, it simulates a user request by passing the product to the controller, which prepares the view model using the helper and displays it using the view. This demonstrates a clean separation between data, presentation logic, and rendering. + +## When to Use the View Helper Pattern in Java +Use the View Helper pattern when your view layer starts containing logic such as formatting data, applying conditional styles, or transforming domain objects for display. It's especially useful in MVC architectures where you want to keep views clean and focused on rendering, while delegating non-trivial presentation logic to reusable helper classes. This pattern helps improve maintainability, testability, and separation of concerns in your application's UI layer. + +## Real‑World Uses of View Helper Pattern in Java +The View Helper pattern is widely used in web frameworks that follow the MVC architecture. In Java-based web applications (e.g., JSP, Spring MVC), it's common to use helper classes or utility methods to format dates, currencies, or apply conditional logic before rendering views. Technologies like Thymeleaf or JSF often rely on custom tags or expression helpers to achieve the same effect. + +## Benefits and Trade‑offs +Benefits: +* Separation of concerns: Keeps view templates clean by moving logic into dedicated helpers. +* Reusability: Common formatting and display logic can be reused across multiple views. +* Improved maintainability: Easier to update presentation logic without touching the view. +* Testability: Helpers can be unit tested independently from the UI layer. + +Trade‑offs: +* Added complexity: Introduces extra classes, which may feel unnecessary for very simple views. +* Overuse risk: Excessive use of helpers can spread logic thinly across many files, making it harder to trace behavior. +* Tight coupling risk: If not designed carefully, helpers can become tightly coupled to specific views or data formats. + +## Related Java Design Patterns +* [Model-View-Controller (MVC)](https://java-design-patterns.com/patterns/model-view-controller/): View Helper supports the View layer in MVC by offloading logic from the view to helper classes. +* [Template Method](https://java-design-patterns.com/patterns/template-method/): Can structure the steps of rendering or data transformation, with helpers handling specific formatting tasks. +* [Data Transfer Object (DTO)](https://java-design-patterns.com/patterns/data-transfer-object/): Often used alongside View Helper when transferring raw data that needs formatting before being displayed. + +## References & Credits +* [Core J2EE Patterns: View Helper.](https://www.oracle.com/java/technologies/viewhelper.html) diff --git a/view-helper/etc/view-helper-sequence-diagram.png b/view-helper/etc/view-helper-sequence-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..22e53c6b8afe625ae8604ca8f37659e69e6ef8e2 GIT binary patch literal 27969 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 literal 0 HcmV?d00001 diff --git a/view-helper/etc/view-helper-sequence-diagram.puml b/view-helper/etc/view-helper-sequence-diagram.puml new file mode 100644 index 000000000000..d5be27e51510 --- /dev/null +++ b/view-helper/etc/view-helper-sequence-diagram.puml @@ -0,0 +1,15 @@ +@startuml +actor Client +participant Controller +participant ViewHelper +participant View +participant Product +participant ProductViewModel + +Client -> Controller : handle(product) +Controller -> ViewHelper : prepare(product) +ViewHelper -> Product : access data +ViewHelper -> ProductViewModel : return formatted view model +Controller -> View : render(viewModel) +View -> Console : display output +@enduml \ No newline at end of file diff --git a/view-helper/etc/view-helper.png b/view-helper/etc/view-helper.png new file mode 100644 index 0000000000000000000000000000000000000000..9550b80d7acb2496f8ededf8ad9a85237203b28b GIT binary patch literal 56099 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 { + +render(T model) + } + + interface ViewHelper { + +prepare(S source): T + } + + class Product { + -name: String + -price: BigDecimal + -releaseDate: LocalDate + -discounted: boolean + } + + class ProductViewModel { + -name: String + -price: String + -releasedDate: String + } + + class ProductViewHelper { + +prepare(Product): ProductViewModel + } + + class ConsoleProductView { + +render(ProductViewModel) + } + + class ProductController { + -helper: ViewHelper + -view: View + +handle(Product) + } +} +Product --> ProductViewHelper +ProductViewHelper ..|> ViewHelper +ConsoleProductView ..|> View +ProductViewHelper --> ProductViewModel +ProductController --> ProductViewHelper +ProductController --> ConsoleProductView + +@enduml \ No newline at end of file diff --git a/view-helper/pom.xml b/view-helper/pom.xml new file mode 100644 index 000000000000..e2f3afca3a08 --- /dev/null +++ b/view-helper/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + view-helper + + + 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.value.object.App + + + + + + + + + diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/App.java b/view-helper/src/main/java/com/iluwatar/viewhelper/App.java new file mode 100644 index 000000000000..e427bc8f5e9b --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/App.java @@ -0,0 +1,52 @@ +/* + * 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.viewhelper; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** The main application class that sets up and runs the View Helper pattern demo. */ +public class App { + /** + * The entry point of the application. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + // Raw Product data (no formatting, no UI tags) + var product = + new Product( + "Design patterns book", new BigDecimal("18.90"), LocalDate.of(2025, 4, 19), true); + + // Create view, viewHelper and viewHelper + var helper = new ProductViewHelper(); + var view = new ConsoleProductView(); + var controller = new ProductController(helper, view); + + // Handle “request” + controller.handle(product); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java new file mode 100644 index 000000000000..7f215a7514f6 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.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.viewhelper; + +import lombok.extern.slf4j.Slf4j; + +/** Renders {@link ProductViewModel} to the console. */ +@Slf4j +public class ConsoleProductView implements View { + @Override + public void render(ProductViewModel productViewModel) { + LOGGER.info(productViewModel.toString()); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java b/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java new file mode 100644 index 000000000000..a0a75cf24188 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java @@ -0,0 +1,31 @@ +/* + * 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.viewhelper; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** Definition of product. */ +public record Product(String name, BigDecimal price, LocalDate releaseDate, boolean discounted) {} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java new file mode 100644 index 000000000000..836f34a33167 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java @@ -0,0 +1,49 @@ +/* + * 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.viewhelper; + +/** + * Controller delegates a {@link Product} to {@link ProductViewHelper} and then to {@link + * ConsoleProductView}. + */ +public class ProductController { + + private final ViewHelper viewHelper; + private final View view; + + public ProductController( + ViewHelper viewHelper, View view) { + this.viewHelper = viewHelper; + this.view = view; + } + + /** + * Passes the product to the helper for formatting and then forwards formatted product to the + * view. + */ + public void handle(Product product) { + view.render(viewHelper.prepare(product)); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java new file mode 100644 index 000000000000..4c739e9f14a8 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.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.viewhelper; + +import static java.time.format.DateTimeFormatter.ISO_DATE; +import static java.util.Locale.US; + +import java.text.NumberFormat; + +/** Formats a {@link Product} into a {@link ProductViewModel}. */ +public class ProductViewHelper implements ViewHelper { + + private static final String DISCOUNT_TAG = " ON SALE"; + + @Override + public ProductViewModel prepare(Product product) { + var displayName = product.name() + (product.discounted() ? DISCOUNT_TAG : ""); + var priceWithCurrency = NumberFormat.getCurrencyInstance(US).format(product.price()); + var formattedDate = product.releaseDate().format(ISO_DATE); + + return new ProductViewModel(displayName, priceWithCurrency, formattedDate); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java new file mode 100644 index 000000000000..b133fc071da1 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.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. + */ +package com.iluwatar.viewhelper; + +/** Class defining formatted display data of a {@link Product}. */ +public record ProductViewModel(String name, String price, String releasedDate) {} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/View.java b/view-helper/src/main/java/com/iluwatar/viewhelper/View.java new file mode 100644 index 000000000000..7bc822166885 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/View.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. + */ +package com.iluwatar.viewhelper; + +public interface View { + + void render(V data); +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java new file mode 100644 index 000000000000..68756f46585d --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.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. + */ +package com.iluwatar.viewhelper; + +public interface ViewHelper { + V prepare(M source); +} diff --git a/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java b/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java new file mode 100644 index 000000000000..bc4a31cc43a8 --- /dev/null +++ b/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.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.viewhelper; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** Application test */ +class AppTest { + + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java b/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java new file mode 100644 index 000000000000..49cc48556f47 --- /dev/null +++ b/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.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, 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.viewhelper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.time.LocalDate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ProductViewHelperTest { + + private ProductViewHelper helper; + + @BeforeEach + void setUp() { + helper = new ProductViewHelper(); + } + + @Test + void shouldFormatProductWithoutDiscount() { + var product = new Product("X", new BigDecimal("10.00"), LocalDate.of(2025, 1, 1), false); + ProductViewModel viewModel = helper.prepare(product); + + assertEquals("X", viewModel.name()); + assertEquals("$10.00", viewModel.price()); + assertEquals("2025-01-01", viewModel.releasedDate()); + } + + @Test + void shouldFormatProductWithDiscount() { + var product = new Product("X", new BigDecimal("10.00"), LocalDate.of(2025, 1, 1), true); + ProductViewModel viewModel = helper.prepare(product); + + assertEquals("X ON SALE", viewModel.name()); // locale follows JVM default + } +} From 265e3d0bda52c5039503ca57b3a1c025891ddc54 Mon Sep 17 00:00:00 2001 From: Soham Kamble <121136639+skamble2@users.noreply.github.com> Date: Sun, 22 Feb 2026 23:45:11 +0530 Subject: [PATCH 031/108] feat: Rate Limiting Pattern #2973 (#3291) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * need to fix one test case shouldGraduallyIncreaseLimitWhenHealthy failing for AdaptiveRateLimiter.java * Added Class Diagram and Flow Diagrams for Adaptive, Fixed Window and Token Bucket Rate Limiter * Updated README.md. All test case passed. Updated with Google Java Guidelines * Updated parent pom #2973 * Updated parent pom #2973 * fixed shouldResetCounterAfterWindow() test #2973 * formatting fixed #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * added test coverage for app.java and fixed random to be thread safe #2973 * fixed random to be thread safe #2973 * fixed random to be thread safe #2973 * fixed random to be thread safe #2973 * fixed spacing in pom.xml #2973 --------- Co-authored-by: Ilkka Seppälä --- pom.xml | 1 + rate-limiting-pattern/README.md | 328 ++++++++++++++++++ .../etc/AdaptiveRateLimiter.png | Bin 0 -> 117129 bytes .../etc/FixedWindowRateLimiter.png | Bin 0 -> 105244 bytes .../etc/TokenBucketRateLimiter.png | Bin 0 -> 122458 bytes rate-limiting-pattern/etc/UMLClassDiagram.png | Bin 0 -> 122880 bytes rate-limiting-pattern/pom.xml | 89 +++++ .../limiting/pattern/AdaptiveRateLimiter.java | 50 +++ .../iluwatar/rate/limiting/pattern/App.java | 178 ++++++++++ .../limiting/pattern/FindCustomerRequest.java | 40 +++ .../pattern/FixedWindowRateLimiter.java | 53 +++ .../limiting/pattern/RateLimitException.java | 15 + .../limiting/pattern/RateLimitOperation.java | 10 + .../rate/limiting/pattern/RateLimiter.java | 13 + .../pattern/ServiceUnavailableException.java | 15 + .../limiting/pattern/ThrottlingException.java | 21 ++ .../pattern/TokenBucketRateLimiter.java | 64 ++++ .../pattern/AdaptiveRateLimiterTest.java | 56 +++ .../rate/limiting/pattern/AppTest.java | 59 ++++ .../rate/limiting/pattern/AppTestUtils.java | 27 ++ .../limiting/pattern/ConcurrencyTests.java | 69 ++++ .../rate/limiting/pattern/ExceptionTests.java | 28 ++ .../pattern/FindCustomerRequestTest.java | 62 ++++ .../pattern/FixedWindowRateLimiterTest.java | 40 +++ .../pattern/RateLimitOperationTest.java | 22 ++ .../limiting/pattern/RateLimiterTest.java | 25 ++ .../pattern/TokenBucketRateLimiterTest.java | 39 +++ 27 files changed, 1304 insertions(+) create mode 100644 rate-limiting-pattern/README.md create mode 100644 rate-limiting-pattern/etc/AdaptiveRateLimiter.png create mode 100644 rate-limiting-pattern/etc/FixedWindowRateLimiter.png create mode 100644 rate-limiting-pattern/etc/TokenBucketRateLimiter.png create mode 100644 rate-limiting-pattern/etc/UMLClassDiagram.png create mode 100644 rate-limiting-pattern/pom.xml create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/App.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequest.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiter.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitException.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitOperation.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimiter.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ServiceUnavailableException.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ThrottlingException.java create mode 100644 rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTestUtils.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ExceptionTests.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequestTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiterTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimitOperationTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimiterTest.java create mode 100644 rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiterTest.java diff --git a/pom.xml b/pom.xml index 5926820b7fb4..82d15bdf1d74 100644 --- a/pom.xml +++ b/pom.xml @@ -248,6 +248,7 @@ visitor backpressure actor-model + rate-limiting-pattern diff --git a/rate-limiting-pattern/README.md b/rate-limiting-pattern/README.md new file mode 100644 index 000000000000..de7742a5d13f --- /dev/null +++ b/rate-limiting-pattern/README.md @@ -0,0 +1,328 @@ +--- +title: "Rate Limiting Pattern in Java: Controlling System Overload Gracefully" +shortTitle: Rate Limiting +description: "Explore multiple rate limiting strategies in Java—Token Bucket, Fixed Window, and Adaptive Limiting. Learn with diagrams, programmatic examples, and real-world simulation." +category: Behavioral +language: en +tag: + - Resilience + - System Overload Protection + - API Throttling + - Concurrency + - Cloud Patterns +--- + +## Also known as + +- Throttling +- Request Limiting +- API Rate Limiting + +--- + +## Intent of Rate Limiting Design Pattern + +To regulate the number of requests sent to a service in a specific time window, avoiding resource exhaustion and ensuring system stability. This is especially useful in distributed and cloud-native architectures. + +--- + +## Detailed Explanation of Rate Limiting with Real-World Examples + +### Real-world example + +Imagine you're entering a concert hall that only allows 50 people per minute. If too many fans arrive at once, the gate staff slows down entry, allowing only a few at a time. This prevents overcrowding and ensures safety. Similarly, the rate limiter controls how many requests are processed to avoid overloading a server. + +### In plain words + +Regulate the number of requests a system handles within a time frame to protect availability and performance. + + +### AWS says + +> "API Gateway limits the steady-state rate and burst rate of requests that it allows for each method in your REST APIs. When request rates exceed these limits, API Gateway begins to throttle requests." + +— [API Gateway quotas and important notes - AWS Documentation](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html) + +--- + +## Architecture Diagram + +![UML Class Diagram](etc/UMLClassDiagram.png) + +This UML shows the key components: +- `RateLimiter` interface +- `TokenBucketRateLimiter`, `FixedWindowRateLimiter`, `AdaptiveRateLimiter` +- Supporting exception classes +- `FindCustomerRequest` as a rate-limited operation + +--- + +## Flowcharts + +### 1. Token Bucket Strategy + +![Token Bucket Rate Limiter](etc/TokenBucketRateLimiter.png) + +### 2. Fixed Window Strategy + +![Fixed Window Rate Limiter](etc/FixedWindowRateLimiter.png) + +### 3. Adaptive Rate Limiting Strategy + +![Adaptive Rate Limiter](etc/AdaptiveRateLimiter.png) + +--- + +### Programmatic Example of Rate Limiter Pattern in Java + +The **Rate Limiter** design pattern helps protect systems from overload by restricting the number of operations that can be performed in a given time window. It is especially useful when accessing shared resources, APIs, or services that are sensitive to spikes in traffic. + +This implementation demonstrates three strategies for rate limiting: + +- **Token Bucket Rate Limiter** +- **Fixed Window Rate Limiter** +- **Adaptive Rate Limiter** + +Let’s walk through the key components. + +--- + +#### 1. Token Bucket Rate Limiter + +The token bucket allows short bursts followed by a steady rate. Tokens are added periodically and requests are only allowed if a token is available. + +```java +public class TokenBucketRateLimiter implements RateLimiter { + private final int capacity; + private final int refillRate; + private final ConcurrentHashMap buckets = new ConcurrentHashMap<>(); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + public TokenBucketRateLimiter(int capacity, int refillRate) { + this.capacity = capacity; + this.refillRate = refillRate; + scheduler.scheduleAtFixedRate(this::refillBuckets, 1, 1, TimeUnit.SECONDS); + } + + @Override + public void check(String serviceName, String operationName) throws RateLimitException { + String key = serviceName + ":" + operationName; + TokenBucket bucket = buckets.computeIfAbsent(key, k -> new TokenBucket(capacity)); + if (!bucket.tryConsume()) { + throw new ThrottlingException(serviceName, operationName, 1000); + } + } + + private void refillBuckets() { + buckets.forEach((k, b) -> b.refill(refillRate)); + } + + private static class TokenBucket { + private final int capacity; + private final AtomicInteger tokens; + + TokenBucket(int capacity) { + this.capacity = capacity; + this.tokens = new AtomicInteger(capacity); + } + + boolean tryConsume() { + while (true) { + int current = tokens.get(); + if (current <= 0) return false; + if (tokens.compareAndSet(current, current - 1)) return true; + } + } + + void refill(int amount) { + tokens.getAndUpdate(current -> Math.min(current + amount, capacity)); + } + } +} +``` + +--- + +#### 2. Fixed Window Rate Limiter + +This strategy uses a simple counter within a fixed time window. + +```java +public class FixedWindowRateLimiter implements RateLimiter { + private final int limit; + private final long windowMillis; + private final ConcurrentHashMap counters = new ConcurrentHashMap<>(); + + public FixedWindowRateLimiter(int limit, long windowSeconds) { + this.limit = limit; + this.windowMillis = TimeUnit.SECONDS.toMillis(windowSeconds); + } + + @Override + public synchronized void check(String serviceName, String operationName) throws RateLimitException { + String key = serviceName + ":" + operationName; + WindowCounter counter = counters.computeIfAbsent(key, k -> new WindowCounter()); + + if (!counter.tryIncrement()) { + throw new RateLimitException("Rate limit exceeded for " + key, windowMillis); + } + } + + private class WindowCounter { + private AtomicInteger count = new AtomicInteger(0); + private volatile long windowStart = System.currentTimeMillis(); + + synchronized boolean tryIncrement() { + long now = System.currentTimeMillis(); + if (now - windowStart > windowMillis) { + count.set(0); + windowStart = now; + } + return count.incrementAndGet() <= limit; + } + } +} +``` + +--- + +#### 3. Adaptive Rate Limiter + +This version adjusts the rate based on system health, reducing the rate when throttling occurs and recovering periodically. + +```java +public class AdaptiveRateLimiter implements RateLimiter { + private final int initialLimit; + private final int maxLimit; + private final AtomicInteger currentLimit; + private final ConcurrentHashMap limiters = new ConcurrentHashMap<>(); + private final ScheduledExecutorService healthChecker = Executors.newScheduledThreadPool(1); + + public AdaptiveRateLimiter(int initialLimit, int maxLimit) { + this.initialLimit = initialLimit; + this.maxLimit = maxLimit; + this.currentLimit = new AtomicInteger(initialLimit); + healthChecker.scheduleAtFixedRate(this::adjustLimits, 10, 10, TimeUnit.SECONDS); + } + + @Override + public void check(String serviceName, String operationName) throws RateLimitException { + String key = serviceName + ":" + operationName; + int current = currentLimit.get(); + RateLimiter limiter = limiters.computeIfAbsent(key, k -> new TokenBucketRateLimiter(current, current)); + + try { + limiter.check(serviceName, operationName); + } catch (RateLimitException e) { + currentLimit.updateAndGet(curr -> Math.max(initialLimit, curr / 2)); + throw e; + } + } + + private void adjustLimits() { + currentLimit.updateAndGet(curr -> Math.min(maxLimit, curr + (initialLimit / 2))); + } +} +``` + +--- + +#### 4. Simulated Demo Using All Limiters + +```java +public final class App { + public static void main(String[] args) { + TokenBucketRateLimiter tb = new TokenBucketRateLimiter(2, 1); + FixedWindowRateLimiter fw = new FixedWindowRateLimiter(3, 1); + AdaptiveRateLimiter ar = new AdaptiveRateLimiter(2, 6); + + ExecutorService executor = Executors.newFixedThreadPool(3); + for (int i = 1; i <= 3; i++) { + executor.submit(createClientTask(i, tb, fw, ar)); + } + } + + private static Runnable createClientTask(int clientId, RateLimiter tb, RateLimiter fw, RateLimiter ar) { + return () -> { + String[] services = {"s3", "dynamodb", "lambda"}; + String[] operations = {"GetObject", "PutObject", "Query", "Scan", "PutItem", "Invoke", "ListFunctions"}; + Random random = new Random(); + + while (true) { + String service = services[random.nextInt(services.length)]; + String operation = operations[random.nextInt(operations.length)]; + try { + switch (service) { + case "s3" -> tb.check(service, operation); + case "dynamodb" -> fw.check(service, operation); + case "lambda" -> ar.check(service, operation); + } + System.out.printf("Client %d: %s.%s - ALLOWED%n", clientId, service, operation); + } catch (RateLimitException e) { + System.out.printf("Client %d: %s.%s - THROTTLED%n", clientId, service, operation); + } + + try { + Thread.sleep(30 + random.nextInt(50)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }; + } +} +``` + +--- + +This example highlights how the Rate Limiter pattern supports various throttling techniques and how they respond under simulated traffic pressure, making it invaluable for building scalable, resilient systems. + +## When to Use Rate Limiting + +- APIs receiving unpredictable traffic +- Shared cloud resources (e.g., DB, compute) +- Services requiring fair client usage +- Preventing DoS or abuse + +--- + +## Real-World Applications + +- **AWS API Gateway** +- **Google Cloud Functions** +- **Netflix Zuul API Gateway** +- **Stripe API Throttling** + +--- + +## Benefits and Trade-offs + +### Benefits + +- Protects backend from overload +- Fair distribution of resources +- Better user experience under load + +### Trade-offs + +- May delay valid requests +- Requires tuning of limits +- Could create bottlenecks if misused + +--- + +## Related Java Design Patterns + +- [Circuit Breaker](https://java-design-patterns.com/patterns/circuit-breaker/) +- [Retry](https://java-design-patterns.com/patterns/retry/) +- [Throttling Queue](https://java-design-patterns.com/patterns/throttling/) + +--- + +## References and Credits + +- [Microsoft Cloud Design Patterns](https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling) +- [AWS API Gateway Throttling](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html) +- *Designing Data-Intensive Applications* by Martin Kleppmann +- [Resilience4j](https://resilience4j.readme.io/) +- Java Design Patterns Project: [java-design-patterns](https://github.com/iluwatar/java-design-patterns) diff --git a/rate-limiting-pattern/etc/AdaptiveRateLimiter.png b/rate-limiting-pattern/etc/AdaptiveRateLimiter.png new file mode 100644 index 0000000000000000000000000000000000000000..2d849ee8d05757acbbf37b980d7579fe6872364e GIT binary patch literal 117129 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 MV*ZcppDx_|FJq0YMgRZ+ literal 0 HcmV?d00001 diff --git a/rate-limiting-pattern/etc/TokenBucketRateLimiter.png b/rate-limiting-pattern/etc/TokenBucketRateLimiter.png new file mode 100644 index 0000000000000000000000000000000000000000..d41701781e27091e6b2f0913581e18e6c115e850 GIT binary patch literal 122458 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 bb~5nvfBl^=p4KhkYurKmuk!wR;-~)&VwMQW literal 0 HcmV?d00001 diff --git a/rate-limiting-pattern/etc/UMLClassDiagram.png b/rate-limiting-pattern/etc/UMLClassDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..9292880244e086e87fe98ff0ac34deb436206ada GIT binary patch literal 122880 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

Mha{WV8AR1NRGN+NYShMVSfBf~ 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 + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + rate-limiter + + + 22 + 22 + UTF-8 + 5.11.1 + 1.11.1 + + + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + org.mockito + mockito-core + 5.12.0 + test + + + + org.slf4j + slf4j-api + 2.0.9 + + + + ch.qos.logback + logback-classic + 1.4.11 + + + + org.assertj + assertj-core + 3.24.2 + test + + + + + + + com.diffplug.spotless + spotless-maven-plugin + 2.44.2 + + + + check + apply + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + false + + + + + diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java new file mode 100644 index 000000000000..1b18a8c941b9 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java @@ -0,0 +1,50 @@ +package com.iluwatar.rate.limiting.pattern; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** Adaptive rate limiter that adjusts limits based on system health. */ +public class AdaptiveRateLimiter implements RateLimiter { + private final int initialLimit; + private final int maxLimit; + private final AtomicInteger currentLimit; + private final ConcurrentHashMap limiters = new ConcurrentHashMap<>(); + private final ScheduledExecutorService healthChecker = Executors.newScheduledThreadPool(1); + + public AdaptiveRateLimiter(int initialLimit, int maxLimit) { + this.initialLimit = initialLimit; + this.maxLimit = maxLimit; + this.currentLimit = new AtomicInteger(initialLimit); + // Periodically increase limit to recover if system appears healthy + healthChecker.scheduleAtFixedRate(this::adjustLimits, 10, 10, TimeUnit.SECONDS); + } + + @Override + public void check(String serviceName, String operationName) throws RateLimitException { + String key = serviceName + ":" + operationName; + int current = currentLimit.get(); + + // Reuse or create TokenBucket for this key using currentLimit + RateLimiter limiter = + limiters.computeIfAbsent(key, k -> new TokenBucketRateLimiter(current, current)); + + try { + limiter.check(serviceName, operationName); + System.out.printf( + "[Adaptive] Allowed %s.%s - CurrentLimit: %d%n", serviceName, operationName, current); + } catch (RateLimitException e) { + // On throttling, reduce system limit to reduce load + currentLimit.updateAndGet(curr -> Math.max(initialLimit, curr / 2)); + System.out.printf( + "[Adaptive] Throttled %s.%s - Decreasing limit to %d%n", + serviceName, operationName, currentLimit.get()); + throw e; + } + } + + // Periodic recovery mechanism to raise limits when the system is under control + private void adjustLimits() { + int updated = currentLimit.updateAndGet(curr -> Math.min(maxLimit, curr + (initialLimit / 2))); + System.out.printf("[Adaptive] Health check passed - Increasing limit to %d%n", updated); + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/App.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/App.java new file mode 100644 index 000000000000..e76ed5254345 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/App.java @@ -0,0 +1,178 @@ +package com.iluwatar.rate.limiting.pattern; + +import java.security.SecureRandom; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Rate Limiter pattern is a key defensive strategy used to prevent system overload and + * ensure fair usage of shared services. This demo showcases how different rate limiting techniques + * can regulate traffic in distributed systems. + * + *

Specifically, this simulation implements three rate limiter strategies: + * + *

    + *
  • Token Bucket – Allows short bursts followed by steady request rates. + *
  • Fixed Window – Enforces a strict limit per discrete time window (e.g., 3 + * requests/sec). + *
  • Adaptive – Dynamically scales limits based on system health, simulating elastic + * backoff. + *
+ * + *

Each simulated service (e.g., S3, DynamoDB, Lambda) is governed by one of these limiters. + * Multiple concurrent client threads issue randomized requests to these services over a fixed + * duration. Each request is either: + * + *

    + *
  • ALLOWED – Permitted under the current rate limit + *
  • THROTTLED – Rejected due to quota exhaustion + *
  • FAILED – Dropped due to transient service failure + *
+ * + *

Statistics are printed every few seconds, and the simulation exits gracefully after a fixed + * runtime, offering a clear view into how each limiter behaves under pressure. + * + *

Relation to AWS API Gateway:
+ * This implementation mirrors the throttling behavior described in the
+ * AWS API Gateway Request Throttling documentation, where limits are applied per second and + * over longer durations (burst and rate limits). The TokenBucketRateLimiter mimics + * burst capacity, the FixedWindowRateLimiter models steady rate enforcement, and the + * AdaptiveRateLimiter reflects elasticity in real-world systems like AWS Lambda under + * variable load. + */ +public final class App { + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + private static final int RUN_DURATION_SECONDS = 10; + private static final int SHUTDOWN_TIMEOUT_SECONDS = 5; + + static final AtomicInteger successfulRequests = new AtomicInteger(); + static final AtomicInteger throttledRequests = new AtomicInteger(); + static final AtomicInteger failedRequests = new AtomicInteger(); + static final AtomicBoolean running = new AtomicBoolean(true); + private static final String DIVIDER_LINE = "===================================="; + + public static void main(String[] args) { + LOGGER.info("Starting Rate Limiter Demo"); + LOGGER.info(DIVIDER_LINE); + + ExecutorService executor = Executors.newFixedThreadPool(3); + ScheduledExecutorService statsPrinter = Executors.newSingleThreadScheduledExecutor(); + + try { + TokenBucketRateLimiter tb = new TokenBucketRateLimiter(2, 1); + FixedWindowRateLimiter fw = new FixedWindowRateLimiter(3, 1); + AdaptiveRateLimiter ar = new AdaptiveRateLimiter(2, 6); + + statsPrinter.scheduleAtFixedRate(App::printStats, 2, 2, TimeUnit.SECONDS); + + for (int i = 1; i <= 3; i++) { + executor.submit(createClientTask(i, tb, fw, ar)); + } + + Thread.sleep(RUN_DURATION_SECONDS * 1000L); + LOGGER.info("Shutting down the demo..."); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + running.set(false); + shutdownExecutor(executor, "mainExecutor"); + shutdownExecutor(statsPrinter, "statsPrinter"); + printFinalStats(); + LOGGER.info("Demo completed."); + } + } + + private static void shutdownExecutor(ExecutorService service, String name) { + service.shutdown(); + try { + if (!service.awaitTermination(SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS)) { + service.shutdownNow(); + LOGGER.warn("Forced shutdown of {}", name); + } + } catch (InterruptedException e) { + service.shutdownNow(); + Thread.currentThread().interrupt(); + } + } + + static Runnable createClientTask( + int clientId, RateLimiter s3Limiter, RateLimiter dynamoDbLimiter, RateLimiter lambdaLimiter) { + + return () -> { + String[] services = {"s3", "dynamodb", "lambda"}; + String[] operations = { + "GetObject", "PutObject", "Query", "Scan", "PutItem", "Invoke", "ListFunctions" + }; + SecureRandom random = new SecureRandom(); // ✅ Safe & compliant for SonarCloud + + while (running.get() && !Thread.currentThread().isInterrupted()) { + try { + String service = services[random.nextInt(services.length)]; + String operation = operations[random.nextInt(operations.length)]; + + switch (service) { + case "s3" -> makeRequest(clientId, s3Limiter, service, operation); + case "dynamodb" -> makeRequest(clientId, dynamoDbLimiter, service, operation); + case "lambda" -> makeRequest(clientId, lambdaLimiter, service, operation); + default -> LOGGER.warn("Unknown service: {}", service); + } + + Thread.sleep(30L + random.nextInt(50)); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + }; + } + + static void makeRequest(int clientId, RateLimiter limiter, String service, String operation) { + try { + limiter.check(service, operation); + successfulRequests.incrementAndGet(); + LOGGER.info("Client {}: {}.{} - ALLOWED", clientId, service, operation); + } catch (ThrottlingException e) { + throttledRequests.incrementAndGet(); + LOGGER.warn( + "Client {}: {}.{} - THROTTLED (Retry in {}ms)", + clientId, + service, + operation, + e.getRetryAfterMillis()); + } catch (ServiceUnavailableException e) { + failedRequests.incrementAndGet(); + LOGGER.warn("Client {}: {}.{} - SERVICE UNAVAILABLE", clientId, service, operation); + } catch (Exception e) { + failedRequests.incrementAndGet(); + LOGGER.error("Client {}: {}.{} - ERROR: {}", clientId, service, operation, e.getMessage()); + } + } + + static void printStats() { + if (!running.get()) return; + LOGGER.info("=== Current Statistics ==="); + LOGGER.info("Successful Requests: {}", successfulRequests.get()); + LOGGER.info("Throttled Requests : {}", throttledRequests.get()); + LOGGER.info("Failed Requests : {}", failedRequests.get()); + LOGGER.info(DIVIDER_LINE); + } + + static void printFinalStats() { + LOGGER.info("Final Statistics"); + LOGGER.info(DIVIDER_LINE); + LOGGER.info("Successful Requests: {}", successfulRequests.get()); + LOGGER.info("Throttled Requests : {}", throttledRequests.get()); + LOGGER.info("Failed Requests : {}", failedRequests.get()); + LOGGER.info(DIVIDER_LINE); + } + + static void resetCountersForTesting() { + successfulRequests.set(0); + throttledRequests.set(0); + failedRequests.set(0); + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequest.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequest.java new file mode 100644 index 000000000000..a61fc35f496a --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequest.java @@ -0,0 +1,40 @@ +package com.iluwatar.rate.limiting.pattern; + +/** + * A rate-limited customer lookup operation. This class wraps the rate limiting logic and represents + * an executable business request. + */ +public class FindCustomerRequest implements RateLimitOperation { + private final String customerId; + private final RateLimiter rateLimiter; + + public FindCustomerRequest(String customerId, RateLimiter rateLimiter) { + this.customerId = customerId; + this.rateLimiter = rateLimiter; + } + + @Override + public String getServiceName() { + return "CustomerService"; + } + + @Override + public String getOperationName() { + return "FindCustomer"; + } + + @Override + public String execute() throws RateLimitException { + // Ensure the operation respects the assigned rate limiter + rateLimiter.check(getServiceName(), getOperationName()); + + // Simulate actual operation + try { + Thread.sleep(50); // Simulate processing time + return "Customer-" + customerId; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new ServiceUnavailableException(getServiceName(), 1000); + } + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiter.java new file mode 100644 index 000000000000..3a2b52888ca7 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiter.java @@ -0,0 +1,53 @@ +package com.iluwatar.rate.limiting.pattern; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Implements a fixed window rate limiter. It allows up to 'limit' number of requests within a time + * window of fixed size. + */ +public class FixedWindowRateLimiter implements RateLimiter { + private final int limit; + private final long windowMillis; + private final ConcurrentHashMap counters = new ConcurrentHashMap<>(); + + public FixedWindowRateLimiter(int limit, long windowSeconds) { + this.limit = limit; + this.windowMillis = TimeUnit.SECONDS.toMillis(windowSeconds); + } + + @Override + public synchronized void check(String serviceName, String operationName) + throws RateLimitException { + String key = serviceName + ":" + operationName; + WindowCounter counter = counters.computeIfAbsent(key, k -> new WindowCounter()); + + if (!counter.tryIncrement()) { + System.out.printf( + "[FixedWindow] Throttled %s.%s - Limit %d reached in window%n", + serviceName, operationName, limit); + throw new RateLimitException("Rate limit exceeded for " + key, windowMillis); + } else { + System.out.printf( + "[FixedWindow] Allowed %s.%s - Count within window%n", serviceName, operationName); + } + } + + /** Tracks the count of requests within the current window. */ + private class WindowCounter { + private AtomicInteger count = new AtomicInteger(0); + private volatile long windowStart = System.currentTimeMillis(); + + synchronized boolean tryIncrement() { + long now = System.currentTimeMillis(); + // Reset window if expired + if (now - windowStart > windowMillis) { + count.set(0); + windowStart = now; + } + // Enforce the request limit within window + return count.incrementAndGet() <= limit; + } + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitException.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitException.java new file mode 100644 index 000000000000..2b3cc1f3006b --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitException.java @@ -0,0 +1,15 @@ +package com.iluwatar.rate.limiting.pattern; + +/** Base exception for rate limiting errors. */ +public class RateLimitException extends Exception { + private final long retryAfterMillis; + + public RateLimitException(String message, long retryAfterMillis) { + super(message); + this.retryAfterMillis = retryAfterMillis; + } + + public long getRetryAfterMillis() { + return retryAfterMillis; + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitOperation.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitOperation.java new file mode 100644 index 000000000000..59191e81fc04 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimitOperation.java @@ -0,0 +1,10 @@ +package com.iluwatar.rate.limiting.pattern; + +/** Represents a business operation that needs rate limiting. Supports type-safe return values. */ +public interface RateLimitOperation { + String getServiceName(); + + String getOperationName(); + + T execute() throws RateLimitException; +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimiter.java new file mode 100644 index 000000000000..19495b401ddb --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/RateLimiter.java @@ -0,0 +1,13 @@ +package com.iluwatar.rate.limiting.pattern; + +/** Base interface for all rate limiter strategies. */ +public interface RateLimiter { + /** + * Checks if a request is allowed under current rate limits + * + * @param serviceName Service being called (e.g., "dynamodb") + * @param operationName Operation being performed (e.g., "Query") + * @throws RateLimitException if request exceeds limits + */ + void check(String serviceName, String operationName) throws RateLimitException; +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ServiceUnavailableException.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ServiceUnavailableException.java new file mode 100644 index 000000000000..f9fc55f15d20 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ServiceUnavailableException.java @@ -0,0 +1,15 @@ +package com.iluwatar.rate.limiting.pattern; + +/** Exception for when a service is temporarily unavailable. */ +public class ServiceUnavailableException extends RateLimitException { + private final String serviceName; + + public ServiceUnavailableException(String serviceName, long retryAfterMillis) { + super("Service temporarily unavailable: " + serviceName, retryAfterMillis); + this.serviceName = serviceName; + } + + public String getServiceName() { + return serviceName; + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ThrottlingException.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ThrottlingException.java new file mode 100644 index 000000000000..e07087dfee6c --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/ThrottlingException.java @@ -0,0 +1,21 @@ +package com.iluwatar.rate.limiting.pattern; + +/** Exception thrown when AWS-style throttling occurs. */ +public class ThrottlingException extends RateLimitException { + private final String serviceName; + private final String errorCode; + + public ThrottlingException(String serviceName, String operationName, long retryAfterMillis) { + super("AWS throttling error for " + serviceName + "/" + operationName, retryAfterMillis); + this.serviceName = serviceName; + this.errorCode = "ThrottlingException"; + } + + public String getServiceName() { + return serviceName; + } + + public String getErrorCode() { + return errorCode; + } +} diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java new file mode 100644 index 000000000000..3001c880aad3 --- /dev/null +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java @@ -0,0 +1,64 @@ +package com.iluwatar.rate.limiting.pattern; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Token Bucket rate limiter implementation. Allows requests to proceed as long as there are tokens + * available in the bucket. Tokens are added at a fixed interval up to a defined capacity. + */ +public class TokenBucketRateLimiter implements RateLimiter { + private final int capacity; + private final int refillRate; + private final ConcurrentHashMap buckets = new ConcurrentHashMap<>(); + private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + public TokenBucketRateLimiter(int capacity, int refillRate) { + this.capacity = capacity; + this.refillRate = refillRate; + // Refill tokens in all buckets every second + scheduler.scheduleAtFixedRate(this::refillBuckets, 1, 1, TimeUnit.SECONDS); + } + + @Override + public void check(String serviceName, String operationName) throws RateLimitException { + String key = serviceName + ":" + operationName; + TokenBucket bucket = buckets.computeIfAbsent(key, k -> new TokenBucket(capacity)); + + if (!bucket.tryConsume()) { + System.out.printf( + "[TokenBucket] Throttled %s.%s - No tokens available%n", serviceName, operationName); + throw new ThrottlingException(serviceName, operationName, 1000); + } else { + System.out.printf( + "[TokenBucket] Allowed %s.%s - Tokens remaining%n", serviceName, operationName); + } + } + + private void refillBuckets() { + buckets.forEach((k, b) -> b.refill(refillRate)); + } + + /** Inner class that represents the bucket holding tokens for each service-operation. */ + private static class TokenBucket { + private final int capacity; + private final AtomicInteger tokens; + + TokenBucket(int capacity) { + this.capacity = capacity; + this.tokens = new AtomicInteger(capacity); + } + + boolean tryConsume() { + while (true) { + int current = tokens.get(); + if (current <= 0) return false; + if (tokens.compareAndSet(current, current - 1)) return true; + } + } + + void refill(int amount) { + tokens.getAndUpdate(current -> Math.min(current + amount, capacity)); + } + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java new file mode 100644 index 000000000000..042d606490d0 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java @@ -0,0 +1,56 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class AdaptiveRateLimiterTest { + @Test + void shouldDecreaseLimitWhenThrottled() throws Exception { + AdaptiveRateLimiter limiter = new AdaptiveRateLimiter(10, 20); + + // Exceed initial limit + for (int i = 0; i < 11; i++) { + try { + limiter.check("test", "op"); + } catch (RateLimitException e) { + // Expected after 10 requests + } + } + + // Verify limit was reduced + assertThrows( + RateLimitException.class, + () -> { + for (int i = 0; i < 6; i++) { // New limit should be 5 (10/2) + limiter.check("test", "op"); + } + }); + } + + @Test + void shouldGraduallyIncreaseLimitWhenHealthy() throws Exception { + AdaptiveRateLimiter limiter = + new AdaptiveRateLimiter(4, 10); // Start from 4 → expect 2 → expect increase to 4 + + // Force throttling to reduce limit + for (int i = 0; i < 5; i++) { + try { + limiter.check("test", "op"); + } catch (RateLimitException e) { + // Expected to throttle and reduce limit + } + } + + // Wait for health check to increase limit + Thread.sleep(11000); // Wait slightly more than 10 seconds + + // Allow up to 4 requests again (limit should've increased to 4) + for (int i = 0; i < 4; i++) { + limiter.check("test", "op"); + } + + // 5th should throw exception again + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTest.java new file mode 100644 index 000000000000..11815a75de84 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTest.java @@ -0,0 +1,59 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Unit tests for {@link App}. */ +class AppTest { + + private RateLimiter mockLimiter; + + @BeforeEach + void setUp() { + mockLimiter = mock(RateLimiter.class); + AppTestUtils.resetCounters(); // Ensures counters are clean before every test + } + + @Test + void shouldAllowRequest() { + AppTestUtils.invokeMakeRequest(1, mockLimiter, "s3", "GetObject"); + assertEquals(1, AppTestUtils.getSuccessfulRequests().get(), "Successful count should be 1"); + assertEquals(0, AppTestUtils.getThrottledRequests().get(), "Throttled count should be 0"); + assertEquals(0, AppTestUtils.getFailedRequests().get(), "Failed count should be 0"); + } + + @Test + void shouldHandleThrottlingException() throws Exception { + doThrow(new ThrottlingException("s3", "PutObject", 1000)).when(mockLimiter).check(any(), any()); + AppTestUtils.invokeMakeRequest(2, mockLimiter, "s3", "PutObject"); + assertEquals(0, AppTestUtils.getSuccessfulRequests().get()); + assertEquals(1, AppTestUtils.getThrottledRequests().get()); + assertEquals(0, AppTestUtils.getFailedRequests().get()); + } + + @Test + void shouldHandleServiceUnavailableException() throws Exception { + doThrow(new ServiceUnavailableException("lambda", 500)).when(mockLimiter).check(any(), any()); + AppTestUtils.invokeMakeRequest(3, mockLimiter, "lambda", "Invoke"); + assertEquals(0, AppTestUtils.getSuccessfulRequests().get()); + assertEquals(0, AppTestUtils.getThrottledRequests().get()); + assertEquals(1, AppTestUtils.getFailedRequests().get()); + } + + @Test + void shouldHandleGenericException() throws Exception { + doThrow(new RuntimeException("Unexpected")).when(mockLimiter).check(any(), any()); + AppTestUtils.invokeMakeRequest(4, mockLimiter, "dynamodb", "Query"); + assertEquals(0, AppTestUtils.getSuccessfulRequests().get()); + assertEquals(0, AppTestUtils.getThrottledRequests().get()); + assertEquals(1, AppTestUtils.getFailedRequests().get()); + } + + @Test + void shouldRunMainMethodWithoutException() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTestUtils.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTestUtils.java new file mode 100644 index 000000000000..9d652ec96c63 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AppTestUtils.java @@ -0,0 +1,27 @@ +package com.iluwatar.rate.limiting.pattern; + +import java.util.concurrent.atomic.AtomicInteger; + +public class AppTestUtils { + + public static void invokeMakeRequest( + int clientId, RateLimiter limiter, String service, String operation) { + App.makeRequest(clientId, limiter, service, operation); + } + + public static void resetCounters() { + App.resetCountersForTesting(); + } + + public static AtomicInteger getSuccessfulRequests() { + return App.successfulRequests; + } + + public static AtomicInteger getThrottledRequests() { + return App.throttledRequests; + } + + public static AtomicInteger getFailedRequests() { + return App.failedRequests; + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java new file mode 100644 index 000000000000..35a1294a8ad3 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java @@ -0,0 +1,69 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Test; + +class ConcurrencyTests { + @Test + void tokenBucketShouldHandleConcurrentRequests() throws Exception { + int threadCount = 10; + int requestLimit = 5; + RateLimiter limiter = new TokenBucketRateLimiter(requestLimit, requestLimit); + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + CountDownLatch latch = new CountDownLatch(threadCount); + + AtomicInteger successCount = new AtomicInteger(); + AtomicInteger failureCount = new AtomicInteger(); + + for (int i = 0; i < threadCount; i++) { + executor.submit( + () -> { + try { + limiter.check("test", "op"); + successCount.incrementAndGet(); + } catch (RateLimitException e) { + failureCount.incrementAndGet(); + } + latch.countDown(); + }); + } + + latch.await(); + assertEquals(requestLimit, successCount.get()); + assertEquals(threadCount - requestLimit, failureCount.get()); + } + + @Test + void adaptiveLimiterShouldAdjustUnderLoad() throws Exception { + AdaptiveRateLimiter limiter = new AdaptiveRateLimiter(10, 20); + ExecutorService executor = Executors.newFixedThreadPool(20); + + // Flood with requests to trigger throttling + for (int i = 0; i < 30; i++) { + executor.submit( + () -> { + try { + limiter.check("test", "op"); + } catch (RateLimitException ignored) { + } + }); + } + + Thread.sleep(15000); // Wait for adjustment + + // Verify new limit is in effect + int allowed = 0; + for (int i = 0; i < 20; i++) { + try { + limiter.check("test", "op"); + allowed++; + } catch (RateLimitException ignored) { + } + } + + assertTrue(allowed > 5 && allowed < 15); // Should be between initial and max + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ExceptionTests.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ExceptionTests.java new file mode 100644 index 000000000000..a7b037fbe73f --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ExceptionTests.java @@ -0,0 +1,28 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class ExceptionTests { + @Test + void rateLimitExceptionShouldContainRetryInfo() { + RateLimitException exception = new RateLimitException("Test", 1000); + assertEquals(1000, exception.getRetryAfterMillis()); + assertEquals("Test", exception.getMessage()); + } + + @Test + void throttlingExceptionShouldContainServiceInfo() { + ThrottlingException exception = new ThrottlingException("dynamodb", "Query", 500); + assertEquals("dynamodb", exception.getServiceName()); + assertEquals("ThrottlingException", exception.getErrorCode()); + } + + @Test + void serviceUnavailableExceptionShouldContainRetryInfo() { + ServiceUnavailableException exception = new ServiceUnavailableException("s3", 2000); + assertEquals("s3", exception.getServiceName()); + assertEquals(2000, exception.getRetryAfterMillis()); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequestTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequestTest.java new file mode 100644 index 000000000000..d0c3197289cd --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FindCustomerRequestTest.java @@ -0,0 +1,62 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class FindCustomerRequestTest implements RateLimitOperationTest { + + @Override + public RateLimitOperation createOperation(RateLimiter limiter) { + return new FindCustomerRequest("123", limiter); + } + + @Test + void shouldExecuteWhenUnderRateLimit() throws Exception { + RateLimiter limiter = new TokenBucketRateLimiter(10, 10); + RateLimitOperation request = createOperation(limiter); + + String result = request.execute(); + assertEquals("Customer-123", result); + } + + @Test + void shouldThrowWhenRateLimitExceeded() { + RateLimiter limiter = new TokenBucketRateLimiter(0, 0); // Always throttled + RateLimitOperation request = createOperation(limiter); + + assertThrows(RateLimitException.class, request::execute); + } + + @Test + void shouldReturnCorrectServiceAndOperationNames() { + RateLimiter limiter = new TokenBucketRateLimiter(10, 10); + FindCustomerRequest request = new FindCustomerRequest("123", limiter); + + assertEquals("CustomerService", request.getServiceName()); + assertEquals("FindCustomer", request.getOperationName()); + } + + // Reuse helper logic from the interface for coverage + @Test + void shouldExecuteUsingDefaultHelper() throws Exception { + RateLimiter limiter = new TokenBucketRateLimiter(5, 5); + shouldExecuteWhenUnderLimit(createOperation(limiter)); + } + + @Test + void shouldThrowServiceUnavailableOnInterruptedException() { + RateLimiter noOpLimiter = (service, operation) -> {}; // no throttling + + FindCustomerRequest request = + new FindCustomerRequest("999", noOpLimiter) { + @Override + public String execute() throws RateLimitException { + Thread.currentThread().interrupt(); // Simulate thread interruption + return super.execute(); // Should throw ServiceUnavailableException + } + }; + + assertThrows(ServiceUnavailableException.class, request::execute); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiterTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiterTest.java new file mode 100644 index 000000000000..656185b7e68e --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/FixedWindowRateLimiterTest.java @@ -0,0 +1,40 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +class FixedWindowRateLimiterTest extends RateLimiterTest { + @Override + protected RateLimiter createRateLimiter(int limit, long windowMillis) { + return new FixedWindowRateLimiter(limit, windowMillis / 1000); + } + + @Test + void shouldResetCounterAfterWindow() throws Exception { + FixedWindowRateLimiter limiter = + new FixedWindowRateLimiter(1, 1); // 1 request per 1 second window + + // First request should pass + limiter.check("test", "op"); + + // Second request in same window should be throttled + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + + // Wait a bit more than 1 second to ensure window resets + TimeUnit.MILLISECONDS.sleep(1100); + + // After window reset, this should pass again + limiter.check("test", "op"); + } + + @Test + void shouldNotAllowMoreThanLimitInWindow() throws Exception { + FixedWindowRateLimiter limiter = new FixedWindowRateLimiter(3, 1); + for (int i = 0; i < 3; i++) { + limiter.check("test", "op"); + } + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimitOperationTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimitOperationTest.java new file mode 100644 index 000000000000..d4922bdfc073 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimitOperationTest.java @@ -0,0 +1,22 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +interface RateLimitOperationTest { + + RateLimitOperation createOperation(RateLimiter limiter); + + @Test + default void shouldThrowWhenRateLimited() { + RateLimiter limiter = new TokenBucketRateLimiter(0, 0); // Always throttled + RateLimitOperation operation = createOperation(limiter); + assertThrows(RateLimitException.class, operation::execute); + } + + // ✅ No @Test here, just a helper method + default void shouldExecuteWhenUnderLimit(RateLimitOperation operation) throws Exception { + assertNotNull(operation.execute()); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimiterTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimiterTest.java new file mode 100644 index 000000000000..7f1e6b4a2806 --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/RateLimiterTest.java @@ -0,0 +1,25 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +public abstract class RateLimiterTest { + protected abstract RateLimiter createRateLimiter(int limit, long windowMillis); + + @Test + void shouldAllowRequestsWithinLimit() throws Exception { + RateLimiter limiter = createRateLimiter(5, 1000); + for (int i = 0; i < 5; i++) { + limiter.check("test", "op"); + } + } + + @Test + void shouldThrowWhenLimitExceeded() throws Exception { + RateLimiter limiter = createRateLimiter(2, 1000); + limiter.check("test", "op"); + limiter.check("test", "op"); + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + } +} diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiterTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiterTest.java new file mode 100644 index 000000000000..5696299512fb --- /dev/null +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiterTest.java @@ -0,0 +1,39 @@ +package com.iluwatar.rate.limiting.pattern; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.concurrent.TimeUnit; +import org.junit.jupiter.api.Test; + +class TokenBucketRateLimiterTest extends RateLimiterTest { + @Override + protected RateLimiter createRateLimiter(int limit, long windowMillis) { + return new TokenBucketRateLimiter(limit, (int) (limit * 1000 / windowMillis)); + } + + @Test + void shouldAllowBurstRequests() throws Exception { + TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(10, 5); + for (int i = 0; i < 10; i++) { + limiter.check("test", "op"); + } + } + + @Test + void shouldRefillTokensAfterTime() throws Exception { + TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(1, 1); + limiter.check("test", "op"); + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + + TimeUnit.SECONDS.sleep(1); + limiter.check("test", "op"); + } + + @Test + void shouldHandleMultipleServicesSeparately() throws Exception { + TokenBucketRateLimiter limiter = new TokenBucketRateLimiter(1, 1); + limiter.check("service1", "op"); + limiter.check("service2", "op"); + assertThrows(RateLimitException.class, () -> limiter.check("service1", "op")); + } +} From ce5154effcac97300d27a888c8c0f11ef9b1995c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:15:55 +0200 Subject: [PATCH 032/108] docs: add skamble2 as a contributor for code (#3437) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 59c7a7b92a6b..411ca2bc3619 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3557,6 +3557,15 @@ "contributions": [ "code" ] + }, + { + "login": "skamble2", + "name": "Soham Kamble", + "avatar_url": "https://avatars.githubusercontent.com/u/121136639?v=4", + "profile": "https://github.com/skamble2", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 1aeab8760ae0..805e7bdac0a0 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-390-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-391-orange.svg?style=flat-square)](#contributors-)
@@ -580,6 +580,9 @@ This project is licensed under the terms of the MIT license. Naman Srivastava
Naman Srivastava

💻 Thanh Nguyen Duc
Thanh Nguyen Duc

💻 + + Soham Kamble
Soham Kamble

💻 + From b8f819988f8056045c87c4a1e188967399a33b6f Mon Sep 17 00:00:00 2001 From: Olexandr88 Date: Sun, 22 Feb 2026 20:16:56 +0200 Subject: [PATCH 033/108] docs: Update README.md (#3298) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ilkka Seppälä --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 805e7bdac0a0..e726b8890ef0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Design Patterns Implemented in Java -![Java CI](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) +[![Java CI](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg)](https://github.com/iluwatar/java-design-patterns/actions/workflows/maven-ci.yml) [![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) [![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) From 2d39fe7ed8acfb683890644355ab5156c9b37354 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 22 Feb 2026 20:17:34 +0200 Subject: [PATCH 034/108] docs: add Olexandr88 as a contributor for doc (#3440) * 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 411ca2bc3619..ed336828d406 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3566,6 +3566,15 @@ "contributions": [ "code" ] + }, + { + "login": "Olexandr88", + "name": "Olexandr88", + "avatar_url": "https://avatars.githubusercontent.com/u/93856062?v=4", + "profile": "https://github.com/Olexandr88", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index e726b8890ef0..bf0e4ec9f073 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-391-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-392-orange.svg?style=flat-square)](#contributors-)
@@ -582,6 +582,7 @@ This project is licensed under the terms of the MIT license. Soham Kamble
Soham Kamble

💻 + Olexandr88
Olexandr88

📖 From d24dd22bb9d3d2a442fab8ffaa746b78072ba211 Mon Sep 17 00:00:00 2001 From: iluwatar Date: Sun, 3 May 2026 18:11:17 +0300 Subject: [PATCH 035/108] feat: Add AGENTS.md --- AGENTS.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000000..b30cbdd19b06 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,51 @@ +# Java Design Patterns - Priming Context for AI Agents + +## Quick Overview +- This repository is a comprehensive collection of design patterns implemented in Java. +- The project demonstrates how to solve common software design problems using standard patterns. +- The code for each pattern lives directly in this repository, alongside its explanatory README. +- These readmes are published on the java-design-patterns.com website. +- Another repository (https://github.com/iluwatar/java-design-patterns-vuepress-web) handles the deployment of the website. + +## Stack +- **Java 21**: The primary programming language used for pattern implementations. +- **Maven**: Dependency management and build tool. +- **JUnit 5**: The testing framework used to verify pattern behaviors. +- **Mockito**: Used for mocking dependencies in unit tests. +- **Lombok**: Used to reduce boilerplate code (getters, setters, etc.). +- **Spotless**: Enforces consistent code formatting via Google Java Format. + +## Trusted Sources +- [Java SE 21 Documentation](https://docs.oracle.com/en/java/javase/21/docs/api/) +- [Maven Official Documentation](https://maven.apache.org/guides/index.html) +- [JUnit 5 User Guide](https://junit.org/junit5/docs/current/user-guide/) +- [Project Wiki](https://github.com/iluwatar/java-design-patterns/wiki) + +## Structure +- `/pom.xml`: The root Maven configuration file that defines global dependencies and lists all pattern modules. +- `/[pattern-name]/`: Individual folders for each design pattern (e.g., `/abstract-factory`, `/builder`), acting as standalone Maven modules. +- `/[pattern-name]/src/main/java/`: Contains the actual Java implementation classes of the specific design pattern. +- `/[pattern-name]/src/test/java/`: Contains the JUnit tests verifying the pattern's behavior. +- `/[pattern-name]/README.md`: The documentation for the pattern, which gets published to the main website. + +## Patterns +- Keep pattern implementations simple, atomic, and easy to understand. +- Write descriptive and meaningful names for classes, interfaces, and methods. +- Always include comprehensive unit tests for every new pattern or code modification. +- Follow the Google Java Format strictly (enforced by Spotless). +- Document the intent, explanation, and real-world usage clearly in each module's `README.md`. + +## Anti-patterns +- Avoid overcomplicating patterns with unnecessary external dependencies or complex frameworks. +- Do not introduce business logic that distracts from the core mechanism of the design pattern itself. +- Submitting new patterns or features without corresponding unit tests is strictly discouraged. +- Avoid large monolithic packages; each pattern should reside in its own isolated module. + +## Example Design Pattern +When a new design pattern is added to the repository, it generally follows these steps: +- **Create a Module**: Create a new folder for the pattern in the root directory (e.g., `/my-new-pattern`). +- **Update root pom.xml**: Add `my-new-pattern` to the `` section of the root `pom.xml`. +- **Add Module pom.xml**: Create a `pom.xml` inside the new folder that inherits from the parent project. +- **Write the Code**: Implement the pattern logic under `src/main/java/com/iluwatar/mynewpattern`, usually including an `App.java` class to demonstrate its usage. +- **Write the Tests**: Add comprehensive unit tests under `src/test/java/com/iluwatar/mynewpattern`. +- **Document**: Create a `README.md` at the root of the new module, structured with standard sections like Intent, Explanation, Class diagram, Applicability, and Real world examples. From e4384ef7d2c1684e7d57612ca82a622dae60159b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 31 May 2026 08:03:33 +0300 Subject: [PATCH 036/108] fix: Update PR builder not to execute Sonar analysis (#3486) --- .github/workflows/maven-pr-builder.yml | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 99ee85152962..2bae03814fcf 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -1,7 +1,7 @@ name: Java PR Builder on: - pull_request_target: + pull_request: branches: [ master ] types: [ opened, reopened, synchronize ] @@ -17,8 +17,6 @@ jobs: - name: Checkout Code uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - name: Set up JDK 21 uses: actions/setup-java@v4 @@ -35,23 +33,9 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - # Cache Sonar packages which are used to run analysis and collect metrics - - name: Cache SonarCloud packages - uses: actions/cache@v4 - with: - path: ~/.sonar/cache - key: ${{ runner.os }}-sonar - restore-keys: ${{ runner.os }}-sonar - # Some tests need screen access - name: Install xvfb run: sudo apt-get install -y xvfb - - name: Build with Maven and run SonarQube analysis - env: - # Intermediate variable - HEAD_REF: ${{ github.head_ref }} - # These two env variables are needed for sonar analysis - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: xvfb-run ./mvnw clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.organization=iluwatar -Dsonar.projectKey=iluwatar_java-design-patterns -Dsonar.pullrequest.branch=$HEAD_REF -Dsonar.pullrequest.base=${{ github.base_ref }} -Dsonar.pullrequest.key=${{ github.event.pull_request.number }} \ No newline at end of file + - name: Build with Maven + run: xvfb-run ./mvnw clean verify \ No newline at end of file From 83887271ae8e2b35ed36615048187e83f1dc9146 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:25:58 +0300 Subject: [PATCH 037/108] docs: add nilsreichardt as a contributor for security (#3488) * 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 ed336828d406..c854c92b5035 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3575,6 +3575,15 @@ "contributions": [ "doc" ] + }, + { + "login": "nilsreichardt", + "name": "Nils Reichardt", + "avatar_url": "https://avatars.githubusercontent.com/u/24459435?v=4", + "profile": "https://github.com/nilsreichardt", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index bf0e4ec9f073..1208dbb57786 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-392-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-393-orange.svg?style=flat-square)](#contributors-)
@@ -583,6 +583,7 @@ This project is licensed under the terms of the MIT license. Soham Kamble
Soham Kamble

💻 Olexandr88
Olexandr88

📖 + Nils Reichardt
Nils Reichardt

🛡️ From 213a4a5ee71b90c47383f18f52da64d4e038ba74 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:26:42 +0300 Subject: [PATCH 038/108] docs: add north-echo as a contributor for security (#3489) * 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 c854c92b5035..138846e43acd 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3584,6 +3584,15 @@ "contributions": [ "security" ] + }, + { + "login": "north-echo", + "name": "Christopher Lusk", + "avatar_url": "https://avatars.githubusercontent.com/u/122107484?v=4", + "profile": "http://www.northecho.dev", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 1208dbb57786..86a0c9accb6a 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-393-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-394-orange.svg?style=flat-square)](#contributors-)
@@ -584,6 +584,7 @@ This project is licensed under the terms of the MIT license. Soham Kamble
Soham Kamble

💻 Olexandr88
Olexandr88

📖 Nils Reichardt
Nils Reichardt

🛡️ + Christopher Lusk
Christopher Lusk

🛡️ From 546d9a5baedc651fb337c69fd133e692b075bb77 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:27:29 +0300 Subject: [PATCH 039/108] docs: add dagecko as a contributor for security (#3490) * 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 138846e43acd..481fbc748a69 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3593,6 +3593,15 @@ "contributions": [ "security" ] + }, + { + "login": "dagecko", + "name": "dagecko", + "avatar_url": "https://avatars.githubusercontent.com/u/6371704?v=4", + "profile": "https://github.com/dagecko", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 86a0c9accb6a..1e40ac7b2546 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-394-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-395-orange.svg?style=flat-square)](#contributors-)
@@ -585,6 +585,7 @@ This project is licensed under the terms of the MIT license. Olexandr88
Olexandr88

📖 Nils Reichardt
Nils Reichardt

🛡️ Christopher Lusk
Christopher Lusk

🛡️ + dagecko
dagecko

🛡️ From 5a0440b696ef1d075cef1d534570e6745d373737 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:28:18 +0300 Subject: [PATCH 040/108] docs: add jackmisbach as a contributor for security (#3491) * 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 481fbc748a69..35dd8445496e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3602,6 +3602,15 @@ "contributions": [ "security" ] + }, + { + "login": "jackmisbach", + "name": "jackmisbach", + "avatar_url": "https://avatars.githubusercontent.com/u/183796460?v=4", + "profile": "https://github.com/jackmisbach", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 1e40ac7b2546..45742cbd8d4f 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-395-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-396-orange.svg?style=flat-square)](#contributors-)
@@ -586,6 +586,7 @@ This project is licensed under the terms of the MIT license. Nils Reichardt
Nils Reichardt

🛡️ Christopher Lusk
Christopher Lusk

🛡️ dagecko
dagecko

🛡️ + jackmisbach
jackmisbach

🛡️ From f7ad42dc057b921224ad2f9f3ee09fbea8e76a48 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:28:52 +0300 Subject: [PATCH 041/108] docs: add avivdon as a contributor for security (#3492) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 35dd8445496e..f11c631b14c1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3611,6 +3611,15 @@ "contributions": [ "security" ] + }, + { + "login": "avivdon", + "name": "avivdon", + "avatar_url": "https://avatars.githubusercontent.com/u/74790003?v=4", + "profile": "https://github.com/avivdon", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 45742cbd8d4f..e79b748c12b2 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-396-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-397-orange.svg?style=flat-square)](#contributors-)
@@ -588,6 +588,9 @@ This project is licensed under the terms of the MIT license. dagecko
dagecko

🛡️ jackmisbach
jackmisbach

🛡️ + + avivdon
avivdon

🛡️ + From 318130c4862bfbaf77d35297b952808b71d3262c Mon Sep 17 00:00:00 2001 From: Aditya Kumawat <56085648+quantdevv@users.noreply.github.com> Date: Sun, 31 May 2026 20:24:58 +0530 Subject: [PATCH 042/108] #2673: feat: Microservice pattern: Polling publisher #3243 (#3292) * added new microservice pattern polling-publisher, created folder structure, README.md & App.java * added two service polling service & publisher service to handle two different operation & prepared initial skeleton * polling-publisher service implementation * fixed checkstyle errors * subscriber-service implementation * added entry point for subscriber service & unit test-case * added unit test-case for DataSourceService class * resolved dependency & structured classes * implemented Data repository, DataSource Service & added unittest-case & implemented polling-service microservice * implemented subscriber microservice using kafkaConsumer * Fixed Kafka bug & added a controller to send message using API * Fixed subscriber-service & updated pom.xml * Fixed topic name * added new listener for other topic * updated all README.md * added description on both application.yaml file * added scope before class definition in Test classes & removed duplicate dependency from pom.xml & added required one * added polling-publisher module in pom.xml * Updated README.md file based on new template * improved the README.md file & fixed it's format * deleted unnecessary README.md files * fixed the printing statements & used log function * used logger to print statement * addressed review comment: removed unnecessary dependency * addressed review comment --- polling-publisher/README.md | 119 ++++++++++++++++++ .../etc/polling-publisher.urm.puml | 2 + .../etc/polling-service.urm.puml | 2 + polling-publisher/polling-service/pom.xml | 59 +++++++++ .../main/java/com/iluwatar/polling/App.java | 45 +++++++ .../com/iluwatar/polling/DataRepository.java | 67 ++++++++++ .../iluwatar/polling/DataSourceService.java | 81 ++++++++++++ .../com/iluwatar/polling/KafkaProducer.java | 50 ++++++++ .../iluwatar/polling/PollingController.java | 50 ++++++++ .../iluwatar/polling/PollingScheduler.java | 61 +++++++++ .../src/main/resources/application.yml | 36 ++++++ .../java/com/iluwatar/polling/AppTest.java | 39 ++++++ .../iluwatar/polling/DataRepositoryTest.java | 78 ++++++++++++ .../polling/DataSourceServiceTest.java | 84 +++++++++++++ polling-publisher/pom.xml | 106 ++++++++++++++++ .../etc/subscriber-service.urm.puml | 2 + polling-publisher/subscriber-service/pom.xml | 59 +++++++++ .../java/com/iluwatar/subscriber/App.java | 37 ++++++ .../iluwatar/subscriber/KafkaConsumer.java | 48 +++++++ .../src/main/resources/application.yml | 33 +++++ .../java/com/iluwatar/subscriber/AppTest.java | 40 ++++++ pom.xml | 1 + 22 files changed, 1099 insertions(+) create mode 100644 polling-publisher/README.md create mode 100644 polling-publisher/etc/polling-publisher.urm.puml create mode 100644 polling-publisher/polling-service/etc/polling-service.urm.puml create mode 100644 polling-publisher/polling-service/pom.xml create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataRepository.java create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/KafkaProducer.java create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingController.java create mode 100644 polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingScheduler.java create mode 100644 polling-publisher/polling-service/src/main/resources/application.yml create mode 100644 polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java create mode 100644 polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataRepositoryTest.java create mode 100644 polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java create mode 100644 polling-publisher/pom.xml create mode 100644 polling-publisher/subscriber-service/etc/subscriber-service.urm.puml create mode 100644 polling-publisher/subscriber-service/pom.xml create mode 100644 polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java create mode 100644 polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/KafkaConsumer.java create mode 100644 polling-publisher/subscriber-service/src/main/resources/application.yml create mode 100644 polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java diff --git a/polling-publisher/README.md b/polling-publisher/README.md new file mode 100644 index 000000000000..45e02ac59d21 --- /dev/null +++ b/polling-publisher/README.md @@ -0,0 +1,119 @@ +--- +title: "Polling Publisher-Subscriber Pattern in Java: Mastering Asynchronous Messaging Elegantly" +shortTitle: Polling Pub/Sub +description: "Learn how to implement a Polling Publisher-Subscriber system in Java using Spring Boot and Kafka. Explore the architecture, real-world analogies, and benefits of asynchronous communication with clean code examples." +category: Architectural +language: en +tag: + - Spring Boot + - Kafka + - Microservices + - Asynchronous Messaging + - Decoupling +--- + +## Also known as + +* Event-Driven Architecture +* Asynchronous Pub/Sub Pattern +* Message Queue-Based Polling System + +## Intent of Polling Publisher-Subscriber Pattern + +The Polling Publisher-Subscriber pattern decouples data producers from consumers by enabling asynchronous, message-driven communication. A service polls a data source and publishes messages to a message broker (e.g., Kafka), which are then consumed by one or more subscriber services. + +## Detailed Explanation of the Pattern with Real-World Examples + +### Real-world analogy + +> A news agency constantly polls for the latest news updates. Once it receives new information, it publishes them to different news outlets (TV, newspapers, apps). Each outlet consumes and displays the updates independently. + +### In plain words + +> One service regularly checks for updates (polls) and sends messages to Kafka. Another service listens to Kafka and processes the messages asynchronously. + +### Wikipedia says + +> This pattern closely resembles the [Publish–subscribe model](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern), where messages are sent by publishers and received by subscribers without them knowing each other. + +### Architecture Flow + +``` ++------------+ +--------+ +-------------+ +| Publisher | ---> | Kafka | ---> | Subscriber | ++------------+ +--------+ +-------------+ +``` + +## Programmatic Example (Spring Boot + Kafka) + +### Publisher Service + +- Uses Spring's `@Scheduled` to poll data periodically. +- Publishes data to a Kafka topic. +- Optionally exposes a REST API for manual data publishing. + +```java +@Scheduled(fixedRate = 5000) +public void pollAndPublish() { + String data = pollingService.getLatestData(); + kafkaTemplate.send("updates-topic", data); +} +``` + +### Subscriber Service + +- Listens to Kafka topic using `@KafkaListener`. +- Processes messages asynchronously. + +```java +@KafkaListener(topics = "updates-topic") +public void processUpdate(String message) { + log.info("Received update: {}", message); + updateProcessor.handle(message); +} +``` + +## When to Use the Polling Publisher-Subscriber Pattern + +Use this pattern when: + +* Real-time push from the producer is not possible. +* Loose coupling between producers and consumers is desired. +* You need asynchronous, scalable event processing. +* You are building an event-driven microservices architecture. + +## Real-World Applications + +* Real-time reporting dashboards +* Health check aggregators for distributed systems +* IoT telemetry processing +* Notification and alerting systems + +## Benefits and Trade-offs of Polling Pub/Sub Pattern + +### Benefits + +* Loose coupling between services +* Asynchronous and scalable architecture +* Fault-tolerant with message persistence in Kafka +* Easy to extend with new consumers or publishers + +### Trade-Offs + +* Polling introduces latency between data generation and consumption +* Requires managing and configuring Kafka (or other brokers) +* Slightly more complex deployment and infrastructure setup + +## Related Java Design Patterns + +* [Observer Pattern](https://java-design-patterns.com/patterns/observer/) +* [Mediator Pattern](https://java-design-patterns.com/patterns/mediator/) +* [Message Queue Pattern](https://java-design-patterns.com/patterns/event-queue/) + +## References and Credits + +* [Apache Kafka Documentation](https://kafka.apache.org/documentation/) +* [Spring Kafka Documentation](https://docs.spring.io/spring-kafka) +* [Spring Scheduled Tasks](https://www.baeldung.com/spring-scheduled-tasks) +* [Spring Kafka Tutorial – Baeldung](https://www.baeldung.com/spring-kafka) +* Inspired by: [iluwatar/java-design-patterns](https://github.com/iluwatar/java-design-patterns) \ No newline at end of file diff --git a/polling-publisher/etc/polling-publisher.urm.puml b/polling-publisher/etc/polling-publisher.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/polling-publisher/etc/polling-publisher.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/polling-publisher/polling-service/etc/polling-service.urm.puml b/polling-publisher/polling-service/etc/polling-service.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/polling-publisher/polling-service/etc/polling-service.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/polling-publisher/polling-service/pom.xml b/polling-publisher/polling-service/pom.xml new file mode 100644 index 000000000000..a587a96521fe --- /dev/null +++ b/polling-publisher/polling-service/pom.xml @@ -0,0 +1,59 @@ + + + + 4.0.0 + + com.iluwatar + polling-publisher + 1.26.0-SNAPSHOT + + + polling-service + jar + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.polling-service.App + + + + + + + + + + diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java new file mode 100644 index 000000000000..0b5f9f4d00fa --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.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.polling; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** Polling-Publisher pattern paradigm. */ +@SpringBootApplication +@EnableScheduling +public class App { + + /** + * Program entry point. + * + * @param args command line args. + */ + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } +} diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataRepository.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataRepository.java new file mode 100644 index 000000000000..61483e9dedcf --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataRepository.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.polling; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.PostConstruct; +import org.springframework.stereotype.Repository; + +/** Data repository to keep or store data. */ +@Repository +public class DataRepository { + + private final Map dataStorage = new HashMap<>(); + + /** init after map creation ... to put dummy data. */ + @PostConstruct + public void init() { + // Injecting dummy data at startup + dataStorage.put(2, "Initial Dummy Data - two - 2"); + dataStorage.put(3, "Initial Dummy Data - three - 3"); + dataStorage.put(4, "Initial Dummy Data - four - 4"); + } + + /** Save data to the repository. */ + public void save(int id, String value) { + dataStorage.put(id, value); + } + + /** Retrieve data by ID. */ + public String findById(int id) { + return dataStorage.getOrDefault(id, "Data not found"); + } + + /** Delete data by ID. */ + public void delete(int id) { + dataStorage.remove(id); + } + + /** Get all data. */ + public Map findAll() { + return dataStorage; + } +} diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java new file mode 100644 index 000000000000..45dd317fce74 --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.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.polling; + +import java.util.Map; +import java.util.Random; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +/** This class is responsible for keeping the events. */ +@Service +public class DataSourceService { + + private static final Logger log = LoggerFactory.getLogger(DataSourceService.class); + + private final DataRepository repository; + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); + + /** Constructor & Scheduler to push random data. */ + public DataSourceService(DataRepository repository) { + this.repository = repository; + scheduleDataGeneration(); + } + + private void scheduleDataGeneration() { + Random random = new Random(); + scheduler.scheduleAtFixedRate( + () -> { + int id = random.nextInt(100); // Random ID + String value = "Auto-Data-" + id; + this.addData(id, value); + log.info("🔵 Data Added: {} -> {}", id, value); + }, + 0, + 3, + TimeUnit.SECONDS); + } + + public void addData(int id, String value) { + repository.save(id, value); + } + + public String getData(int id) { + return repository.findById(id); + } + + public void removeData(int id) { + repository.delete(id); + } + + public Map getAllData() { + return repository.findAll(); + } +} diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/KafkaProducer.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/KafkaProducer.java new file mode 100644 index 000000000000..23479f83250a --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/KafkaProducer.java @@ -0,0 +1,50 @@ +/* + * 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.polling; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +/** This class is responsible for sending messages to Kafka. */ +@Component +public class KafkaProducer { + + @Autowired private final KafkaTemplate kafkaTemplate; + + public KafkaProducer(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + /** + * Sends a message to the Kafka topic. + * + * @param message The message to send. + */ + public void sendMessage(String topic, String message) { + kafkaTemplate.send(topic, message); + } +} diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingController.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingController.java new file mode 100644 index 000000000000..cf78fc716c19 --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingController.java @@ -0,0 +1,50 @@ +/* + * 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.polling; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** This class is responsible for contolling polling tasks. */ +@RestController +public class PollingController { + + @Autowired private KafkaProducer kafkaProducer; + + @GetMapping("/health") + public String healthCheck() { + return "Polling Service is up and running!"; + } + + @PostMapping("/send") + public String sendMessage(@RequestParam("message") String message) { + kafkaProducer.sendMessage("API", message); + return "Message sent: " + message; + } +} diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingScheduler.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingScheduler.java new file mode 100644 index 000000000000..5c8361c2ff67 --- /dev/null +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/PollingScheduler.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.polling; + +import java.util.Random; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** This class is responsible for scheduling polling tasks. */ +@Component +public class PollingScheduler { + + private static final Logger log = LoggerFactory.getLogger(PollingScheduler.class); + @Autowired private DataSourceService dataSourceService; + @Autowired private KafkaProducer kafkaProducer; + + /** Scheduler for poll data on each 5 second. */ + @Scheduled(fixedRate = 5000) // Poll every 5 seconds + public void pollDataSource() { + try { + int id = new Random().nextInt(100); // Pick a random ID + String data = dataSourceService.getData(id); // Get data from service + + if (data != null) { + log.info("🟢 Publishing Data: {}", data); + kafkaProducer.sendMessage("updates", data); + } else { + log.info("🔴 No Data Found for ID: {}", id); + } + } catch (Exception e) { + log.error("Error while publishing data {}", e.getMessage()); + throw new RuntimeException(e); + } + } +} diff --git a/polling-publisher/polling-service/src/main/resources/application.yml b/polling-publisher/polling-service/src/main/resources/application.yml new file mode 100644 index 000000000000..3ad766e6d017 --- /dev/null +++ b/polling-publisher/polling-service/src/main/resources/application.yml @@ -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. +# + +server: + port: 8081 + +spring: + kafka: + bootstrap-servers: localhost:9092 # Kafka broker address(es) + consumer: + group-id: subscriber-group # Consumer group ID + auto-offset-reset: earliest # How to reset offset on consumer startup + # Add other consumer properties here + diff --git a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java new file mode 100644 index 000000000000..d54972662be7 --- /dev/null +++ b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.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.polling; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class AppTest { + + @Test + void polling() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataRepositoryTest.java b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataRepositoryTest.java new file mode 100644 index 000000000000..034019462a02 --- /dev/null +++ b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataRepositoryTest.java @@ -0,0 +1,78 @@ +/* + * 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.polling; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class DataRepositoryTest { + + private DataRepository repository; + + @BeforeEach + void setUp() { + repository = new DataRepository(); // Initialize before each test + } + + @Test + void testSaveAndFindById() { + repository.save(1, "Test Data"); + + String result = repository.findById(1); + + assertEquals("Test Data", result, "The retrieved data should match the stored value."); + } + + @Test + void testFindById_NotFound() { + String result = repository.findById(99); + + assertEquals("Data not found", result, "Should return 'Data not found' for missing entries."); + } + + @Test + void testDelete() { + repository.save(2, "To be deleted"); + repository.delete(2); + + String result = repository.findById(2); + + assertEquals("Data not found", result, "Deleted data should not be retrievable."); + } + + @Test + void testFindAll() { + repository.save(1, "First"); + repository.save(2, "Second"); + + Map allData = repository.findAll(); + + assertEquals(2, allData.size(), "The repository should contain two items."); + assertTrue(allData.containsKey(1) && allData.containsKey(2), "Both keys should exist."); + } +} diff --git a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java new file mode 100644 index 000000000000..1f861e45beb3 --- /dev/null +++ b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java @@ -0,0 +1,84 @@ +/* + * 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.polling; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Map; +import org.junit.jupiter.api.*; + +public class DataSourceServiceTest { + + private DataRepository repository; + private DataSourceService service; + + @BeforeEach + void setUp() { + repository = new DataRepository(); + service = new DataSourceService(repository); + } + + @Test + void testAddData() { + service.addData(1, "Test Data"); + + assertEquals("Test Data", repository.findById(1)); + } + + @Test + void testGetData() { + repository.save(1, "Test Data"); + + String result = service.getData(1); + + assertEquals("Test Data", result, "The retrieved data should match."); + } + + @Test + void testRemoveData() { + repository.save(2, "Some Data"); + + service.removeData(2); + + assertEquals( + "Data not found", repository.findById(2), "Deleted data should not be retrievable."); + } + + @Test + void testGetAllData() { + Map result = service.getAllData(); + + int size = result.size(); + repository.save(1, "First"); + repository.save(2, "Second"); + + Map result1 = service.getAllData(); + + assertEquals(size + 2, result.size(), "Should return all stored data."); + assertEquals("First", result.get(1), "Value for key 1 should be 'First'."); + assertEquals("Second", result.get(2), "Value for key 2 should be 'Second'."); + } +} diff --git a/polling-publisher/pom.xml b/polling-publisher/pom.xml new file mode 100644 index 000000000000..7cf4c83bae7d --- /dev/null +++ b/polling-publisher/pom.xml @@ -0,0 +1,106 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + polling-publisher + pom + + + polling-service + subscriber-service + + + + + org.springframework.boot + spring-boot-starter-web + ${spring-boot.version} + + + + org.springframework.boot + spring-boot-starter + ${spring-boot.version} + + + + + org.springframework.boot + spring-boot-starter-test + ${spring-boot.version} + test + + + + + org.springframework.kafka + spring-kafka + 3.3.2 + + + + org.springframework.kafka + spring-kafka-test + 3.3.2 + test + + + + + org.springframework.boot + spring-boot + ${spring-boot.version} + + + + + javax.annotation + javax.annotation-api + 1.3.2 + + + + ch.qos.logback + logback-core + 1.5.18 + + + ch.qos.logback + logback-classic + 1.5.18 + + + + + diff --git a/polling-publisher/subscriber-service/etc/subscriber-service.urm.puml b/polling-publisher/subscriber-service/etc/subscriber-service.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/polling-publisher/subscriber-service/etc/subscriber-service.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/polling-publisher/subscriber-service/pom.xml b/polling-publisher/subscriber-service/pom.xml new file mode 100644 index 000000000000..384f1b66c244 --- /dev/null +++ b/polling-publisher/subscriber-service/pom.xml @@ -0,0 +1,59 @@ + + + + 4.0.0 + + com.iluwatar + polling-publisher + 1.26.0-SNAPSHOT + + + subscriber-service + jar + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.subscriber-service.App + + + + + + + + + + diff --git a/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java new file mode 100644 index 000000000000..b8dd8a23f4ec --- /dev/null +++ b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.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.subscriber; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** Polling-Publisher pattern paradigm. */ +@SpringBootApplication +public class App { + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } +} diff --git a/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/KafkaConsumer.java b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/KafkaConsumer.java new file mode 100644 index 000000000000..c159b467dcf1 --- /dev/null +++ b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/KafkaConsumer.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.subscriber; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Service; + +/** Kafka consumer service to consume messages / updates. */ +@Service +public class KafkaConsumer { + + private static final Logger log = LoggerFactory.getLogger(KafkaConsumer.class); + + @KafkaListener(topics = "updates", groupId = "subscriber-group") + public void listenUpdates(String message) { + log.info("[updates]: Received message: {}", message); + } + + @KafkaListener(topics = "API", groupId = "subscriber-group") + public void listenApi(String message) { + log.info("[API]: Received message from /send : {}", message); + } +} diff --git a/polling-publisher/subscriber-service/src/main/resources/application.yml b/polling-publisher/subscriber-service/src/main/resources/application.yml new file mode 100644 index 000000000000..16b8425f39b5 --- /dev/null +++ b/polling-publisher/subscriber-service/src/main/resources/application.yml @@ -0,0 +1,33 @@ +# +# 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. +# + +server: + port: 8082 + +spring: + kafka: + bootstrap-servers: localhost:9092 # Kafka broker address(es) + consumer: + group-id: subscriber-group \ No newline at end of file diff --git a/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java b/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java new file mode 100644 index 000000000000..b03222d435e0 --- /dev/null +++ b/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java @@ -0,0 +1,40 @@ +/* + * 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.subscriber; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class AppTest { + + @Test + void subscriber() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/pom.xml b/pom.xml index 82d15bdf1d74..827b326c0287 100644 --- a/pom.xml +++ b/pom.xml @@ -191,6 +191,7 @@ partial-response pipeline poison-pill + polling-publisher presentation-model private-class-data producer-consumer From f93514af39e05e598e4b847e2d35735f6fd9d4db Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 17:55:39 +0300 Subject: [PATCH 043/108] docs: add quantdevv as a contributor for code (#3493) * 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 f11c631b14c1..8092a956f0eb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3620,6 +3620,15 @@ "contributions": [ "security" ] + }, + { + "login": "quantdevv", + "name": "Aditya Kumawat", + "avatar_url": "https://avatars.githubusercontent.com/u/56085648?v=4", + "profile": "https://github.com/quantdevv", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index e79b748c12b2..bfe48e6f5c02 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-397-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-398-orange.svg?style=flat-square)](#contributors-)
@@ -590,6 +590,7 @@ This project is licensed under the terms of the MIT license. avivdon
avivdon

🛡️ + Aditya Kumawat
Aditya Kumawat

💻 From 9f0b7ae81dd44ce991277cb223e163f2251bc8f8 Mon Sep 17 00:00:00 2001 From: devch37 <72903623+devch37@users.noreply.github.com> Date: Mon, 1 Jun 2026 00:03:03 +0900 Subject: [PATCH 044/108] feat: add override annotation (#3306) Co-authored-by: behappyleee <72903623+behappyleee@users.noreply.github.com> --- layered-architecture/src/main/java/view/CakeViewImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/layered-architecture/src/main/java/view/CakeViewImpl.java b/layered-architecture/src/main/java/view/CakeViewImpl.java index a01d1c1600a0..8c2617b7bba7 100644 --- a/layered-architecture/src/main/java/view/CakeViewImpl.java +++ b/layered-architecture/src/main/java/view/CakeViewImpl.java @@ -40,6 +40,7 @@ public CakeViewImpl(CakeBakingService cakeBakingService) { this.cakeBakingService = cakeBakingService; } + @Override public void render() { cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString())); } From 9e65023a9fb86abbf2041a91f877e8b0d7939b0f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 18:03:44 +0300 Subject: [PATCH 045/108] docs: add devch37 as a contributor for code (#3494) * 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 8092a956f0eb..5b3df17cccbe 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3629,6 +3629,15 @@ "contributions": [ "code" ] + }, + { + "login": "devch37", + "name": "devch37", + "avatar_url": "https://avatars.githubusercontent.com/u/72903623?v=4", + "profile": "https://github.com/devch37", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index bfe48e6f5c02..d7ca3aa11794 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-398-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-399-orange.svg?style=flat-square)](#contributors-)
@@ -591,6 +591,7 @@ This project is licensed under the terms of the MIT license. avivdon
avivdon

🛡️ Aditya Kumawat
Aditya Kumawat

💻 + devch37
devch37

💻 From b93a202d60e82eadbcd9df3ad429d9c37e315fcb Mon Sep 17 00:00:00 2001 From: HY-love-sleep <73268470+HY-love-sleep@users.noreply.github.com> Date: Sun, 31 May 2026 23:17:23 +0800 Subject: [PATCH 046/108] feat: Refactor Callback pattern to support asynchronous callbacks (#3274) * refactor: Refactor Task execution to support asynchronous callbacks * fix: CallbackTest * chore: code style * feat: display synchronous and asynchronous callbacks --- .../main/java/com/iluwatar/callback/App.java | 7 ++- .../java/com/iluwatar/callback/Callback.java | 1 + .../main/java/com/iluwatar/callback/Task.java | 19 +++++++- .../com/iluwatar/callback/CallbackTest.java | 44 +++++++++++++++---- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/callback/src/main/java/com/iluwatar/callback/App.java b/callback/src/main/java/com/iluwatar/callback/App.java index 7b630f8da247..9afaa3fc33fa 100644 --- a/callback/src/main/java/com/iluwatar/callback/App.java +++ b/callback/src/main/java/com/iluwatar/callback/App.java @@ -39,6 +39,11 @@ private App() {} /** Program entry point. */ public static void main(final String[] args) { var task = new SimpleTask(); - task.executeWith(() -> LOGGER.info("I'm done now.")); + + LOGGER.info("=== Synchronous callback ==="); + task.executeWith(() -> LOGGER.info("Sync callback executed.")); + + LOGGER.info("=== Asynchronous callback ==="); + task.executeAsyncWith(() -> LOGGER.info("Async callback executed.")).join(); } } diff --git a/callback/src/main/java/com/iluwatar/callback/Callback.java b/callback/src/main/java/com/iluwatar/callback/Callback.java index 7b75b5c71077..67b2880e1681 100644 --- a/callback/src/main/java/com/iluwatar/callback/Callback.java +++ b/callback/src/main/java/com/iluwatar/callback/Callback.java @@ -25,6 +25,7 @@ package com.iluwatar.callback; /** Callback interface. */ +@FunctionalInterface public interface Callback { void call(); diff --git a/callback/src/main/java/com/iluwatar/callback/Task.java b/callback/src/main/java/com/iluwatar/callback/Task.java index d69697454dff..d58d55540f52 100644 --- a/callback/src/main/java/com/iluwatar/callback/Task.java +++ b/callback/src/main/java/com/iluwatar/callback/Task.java @@ -25,15 +25,30 @@ package com.iluwatar.callback; import java.util.Optional; +import java.util.concurrent.CompletableFuture; -/** Template-method class for callback hook execution. */ +/** + * Template-method class for callback hook execution. + * + *

Provides both synchronous and asynchronous execution with callback support. + */ public abstract class Task { - /** Execute with callback. */ + /** Execute the task and call the callback method synchronously upon completion. */ final void executeWith(Callback callback) { execute(); Optional.ofNullable(callback).ifPresent(Callback::call); } + /** Execute the task and asynchronously call the callback method upon completion. */ + final CompletableFuture executeAsyncWith(Callback callback) { + return CompletableFuture.runAsync( + () -> { + execute(); + Optional.ofNullable(callback).ifPresent(Callback::call); + }); + } + + /** Actual work to be implemented by subclasses. */ public abstract void execute(); } diff --git a/callback/src/test/java/com/iluwatar/callback/CallbackTest.java b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java index 99939d491f4e..64780babec84 100644 --- a/callback/src/test/java/com/iluwatar/callback/CallbackTest.java +++ b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java @@ -26,6 +26,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; /** @@ -39,19 +42,44 @@ class CallbackTest { private Integer callingCount = 0; @Test - void test() { - Callback callback = () -> callingCount++; - + void testSynchronousCallback() { + var counter = new AtomicInteger(); + Callback callback = counter::incrementAndGet; var task = new SimpleTask(); - assertEquals(Integer.valueOf(0), callingCount, "Initial calling count of 0"); - + assertEquals(0, counter.get(), "Initial count should be 0"); task.executeWith(callback); + assertEquals(1, counter.get(), "Callback should be called once"); + task.executeWith(callback); + assertEquals(2, counter.get(), "Callback should be called twice"); + } - assertEquals(Integer.valueOf(1), callingCount, "Callback called once"); + @Test + void testAsynchronousCallback() { + var task = new SimpleTask(); - task.executeWith(callback); + var counter1 = new AtomicInteger(); + final CompletableFuture future1 = new CompletableFuture<>(); + Callback callback1 = + () -> { + counter1.incrementAndGet(); + future1.complete(null); + }; + var f1 = task.executeAsyncWith(callback1); + future1.orTimeout(1, TimeUnit.SECONDS).join(); + f1.join(); + assertEquals(1, counter1.get(), "Async callback should increment once"); - assertEquals(Integer.valueOf(2), callingCount, "Callback called twice"); + var counter2 = new AtomicInteger(); + final CompletableFuture future2 = new CompletableFuture<>(); + Callback callback2 = + () -> { + counter2.incrementAndGet(); + future2.complete(null); + }; + var f2 = task.executeAsyncWith(callback2); + future2.orTimeout(1, TimeUnit.SECONDS).join(); + f2.join(); + assertEquals(1, counter2.get(), "Async callback should increment once again"); } } From 48ba55a8a670ed10ccb66fe9e23d930518deef6e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 31 May 2026 18:18:10 +0300 Subject: [PATCH 047/108] docs: add HY-love-sleep as a contributor for code (#3495) * 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 5b3df17cccbe..571eb0af649b 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3638,6 +3638,15 @@ "contributions": [ "code" ] + }, + { + "login": "HY-love-sleep", + "name": "HY-love-sleep", + "avatar_url": "https://avatars.githubusercontent.com/u/73268470?v=4", + "profile": "https://github.com/HY-love-sleep", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index d7ca3aa11794..a95f8d44cf24 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-399-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-400-orange.svg?style=flat-square)](#contributors-)
@@ -592,6 +592,7 @@ This project is licensed under the terms of the MIT license. avivdon
avivdon

🛡️ Aditya Kumawat
Aditya Kumawat

💻 devch37
devch37

💻 + HY-love-sleep
HY-love-sleep

💻 From e8595393d6ff5fb6b49c7ae90f372f5661269272 Mon Sep 17 00:00:00 2001 From: CMD137 <2992456841@qq.com> Date: Tue, 2 Jun 2026 02:11:47 +0800 Subject: [PATCH 048/108] feat: Add Thread-Specific Storage design pattern (#3422) * Add Thread-Specific Storage design pattern * fixed:pom.xml Run 'mvn spotless:apply' to fix these violations. * fix: address Sonar security hotspots for Random usage and e.printStackTrace() * fixed: Run 'mvn spotless:apply'(remove unused import) * fixed: Refactor Thread-Specific Storage pattern implementation to address Sonar issues: remove unnecessary instantiation, add private constructor, use diamond operator, and update tests. * fixed: update uml and README.md * Trigger CI rerun --- pom.xml | 1 + thread-specific-storage/README.md | 227 ++++++++++++++++++ .../etc/ThreadSpecificStorageUML.png | Bin 0 -> 24939 bytes .../etc/thread-specific-storage.urm.puml | 41 ++++ thread-specific-storage/pom.xml | 89 +++++++ .../iluwatar/threadspecificstorage/App.java | 42 ++++ .../threadspecificstorage/RequestHandler.java | 57 +++++ .../threadspecificstorage/UserContext.java | 15 ++ .../UserContextProxy.java | 33 +++ .../threadspecificstorage/AppTest.java | 38 +++ .../RequestHandlerTest.java | 32 +++ .../UserContextProxyTest.java | 70 ++++++ .../UserContextTest.java | 57 +++++ 13 files changed, 702 insertions(+) create mode 100644 thread-specific-storage/README.md create mode 100644 thread-specific-storage/etc/ThreadSpecificStorageUML.png create mode 100644 thread-specific-storage/etc/thread-specific-storage.urm.puml create mode 100644 thread-specific-storage/pom.xml create mode 100644 thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/App.java create mode 100644 thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/RequestHandler.java create mode 100644 thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContext.java create mode 100644 thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContextProxy.java create mode 100644 thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/AppTest.java create mode 100644 thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/RequestHandlerTest.java create mode 100644 thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextProxyTest.java create mode 100644 thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextTest.java diff --git a/pom.xml b/pom.xml index 827b326c0287..3403c4607f37 100644 --- a/pom.xml +++ b/pom.xml @@ -234,6 +234,7 @@ template-method templateview thread-pool-executor + thread-specific-storage throttling tolerant-reader trampoline diff --git a/thread-specific-storage/README.md b/thread-specific-storage/README.md new file mode 100644 index 000000000000..e3109595fd84 --- /dev/null +++ b/thread-specific-storage/README.md @@ -0,0 +1,227 @@ +--- +title: "Thread-Specific Storage Pattern in Java: Isolated Thread-Local Data Management" +shortTitle: Thread-Specific Storage +description: "Learn the Thread-Specific Storage pattern in Java with practical examples, class +diagrams, and implementation details. Understand how to manage thread-local data efficiently, +improving concurrency and avoiding synchronization issues." +category: Concurrency +language: en +tag: + +- Concurrency +- Multithreading +- Thread Safety +- Data Isolation +- Memory Management + +--- + +## Intent of Thread-Specific Storage Design Pattern + +The Thread-Specific Storage pattern ensures that each thread has its own isolated instance of shared data, +preventing concurrency issues by eliminating the need for synchronization. It achieves this by using +ThreadLocal variables to store data that is specific to each thread. + +## Detailed Explanation of Thread-Specific Storage Pattern with Real-World Examples + +### Real-world example + +> Think of a customer service center where each agent has their own notepad to record information +> about the customer they're currently helping. Even if multiple agents are helping customers +> simultaneously, each agent's notes are completely separate from the others'. When an agent finishes +> with one customer and moves to the next, they start with a fresh notepad. This approach eliminates +> the need for agents to coordinate their note-taking, as each agent's notes are private to their +> current customer interaction. + +### In plain words + +> Thread-Specific Storage provides each thread with its own private copy of data, isolating thread +> interactions and avoiding the need for synchronization mechanisms. + +### Wikipedia says + +> Thread-local storage (TLS) is a computer programming method that uses static or global memory +> local to a thread. TLS is a common technique for avoiding race conditions when multiple threads +> need to access the same data. Each thread has its own copy of the data, so there is no need for +> synchronization. + +### Class diagram + +![Thread-Specific Storage diagram](./etc/ThreadSpecificStorageUML.png) + +## Programmatic Example of Thread-Specific Storage Pattern in Java + +Imagine a web application that needs to track the current user's context across different stages of request processing. + +Each request is handled by a separate thread, and we need to maintain user-specific information without +synchronization overhead. + +The Thread-Specific Storage pattern efficiently handles this by providing each thread with its own copy +of the user context data. + +```java +@Slf4j +public class APP { + public static void main(String[] args) { + // Simulate concurrent requests from multiple users + for (int i = 1; i <= 5; i++) { + // Simulate tokens for different users + String token = "token::" + (i % 3 + 1); // 3 distinct users + + new Thread(() -> { + // Simulate request processing flow + RequestHandler handler = new RequestHandler(token); + handler.process(); + }).start(); + + // Slightly stagger request times + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } +} +``` + +Here's how the request handler processes each request: + +```java +@Slf4j +public class RequestHandler { + private final String token; + + public RequestHandler(String token) { + this.token = token; + } + + public void process() { + LOGGER.info("Start handling request with token: {}", token); + + try { + // Step 1: Parse token to get userId + Long userId = parseToken(token); + + // Step 2: Save userId in ThreadLocal storage + UserContextProxy.set(new UserContext(userId)); + + // Simulate delay between stages of request handling + Thread.sleep(200); + + // Step 3: Retrieve userId later in the request flow + Long retrievedId = UserContextProxy.get().getUserId(); + Random random = new Random(); + String accountInfo = retrievedId + "'s account: " + random.nextInt(400); + LOGGER.info(accountInfo); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + // Step 4: Clear ThreadLocal to avoid potential memory leaks + UserContextProxy.clear(); + } + } + + // ... parseToken method implementation +} +``` + +The UserContextProxy acts as a thread-safe accessor to the ThreadLocal storage: + +```java +public class UserContextProxy { + // Underlying TSObjectCollection (ThreadLocalMap) managed by JVM. + // This ThreadLocal acts as the Key for the map. + private static final ThreadLocal userContextHolder = new ThreadLocal<>(); + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private UserContextProxy() {} + + /** Set UserContext for the current thread */ + public static void set(UserContext context) { + userContextHolder.set(context); + } + + /** Get UserContext for the current thread */ + public static UserContext get() { + return userContextHolder.get(); + } + + /** Clear UserContext to prevent potential memory leaks */ + public static void clear() { + userContextHolder.remove(); + } +} +``` + +Here's a sample console output: + +``` +Start handling request with token: token::1 +Start handling request with token: token::2 +Start handling request with token: token::3 +Start handling request with token: token::1 +1's account: 234 +Start handling request with token: token::2 +2's account: 157 +3's account: 89 +1's account: 342 +2's account: 76 +``` + +**Note:** Since this example demonstrates concurrent thread execution, **the actual output may vary between runs**. The order of execution and timing can differ due to thread scheduling, system load, and other factors that affect concurrent processing. However, each thread will correctly maintain its own user context without interference from other threads. + +## When to Use the Thread-Specific Storage Pattern in Java + +* When you need to maintain per-thread state without synchronization overhead +* For applications that process requests in multiple stages and need to share data across those stages +* To avoid concurrency issues when working with non-thread-safe objects like SimpleDateFormat +* When implementing logging or security context that needs to be accessible throughout a request processing +* To maintain thread-specific caches or counters without risk of data corruption + +## Thread-Specific Storage Pattern Java Tutorial + +* [Thread-Specific Storage Pattern Tutorial (Baeldung)](https://www.baeldung.com/java-threadlocal) + +## Real-World Applications of Thread-Specific Storage Pattern in Java + +* Servlet containers use ThreadLocal to maintain the current request and response objects +* Spring Framework uses ThreadLocal for managing transaction contexts and security contexts +* Logging frameworks use ThreadLocal to associate log messages with the current thread's context +* Database connection management where each thread needs its own connection or maintains a connection pool per thread +* User session management in web applications where session data is accessed across multiple layers + +## Benefits and Trade-offs of Thread-Specific Storage Pattern + +### Benefits + +* Eliminates the need for synchronization mechanisms, improving performance +* Provides complete isolation of data between threads, preventing concurrency issues +* Simplifies code by removing the need to pass context objects through method parameters +* Enables safe use of non-thread-safe classes in multi-threaded environments +* Reduces object creation overhead by reusing thread-local instances + +### Trade-offs + +* Can lead to increased memory consumption as each thread maintains its own copy of data +* Requires careful cleanup to prevent memory leaks, especially in long-running applications +* May complicate debugging as data is not visible across threads +* Can cause issues in environments with thread pooling where threads are reused (data from previous tasks may persist) + +## Related Java Design Patterns + +* [Context Object Pattern](https://java-design-patterns.com/patterns/context-object/): Encapsulates + request-specific information into a context object that can be passed between components. +* [Thread Pool Pattern](https://java-design-patterns.com/patterns/thread-pool-executor/): + Maintains a pool of worker threads to execute tasks concurrently, optimizing resource usage. +* [Singleton Pattern](https://java-design-patterns.com/patterns/singleton/): Ensures a class has only + one instance and provides global access to it, similar to how ThreadLocal provides per-thread access. + +## References and Credits + +* [Pattern-Oriented Software Architecture, Volume 2: Patterns for Concurrent and Networked Objects](https://www.amazon.com/Pattern-Oriented-Software-Architecture-Concurrent-Networked/dp/0471606952) +* [Java Documentation for ThreadLocal](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ThreadLocal.html) +* [Java Concurrency in Practice](https://jcip.net/) by Brian Goetz \ No newline at end of file diff --git a/thread-specific-storage/etc/ThreadSpecificStorageUML.png b/thread-specific-storage/etc/ThreadSpecificStorageUML.png new file mode 100644 index 0000000000000000000000000000000000000000..d4957dd1cc2a3a488979328616ec1671a2050675 GIT binary patch literal 24939 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 + + {static} set(context : UserContext) : void + + {static} get() : UserContext + + {static} clear() : void + } + + class RequestHandler { + - token : String + + RequestHandler(token : String) + + process() : void + - parseToken(token : String) : Long + } + + UserContextProxy --> UserContext : manages + RequestHandler --> UserContextProxy : uses static + RequestHandler --> UserContext : creates + APP --> RequestHandler : creates + APP --> Thread : starts + Thread --> RequestHandler : executes + +} +@enduml \ No newline at end of file diff --git a/thread-specific-storage/pom.xml b/thread-specific-storage/pom.xml new file mode 100644 index 000000000000..1af91514369b --- /dev/null +++ b/thread-specific-storage/pom.xml @@ -0,0 +1,89 @@ + + + + + 4.0.0 + + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + thread-specific-storage + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + org.awaitility + awaitility + 4.2.1 + test + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.threadspecificstorage.App + + + + + + + + + diff --git a/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/App.java b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/App.java new file mode 100644 index 000000000000..a84388acfe08 --- /dev/null +++ b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/App.java @@ -0,0 +1,42 @@ +package com.iluwatar.threadspecificstorage; + +import lombok.extern.slf4j.Slf4j; + +/** + * Application entry point demonstrating the Thread-Specific Storage pattern. + * + *

This example simulates concurrent request processing for multiple users. Each request carries + * a user token, and user-specific context is managed transparently using thread-specific storage. + */ +@Slf4j +public class App { + + /** + * Runs the Thread-Specific Storage pattern demonstration. + * + * @param args command-line arguments (not used) + */ + public static void main(String[] args) { + // Simulate concurrent requests from multiple users + for (int i = 1; i <= 5; i++) { + // Simulate tokens for different users + String token = "token::" + (i % 3 + 1); // 3 distinct users + + new Thread( + () -> { + // Simulate request processing flow + RequestHandler handler = new RequestHandler(token); + handler.process(); + }) + .start(); + + // Slightly stagger request times + try { + Thread.sleep(50); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + LOGGER.warn("Sleep interrupted", e); + } + } + } +} diff --git a/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/RequestHandler.java b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/RequestHandler.java new file mode 100644 index 000000000000..d5f2cca2830d --- /dev/null +++ b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/RequestHandler.java @@ -0,0 +1,57 @@ +package com.iluwatar.threadspecificstorage; + +import java.security.SecureRandom; +import lombok.extern.slf4j.Slf4j; + +/** + * Application Thread + * + *

Each instance simulates a request-processing thread that uses the Thread-Specific Object Proxy + * to access Thread-Specific Object. + */ +@Slf4j +public class RequestHandler { + private final String token; + + public RequestHandler(String token) { + this.token = token; + } + + /** + * Simulated business process: 1. Parse userId from token ("Token::userId"). 2. Store userId in + * thread-local storage. 3. Later, retrieve userId and use it for business logic. 4. Finally, + * clear thread-local to prevent memory leak. + */ + public void process() { + LOGGER.info("Start handling request with token: {}", token); + + try { + // Step 1: Parse token to get userId + Long userId = parseToken(token); + + // Step 2: Save userId in ThreadLocal storage + UserContextProxy.set(new UserContext(userId)); + + // Simulate delay between stages of request handling + Thread.sleep(200); + + // Step 3: Retrieve userId later in the request flow + Long retrievedId = UserContextProxy.get().getUserId(); + SecureRandom random = new SecureRandom(); + String accountInfo = retrievedId + "'s account: " + random.nextInt(400); + LOGGER.info(accountInfo); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } finally { + // Step 4: Clear ThreadLocal to avoid potential memory leaks + UserContextProxy.clear(); + } + } + + private Long parseToken(String token) { + // token format: "Token::1234" + String[] parts = token.split("::"); + return (parts.length == 2) ? Long.parseLong(parts[1]) : -1L; + } +} diff --git a/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContext.java b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContext.java new file mode 100644 index 000000000000..51399a1a0c72 --- /dev/null +++ b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContext.java @@ -0,0 +1,15 @@ +package com.iluwatar.threadspecificstorage; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Thread-Specific Object + * + *

Provides a service or data that is only accessible via a particular thread. + */ +@Data +@AllArgsConstructor +public class UserContext { + private Long userId; +} diff --git a/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContextProxy.java b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContextProxy.java new file mode 100644 index 000000000000..468e554b0bf6 --- /dev/null +++ b/thread-specific-storage/src/main/java/com/iluwatar/threadspecificstorage/UserContextProxy.java @@ -0,0 +1,33 @@ +package com.iluwatar.threadspecificstorage; + +/** + * Thread-Specific Object Proxy + * + *

The Thread-Specific Object Proxy acts as an intermediary, enabling application thread to + * access and manipulate thread-specific objects simply and securely. + */ +public class UserContextProxy { + /** + * Underlying TSObjectCollection (ThreadLocalMap) managed by JVM.This ThreadLocal acts as the Key + * for the map.So That there is also no key factory. + */ + private static final ThreadLocal userContextHolder = new ThreadLocal<>(); + + /** Private constructor to prevent instantiation of this utility class. */ + private UserContextProxy() {} + + /** Set UserContext for the current thread. */ + public static void set(UserContext context) { + userContextHolder.set(context); + } + + /** Get UserContext for the current thread. */ + public static UserContext get() { + return userContextHolder.get(); + } + + /** Clear UserContext to prevent potential memory leaks. */ + public static void clear() { + userContextHolder.remove(); + } +} diff --git a/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/AppTest.java b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/AppTest.java new file mode 100644 index 000000000000..775ded85b8ea --- /dev/null +++ b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/AppTest.java @@ -0,0 +1,38 @@ +package com.iluwatar.threadspecificstorage; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import org.junit.jupiter.api.Test; + +/** Tests for APP class */ +class AppTest { + @Test + void testMainMethod() { + // Capture system output + ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + System.setOut(new PrintStream(outContent)); + + // Run the main method + App.main(new String[] {}); + + // Give some time for threads to execute + await() + .atMost(5, SECONDS) + .pollInterval(100, MILLISECONDS) + .until(() -> outContent.toString().contains("Start handling request with token")); + + // Verify output contains expected log messages + String output = outContent.toString(); + assertTrue( + output.contains("Start handling request with token"), + "Should contain request handling start messages"); + + // Restore system output + System.setOut(System.out); + } +} diff --git a/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/RequestHandlerTest.java b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/RequestHandlerTest.java new file mode 100644 index 000000000000..e5f5968e7794 --- /dev/null +++ b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/RequestHandlerTest.java @@ -0,0 +1,32 @@ +package com.iluwatar.threadspecificstorage; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +class RequestHandlerTest { + + @Test + void process_shouldStoreAndClearUserContext() { + // Given - a request handler without proxy parameter + RequestHandler handler = new RequestHandler("token::123"); + + // When - process the request + handler.process(); + + // Then - after processing, ThreadLocal should be cleared + assertNull(UserContextProxy.get(), "ThreadLocal should be cleared after process()"); + } + + @Test + void process_withInvalidToken_shouldSetUserIdToMinusOne() { + // Given - a request handler without proxy parameter + RequestHandler handler = new RequestHandler("invalid-token"); + + // When - process the request + handler.process(); + + // Then - after processing, ThreadLocal should be cleared + assertNull(UserContextProxy.get(), "ThreadLocal should be cleared even for invalid token"); + } +} diff --git a/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextProxyTest.java b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextProxyTest.java new file mode 100644 index 000000000000..fd8cfbd6b7aa --- /dev/null +++ b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextProxyTest.java @@ -0,0 +1,70 @@ +package com.iluwatar.threadspecificstorage; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** Tests for UserContextProxy class */ +class UserContextProxyTest { + + private UserContext userContext; + + @BeforeEach + void setUp() { + userContext = new UserContext(123L); + } + + @AfterEach + void tearDown() { + UserContextProxy.clear(); + } + + @Test + void testSetAndGetContext() { + UserContextProxy.set(userContext); + UserContext retrievedContext = UserContextProxy.get(); + assertNotNull(retrievedContext, "Retrieved context should not be null"); + assertEquals( + userContext.getUserId(), + retrievedContext.getUserId(), + "Retrieved context should have the same userId"); + } + + @Test + void testGetContextWhenNotSet() { + UserContext retrievedContext = UserContextProxy.get(); + assertNull(retrievedContext, "Context should be null when not set"); + } + + @Test + void testClearContext() { + UserContextProxy.set(userContext); + UserContextProxy.clear(); + UserContext retrievedContext = UserContextProxy.get(); + assertNull(retrievedContext, "Context should be null after clearing"); + } + + @Test + void testThreadIsolation() throws InterruptedException { + UserContext context1 = new UserContext(123L); + UserContext context2 = new UserContext(456L); + UserContextProxy.set(context1); + // Create another thread to set different context + Thread thread = + new Thread( + () -> { + UserContextProxy.set(context2); + UserContext threadContext = UserContextProxy.get(); + assertNotNull(threadContext); + assertEquals(456L, threadContext.getUserId()); + }); + thread.start(); + thread.join(); + // Main thread context should remain unchanged + UserContext mainThreadContext = UserContextProxy.get(); + assertNotNull(mainThreadContext); + assertEquals(123L, mainThreadContext.getUserId()); + } +} diff --git a/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextTest.java b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextTest.java new file mode 100644 index 000000000000..3a7864c9e92e --- /dev/null +++ b/thread-specific-storage/src/test/java/com/iluwatar/threadspecificstorage/UserContextTest.java @@ -0,0 +1,57 @@ +package com.iluwatar.threadspecificstorage; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +/** Tests for UserContext class */ +class UserContextTest { + + @Test + void testConstructorAndGetUserId() { + Long userId = 123L; + UserContext context = new UserContext(userId); + + assertEquals( + userId, context.getUserId(), "UserId should match the one provided in constructor"); + } + + @Test + void testSetUserId() { + UserContext context = new UserContext(123L); + Long newUserId = 456L; + + context.setUserId(newUserId); + + assertEquals(newUserId, context.getUserId(), "UserId should be updated"); + } + + @Test + void testToString() { + Long userId = 123L; + UserContext context = new UserContext(userId); + + String expected = "UserContext(userId=" + userId + ")"; + assertEquals(expected, context.toString(), "toString should return expected format"); + } + + @Test + void testEqualsAndHashCode() { + Long userId = 123L; + UserContext context1 = new UserContext(userId); + UserContext context2 = new UserContext(userId); + UserContext context3 = new UserContext(456L); + + assertEquals(context1, context2, "Objects with same userId should be equal"); + assertEquals( + context1.hashCode(), + context2.hashCode(), + "Objects with same userId should have same hashCode"); + + assertNotEquals(context1, context3, "Objects with different userId should not be equal"); + assertNotEquals( + context1.hashCode(), + context3.hashCode(), + "Objects with different userId should have different hashCode"); + } +} From b0bd9e65939617be605c6368c8d8be64f9afbe3f Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:13:49 +0300 Subject: [PATCH 049/108] docs: add CMD137 as a contributor for code (#3497) * 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 571eb0af649b..e8b2bc1a29c1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3647,6 +3647,15 @@ "contributions": [ "code" ] + }, + { + "login": "CMD137", + "name": "CMD137", + "avatar_url": "https://avatars.githubusercontent.com/u/56242956?v=4", + "profile": "http://www.cmd137blog.top/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index a95f8d44cf24..a7e23baa2f63 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-400-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-401-orange.svg?style=flat-square)](#contributors-)
@@ -593,6 +593,7 @@ This project is licensed under the terms of the MIT license. Aditya Kumawat
Aditya Kumawat

💻 devch37
devch37

💻 HY-love-sleep
HY-love-sleep

💻 + CMD137
CMD137

💻 From 2bfd3e190df7f6627866b7d49f279dc77336dd5b Mon Sep 17 00:00:00 2001 From: QuantumRange <49843948+QuantumRange@users.noreply.github.com> Date: Mon, 1 Jun 2026 20:27:43 +0200 Subject: [PATCH 050/108] fix: external spring guide link changed (#3394) --- circuit-breaker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuit-breaker/README.md b/circuit-breaker/README.md index 99c1b7b4d398..b1baf416fc86 100644 --- a/circuit-breaker/README.md +++ b/circuit-breaker/README.md @@ -193,7 +193,7 @@ The Circuit Breaker pattern is applicable: * Cloud-based services to gracefully handle the failure of external services * E-commerce platforms to manage high volumes of transactions and dependency on external APIs * Microservices architectures for maintaining system stability and responsiveness -* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker) +* [Spring Circuit Breaker module](https://spring.io/guides/gs/cloud-circuit-breaker) * [Netflix Hystrix API](https://github.com/Netflix/Hystrix) ## Benefits and Trade-offs of Circuit Breaker Pattern From f8d4dd8506e3610f00c7a983633629cd4ebba695 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Mon, 1 Jun 2026 21:28:22 +0300 Subject: [PATCH 051/108] docs: add QuantumRange as a contributor for doc (#3498) * 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 e8b2bc1a29c1..84d8ad660381 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3656,6 +3656,15 @@ "contributions": [ "code" ] + }, + { + "login": "QuantumRange", + "name": "QuantumRange", + "avatar_url": "https://avatars.githubusercontent.com/u/49843948?v=4", + "profile": "https://github.com/QuantumRange", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index a7e23baa2f63..08588bef531f 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-401-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-402-orange.svg?style=flat-square)](#contributors-)
@@ -594,6 +594,7 @@ This project is licensed under the terms of the MIT license. devch37
devch37

💻 HY-love-sleep
HY-love-sleep

💻 CMD137
CMD137

💻 + QuantumRange
QuantumRange

📖 From a9ce57c4d045120095df61dd5296d51b8f27d471 Mon Sep 17 00:00:00 2001 From: Dhiraj Birajdar <114354331+Dhiraj-birajdar@users.noreply.github.com> Date: Tue, 2 Jun 2026 23:31:17 +0530 Subject: [PATCH 052/108] fix: Fix broken CQRS link in Saga README (#3409) Co-authored-by: Dhiraj-Birajdar --- saga/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/saga/README.md b/saga/README.md index d715f026af67..b559d3daddf3 100644 --- a/saga/README.md +++ b/saga/README.md @@ -193,7 +193,7 @@ Trade-offs: ## Related Java Design Patterns * [Event Sourcing](https://java-design-patterns.com/patterns/event-sourcing/): Used to capture state changes as a sequence of events, which can complement the Saga pattern by providing a history of state changes. -* [Command Query Responsibility Segregation (CQRS)](https://java-design-patterns.com/patterns/cqrs/): Can be used in conjunction with the Saga pattern to separate command and query responsibilities, improving scalability and fault tolerance. +* [Command Query Responsibility Segregation (CQRS)](https://java-design-patterns.com/patterns/command-query-responsibility-segregation/): Can be used in conjunction with the Saga pattern to separate command and query responsibilities, improving scalability and fault tolerance. ## References and Credits From 93668590e531216b2bc5bc631e3d89289145afa3 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 21:02:01 +0300 Subject: [PATCH 053/108] docs: add Dhiraj-birajdar as a contributor for doc (#3499) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 84d8ad660381..00b30de4eb62 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3665,6 +3665,15 @@ "contributions": [ "doc" ] + }, + { + "login": "Dhiraj-birajdar", + "name": "Dhiraj Birajdar", + "avatar_url": "https://avatars.githubusercontent.com/u/114354331?v=4", + "profile": "https://github.com/Dhiraj-birajdar", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 08588bef531f..e96fba482b54 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-402-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-403-orange.svg?style=flat-square)](#contributors-)
@@ -596,6 +596,9 @@ This project is licensed under the terms of the MIT license. CMD137
CMD137

💻 QuantumRange
QuantumRange

📖 + + Dhiraj Birajdar
Dhiraj Birajdar

📖 + From bdc008fb78a31d6df980629e6470374cdba93361 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:15:59 +0300 Subject: [PATCH 054/108] build(deps): bump com.fasterxml.jackson.core:jackson-core (#3502) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.19.0 to 2.21.4. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.19.0...jackson-core-2.21.4) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.21.4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dynamic-proxy/pom.xml | 2 +- event-sourcing/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dynamic-proxy/pom.xml b/dynamic-proxy/pom.xml index decbb24fd02d..7facbcf6d095 100644 --- a/dynamic-proxy/pom.xml +++ b/dynamic-proxy/pom.xml @@ -46,7 +46,7 @@ com.fasterxml.jackson.core jackson-core - 2.19.0 + 2.21.4 com.fasterxml.jackson.core diff --git a/event-sourcing/pom.xml b/event-sourcing/pom.xml index 5660054d8195..27a72e5f5f65 100644 --- a/event-sourcing/pom.xml +++ b/event-sourcing/pom.xml @@ -50,7 +50,7 @@ com.fasterxml.jackson.core jackson-core - 2.19.0 + 2.21.4 com.fasterxml.jackson.core From cd4753a660423e885692e3dcc1460cc5ea2cf8ec Mon Sep 17 00:00:00 2001 From: Stefan Siebers Date: Wed, 3 Jun 2026 19:20:05 +0200 Subject: [PATCH 055/108] docs: Improve existing German READMEs and add new ones (#3444) * docs: reformulate text, add links to further languages and paragraph about the book in central README.md (#2275) * docs: shorten text for link to payhip (#2275) * docs: reformulate german translation for Abstract Document (#2275) * Create folder for Abstract Factory * Create README.md for Abstract Document * Translate README.md for Abstract Document to German * correct typo * docs: add class diagrams for all patterns (#2275) * docs: add missing words in abstract-factory.README.md (#2275) * docs: Create German README.md for Active Object #2275 first text part * docs: finish German translation of README.md for Active Object * docs: translate actor-model into German #2295 * docs: add German translation for Acyclic Visitor #2295 * correct typo * docs: Translate Singleton into German #2295 * docs: Translate Prototype into German #2295 * Delete localization/de/Abstract Factory * insert line break * correct typos in actor-model * realignment of java code block * docs: translate Adapter Pattern into German #2295 * Update README.md change 'lizenz' to 'Lizenz' in badge * Update README.md translate 'benefits' and 'trade-offs' * remove additional bullet point after line break * correct indentation * docs: translate Dependency Injection into German #2295 * docs: translate Bridge into German #2295 * correct typos * docs: Translate Builder into German * delete english text * little changes in formulation * Update README.md change link to image * docs: remove spanish files (#2275) * docs: remove non-translated patterns (#2275) * Create README.md docs: Translate Step Builder into German #2275 * Create README.md docs: Translate Fluent Interface into German #2275 * eager is eifrig, not gierig * Translate Chain of Responsibility into German #2275 --- localization/de/README.md | 33 +- localization/de/abstract-document/README.md | 183 +++++++----- .../etc/abstract-document.png | Bin 96228 -> 0 bytes localization/de/abstract-factory/README.md | 225 ++++++++++++++ localization/de/active-object/README.md | 232 ++++++++++++++ localization/de/actor-model/README.md | 203 +++++++++++++ localization/de/acyclic-visitor/README.md | 192 ++++++++++++ localization/de/adapter/README.md | 168 +++++++++++ localization/de/bridge/README.md | 282 ++++++++++++++++++ localization/de/builder/README.md | 221 ++++++++++++++ .../de/chain-of-responsibility/README.md | 221 ++++++++++++++ .../de/dependency-injection/README.md | 169 +++++++++++ localization/de/fluent-interface/README.md | 216 ++++++++++++++ localization/de/singleton/README.md | 114 +++++++ localization/de/step-builder/README.md | 218 ++++++++++++++ 15 files changed, 2588 insertions(+), 89 deletions(-) delete mode 100644 localization/de/abstract-document/etc/abstract-document.png create mode 100644 localization/de/abstract-factory/README.md create mode 100644 localization/de/active-object/README.md create mode 100644 localization/de/actor-model/README.md create mode 100644 localization/de/acyclic-visitor/README.md create mode 100644 localization/de/adapter/README.md create mode 100644 localization/de/bridge/README.md create mode 100644 localization/de/builder/README.md create mode 100644 localization/de/chain-of-responsibility/README.md create mode 100644 localization/de/dependency-injection/README.md create mode 100644 localization/de/fluent-interface/README.md create mode 100644 localization/de/singleton/README.md create mode 100644 localization/de/step-builder/README.md diff --git a/localization/de/README.md b/localization/de/README.md index b727e6ba47e1..4442d9682921 100644 --- a/localization/de/README.md +++ b/localization/de/README.md @@ -1,7 +1,7 @@ -# In Java implementierte Entwurfsmuster +# Design Patterns (Entwurfsmuster) in Java ![Java CI](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) -[![Lizenz MIT](https://img.shields.io/badge/lizenz-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) +[![Lizenz MIT](https://img.shields.io/badge/Lizenz-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) [![Codezeilen](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Abdeckung](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Chat beitreten unter 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) @@ -11,38 +11,43 @@
-In anderen Sprachen lesen: [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md) - +In anderen Sprachen lesen: [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md), [**vi**](localization/vi/README.md), [**bn**](localization/bn/README.md), [**np**](localization/ne/README.md), [**it**](localization/it/README.md), [**da**](localization/da/README.md)
# Einführung -Entwurfsmuster sind bewährte Lösungen, die Entwickler nutzen können, um häufige Probleme beim Entwurf von Anwendungen oder Systemen zu lösen. +Design Patterns (auch Entwurfsmuster genannt) sind allgemein anerkannte Vorgehensweisen für den Entwurf von Anwendungen und Systemen, mit denen sich regelmäßig auftauchende Probleme lösen lassen. -Sie helfen dabei, den Entwicklungsprozess zu beschleunigen, indem sie erprobte und zuverlässige Ansätze bereitstellen. +Mit ihnen lässt sich der Entwicklungsprozess beschleunigen, indem erprobte und bewährte Vorlagen zur Verfügung gestellt werden. -Die Wiederverwendung von Entwurfsmustern verhindert subtile Fehler, die zu größeren Problemen führen können, und verbessert die Lesbarkeit des Codes – besonders für Entwickler und Architekten, die mit diesen Mustern vertraut sind. +Die Nutzung von Entwurfsmustern beugt versteckten Fehlern vor, die zu größeren Problemen führen können. Auch verbessert sich die Lesbarkeit des Codes, besonders für Entwickler und Architekten, die mit diesen Mustern vertraut sind. # Erste Schritte -Diese Seite stellt Java-Entwurfsmuster vor. Die Lösungen wurden von erfahrenen Entwicklern und Architekten aus der Open-Source-Community erstellt. Die Muster können entweder durch ihre Beschreibungen oder durch den Quellcode erkundet werden. Die Codebeispiele sind gut kommentiert und eignen sich als Tutorials, um die Muster zu verstehen und umzusetzen. Wir verwenden dabei bekannte und bewährte Open-Source-Java-Technologien. +Diese Seite präsentiert Entwurfsmuster für Java. Die Lösungen wurden von erfahrenen Programmierern und Architekten aus der Open-Source-Community entwickelt. Die Muster können entweder anhand ihrer Beschreibungen oder durch den Quellcode erkundet werden. Die Codebeispiele sind gut kommentiert und eignen sich als Tutorials, wie das jeweilige Muster zu implementieren ist. Wir verwenden dabei bekannte und bewährte Open-Source-Java-Technologien. -Bevor Sie sich mit den Entwurfsmustern beschäftigen, sollten Sie sich mit den grundlegenden [Software-Entwurfsprinzipien](https://java-design-patterns.com/principles/) vertraut machen. +Ehe Sie tiefer in den Stoff eindringen, sollten Sie sich mit den grundlegenden [Software-Entwurfsprinzipien](https://java-design-patterns.com/principles/) vertraut machen. -Entwürfe sollten immer so einfach wie möglich gehalten werden. Beginnen Sie mit den Prinzipien KISS (Keep It Simple, Stupid), YAGNI (You Aren’t Gonna Need It) und "Do The Simplest Thing That Could Possibly Work". Komplexe Muster sollten nur dann verwendet werden, wenn sie wirklich notwendig sind. +Entwürfe sollten immer so einfach wie möglich gehalten werden. Beginnen Sie mit den Prinzipien KISS (Keep It Simple, Stupid), YAGNI (You Aren’t Gonna Need It) und "Do The Simplest Thing That Could Possibly Work". Komplexere Strukturen und Muster sollten erst dann verwendet werden, wenn sie wirklich notwendig sind. Sobald Sie mit diesen Konzepten vertraut sind, können Sie sich die [verfügbaren Entwurfsmuster](https://java-design-patterns.com/patterns/) ansehen. Dafür gibt es verschiedene Ansätze: - Suchen Sie nach einem bestimmten Muster anhand des Namens. Fehlt ein Muster? Melden Sie es gerne [hier](https://github.com/iluwatar/java-design-patterns/issues). - Nutzen Sie Tags wie `Performance`, `Gang of Four` oder `Data access`. -- Durchsuchen Sie die Muster nach Kategorien wie `Creational`, `Behavioral` und anderen. +- Verwenden Sie Kategorien von Patterns wie `Creational`, `Behavioral` usw. Wir hoffen, dass Sie die hier vorgestellten Lösungen für Ihre Projekte nützlich finden und genauso viel Spaß beim Lernen haben, wie wir bei der Entwicklung hatten. -# Mitwirken +# Mitarbeit + +Wenn Sie zum Projekt beitragen möchten, finden Sie alle notwendigen Informationen in unserem [Entwickler-Wiki](https://github.com/iluwatar/java-design-patterns/wiki). Bei Fragen helfen wir Ihnen gerne im [Gitter-Chat](https://gitter.im/iluwatar/java-design-patterns) weiter. + +# Das Buch + +Die Design Patterns sind jetzt als eBook verfügbar. Hier ist es erhältlich: https://payhip.com/b/bNQFX -Wenn Sie zum Projekt beitragen möchten, finden Sie alle notwendigen Informationen in unserem [Entwickler-Wiki](https://github.com/iluwatar/java-design-patterns/wiki). Bei Fragen helfen wir Ihnen gerne im [Gitter-Chatraum](https://gitter.im/iluwatar/java-design-patterns) weiter. +Mitwirkende am Projekt können das Buch kostenlos erhalten. Kontaktieren Sie mich via [Gitter-Chat](https://gitter.im/iluwatar/java-design-patterns) or E-Mail (iluwatar (at) gmail (dot) com ). Die Nachricht sollte enthalten: Ihre Mailadresse, den Usernamen bei Github, and einen Link zu einem akzeptierten Pull Request. # Lizenz -Dieses Projekt steht unter der MIT-Lizenz. \ No newline at end of file +Dieses Projekt unterliegt den Regelungen der MIT-Lizenz. diff --git a/localization/de/abstract-document/README.md b/localization/de/abstract-document/README.md index 13f8d26fbbbf..ca381a3a8c40 100644 --- a/localization/de/abstract-document/README.md +++ b/localization/de/abstract-document/README.md @@ -1,43 +1,48 @@ --- -title: "Abstract Document Pattern in Java: Vereinfachung der Datenverwaltung mit Flexibilität" shortTitle: Abstract Document -description: "Erkunden Sie das Abstract Document Design Pattern in Java. Lernen Sie seine Absicht, Erklärung, Anwendbarkeit, Vorteile kennen und sehen Sie reale Beispiele zur Implementierung flexibler und dynamischer Datenstrukturen." -category: Strukturell +category: Structural language: de tag: - - Abstraktion - - Entkopplung - - Dynamische Typisierung - - Kapselung - - Erweiterbarkeit - - Polymorphismus + - Abstraction + - Decoupling + - Dynamic typing + - Encapsulation + - Extensibility + - Polymorphism --- -## Absicht des Abstract Document Design Patterns +## Zweck -Das Abstract Document Design Pattern in Java ist ein wichtiges strukturelles Design Pattern, das eine konsistente Möglichkeit bietet, hierarchische und baumartige Datenstrukturen zu handhaben, indem es eine gemeinsame Schnittstelle für verschiedene Dokumenttypen definiert. Es trennt die Kernstruktur des Dokuments von spezifischen Datenformaten und ermöglicht dynamische Aktualisierungen und vereinfachte Wartung. +Abstract Document ist ein wichtiges Struktur-Pattern, das ein einheitliches Handling von hierarchischen baumartige Datenstrukturen ermöglicht, indem es eine gemeinsame Schnittstelle für verschiedene Dokumenttypen definiert. Es trennt die Kernstruktur des Dokuments von spezifischen Datenformaten und ermöglicht so dynamische Aktualisierungen und einfachere Wartung. -## Detaillierte Erklärung des Abstract Document Patterns mit realen Beispielen +## Detaillierte Erklärung -Das Abstract Document Design Pattern in Java ermöglicht die dynamische Handhabung nicht-statischer Eigenschaften. Dieses Pattern verwendet das Konzept der Traits, um Typsicherheit zu gewährleisten und Eigenschaften verschiedener Klassen in eine Menge von Schnittstellen zu trennen. +Abstract Document erlaubt die dynamische Behandlung nicht-statischer Eigenschaften. Dieses Pattern verwendet das Konzept der Traits, um Typsicherheit zu gewährleisten und Eigenschaften verschiedener Klassen in verschiedene Schnittstellen abzuspalten. Reales Beispiel -> Betrachten Sie ein Bibliothekssystem, das das Abstract Document Design Pattern in Java implementiert, wo Bücher verschiedene Formate und Attribute haben können: physische Bücher, eBooks und Hörbücher. Jedes Format hat einzigartige Eigenschaften, wie Seitenzahl für physische Bücher, Dateigröße für eBooks und Dauer für Hörbücher. Das Abstract Document Design Pattern ermöglicht es dem Bibliothekssystem, diese verschiedenen Formate flexibel zu verwalten. Durch die Verwendung dieses Patterns kann das System Eigenschaften dynamisch speichern und abrufen, ohne dass eine starre Struktur für jeden Buchtyp erforderlich ist, was es einfacher macht, neue Formate oder Attribute in der Zukunft hinzuzufügen, ohne dass wesentliche Änderungen am Codebase erforderlich sind. +> Denken Sie an ein Bibliothekssystem, wo Bücher verschiedene Formate und Attribute haben können: physische Bücher, eBooks und Hörbücher. Jedes Format hat spezielle Eigenschaften, wie die Seitenzahl bei physischen Büchern, die Dateigröße bei eBooks oder die Spielzeit bei Hörbüchern. Das Abstract Document Design Pattern ermöglicht es dem Bibliothekssystem, diese verschiedenen Formate flexibel zu verwalten. Durch die Verwendung dieses Patterns kann das System Eigenschaften dynamisch speichern und abrufen, ohne dass eine starre Struktur für jeden Buchtyp erforderlich ist. Damit wird es einfacher, in der Zukunft neue Formate oder Attribute hinzuzufügen, ohne erhebliche Änderungen am Code vornehmen zu müssen. In einfachen Worten -> Das Abstract Document Pattern ermöglicht das Anhängen von Eigenschaften an Objekte, ohne dass diese davon wissen. +> Abstract Document erlaubt das Anhängen von Eigenschaften an Objekte, ohne dass diese davon wissen. Wikipedia sagt -> Ein objektorientiertes strukturelles Design Pattern zur Organisation von Objekten in schwach typisierten Schlüssel-Wert-Speichern und zur Bereitstellung der Daten über typisierte Ansichten. Der Zweck des Patterns besteht darin, einen hohen Grad an Flexibilität zwischen Komponenten in einer stark typisierten Sprache zu erreichen, in der neue Eigenschaften zur Objektstruktur dynamisch hinzugefügt werden können, ohne die Unterstützung der Typsicherheit zu verlieren. Das Pattern verwendet Traits, um verschiedene Eigenschaften einer Klasse in verschiedene Schnittstellen zu trennen. +> Ein objektorientiertes strukturelles Design Pattern zur Organisation von Objekten in schwach typisierten Schlüssel-Wert-Speichern mit Darstellung der Daten über typisierte Ansichten. Der Zweck des Patterns besteht darin, einen hohen Grad an Flexibilität zwischen Komponenten in einer stark typisierten Sprache zu erreichen, in der neue Eigenschaften zur Objektstruktur dynamisch hinzugefügt werden können, ohne die Unterstützung der Typsicherheit zu verlieren. Das Pattern verwendet Traits, um verschiedene Klasseneigenschaften in verschiedene Schnittstellen abzutrennen. -## Programmatisches Beispiel des Abstract Document Patterns in Java +## Klassendiagramm -Betrachten Sie ein Auto, das aus mehreren Teilen besteht. Wir wissen jedoch nicht, ob das spezifische Auto wirklich alle Teile hat oder nur einige davon. Unsere Autos sind dynamisch und extrem flexibel. +![Abstract Document](/abstract-document/etc/abstract-document.png "Abstract Document Traits und Domain") -Lassen Sie uns zunächst die Basisklassen `Document` und `AbstractDocument` definieren. Sie sorgen im Wesentlichen dafür, dass das Objekt eine Eigenschaftsmap und eine beliebige Anzahl von Kindobjekten enthält. +## Beispielprogramm in Java + +Betrachten Sie ein Auto, das aus mehreren Teilen besteht. Wir wissen jedoch nicht, +ob das spezifische Auto wirklich alle Teile hat oder nur einige davon. +Unsere Autos sind dynamisch und extrem flexibel. + +Zunächst definieren wir die Basisklassen `Document` und `AbstractDocument`. +Sie sorgen im Wesentlichen dafür, dass jedes Objekt eine Map von Eigenschaften und eine beliebige Anzahl von Kindobjekten enthält. ```java public interface Document { @@ -80,10 +85,11 @@ public abstract class AbstractDocument implements Document { .map(constructor); } - // Andere Eigenschaften und Methoden... + // Weitere Eigenschaften und Methoden... } ``` -Als nächstes definieren wir ein Enum Property und eine Menge von Schnittstellen für Typ, Preis, Modell und Teile. Dies ermöglicht es uns, eine statisch aussehende Schnittstelle für unsere Car-Klasse zu erstellen. + +Als nächstes definieren wir ein Enum `Property` und je eine Schnittstelle für Typ, Preis, Modell und Teile. So können wir eine statisch aussehende Schnittstelle für unsere Klasse `Car` erstellen. ```java public enum Property { @@ -120,33 +126,43 @@ public interface HasParts extends Document { } ``` -Jetzt sind wir bereit, das `Car` einzuführen. +Nun können wir das `Car` einführen. ```java - public static void main(String[] args) { - LOGGER.info("Konstruktion von Teilen und Auto"); - - var wheelProperties = Map.of( - Property.TYPE.toString(), "wheel", - Property.MODEL.toString(), "15C", - Property.PRICE.toString(), 100L); - - var doorProperties = Map.of( - Property.TYPE.toString(), "door", - Property.MODEL.toString(), "Lambo", - Property.PRICE.toString(), 300L); - - var carProperties = Map.of( - Property.MODEL.toString(), "300SL", - Property.PRICE.toString(), 10000L, - Property.PARTS.toString(), List.of(wheelProperties, doorProperties)); - - var car = new Car(carProperties); - - LOGGER.info("Hier ist unser Auto:"); - LOGGER.info("-> Modell: {}", car.getModel().orElseThrow()); - LOGGER.info("-> Preis: {}", car.getPrice().orElseThrow()); - LOGGER.info("-> Teile: "); +public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts { + + public Car(Map properties) { + super(properties); + } +} +``` +Und schließlich konstruieren und verwenden wir ein solches `Car`. + +```java +public static void main(String[] args) { + LOGGER.info("Constructing parts and car"); + +var wheelProperties = Map.of( + Property.TYPE.toString(), "wheel", + Property.MODEL.toString(), "15C", + Property.PRICE.toString(), 100L); + +var doorProperties = Map.of( + Property.TYPE.toString(), "door", + Property.MODEL.toString(), "Lambo", + Property.PRICE.toString(), 300L); + +var carProperties = Map.of( + Property.MODEL.toString(), "300SL", + Property.PRICE.toString(), 10000L, + Property.PARTS.toString(), List.of(wheelProperties, doorProperties)); + +var car = new Car(carProperties); + + LOGGER.info("Here is our car:"); + LOGGER.info("-> model: {}", car.getModel().orElseThrow()); + LOGGER.info("-> price: {}", car.getPrice().orElseThrow()); + LOGGER.info("-> parts: "); car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", p.getType().orElse(null), p.getModel().orElse(null), @@ -154,50 +170,67 @@ Jetzt sind wir bereit, das `Car` einzuführen. ); } ``` -Die Programmausgabe: +Programmausgabe: ``` -07:21:57.391 [main] INFO com.iluwatar.abstractdocument.App -- Konstruktion von Teilen und Auto -07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- Hier ist unser Auto: -07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- -> Modell: 300SL -07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> Preis: 10000 -07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> Teile: -07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- Rad/15C/100 -07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- Tür/Lambo/300 +07:21:57.391 [main] INFO com.iluwatar.abstractdocument.App -- Constructing parts and car +07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- Here is our car: +07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- -> model: 300SL +07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> price: 10000 +07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> parts: +07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- wheel/15C/100 +07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- door/Lambo/300 ``` -## Abstract Document Pattern Klassendiagramm - -![Abstract Document](./etc/abstract-document.png "Abstract Document Traits und Domain") -## Wann sollte das Abstract Document Pattern in Java verwendet werden? +## Verwendung -Das Abstract Document Design Pattern ist besonders vorteilhaft in Szenarien, die eine Verwaltung unterschiedlicher Dokumenttypen in Java erfordern, die einige gemeinsame Attribute oder Verhaltensweisen teilen, aber auch einzigartige Attribute oder Verhaltensweisen haben, die spezifisch für ihren Typ sind. Hier sind einige Szenarien, in denen das Abstract Document Design Pattern anwendbar ist: +Abstract Document ist besonders vorteilhaft in Szenarien, die eine Verwaltung unterschiedlicher +Dokumenttypen erfordern, die zwar einige gemeinsame Attribute oder Verhaltensweisen teilen, +aber auch typspezifische Eigenschaften haben. Hier sind einige Beispiele: * **Content-Management-Systeme (CMS)**: In einem CMS könnten verschiedene Arten von Inhalten wie Artikel, Bilder, Videos usw. vorkommen. Jede Inhaltsart könnte gemeinsame Attribute wie Erstellungsdatum, Autor und Tags haben, aber auch spezifische Attribute wie Bildabmessungen für Bilder oder Videodauer für Videos. -* **Dateisysteme**: Wenn Sie ein Dateisystem entwerfen, in dem unterschiedliche Dateitypen verwaltet werden müssen, wie Dokumente, Bilder, Audiodateien und Verzeichnisse, kann das Abstract Document Pattern helfen, eine konsistente Möglichkeit zum Zugriff auf Attribute wie Dateigröße, Erstellungsdatum usw. zu bieten, während spezifische Attribute wie Bildauflösung oder Audiodauer berücksichtigt werden. +* **Dateisysteme**: Wenn Sie ein Dateisystem entwerfen, in dem unterschiedliche Dateitypen verwaltet werden müssen, wie Dokumente, Bilder, Audiodateien und Verzeichnisse, kann das Pattern helfen, einen einheitlichen Zugriff auf Attribute wie Dateigröße, Erstellungsdatum usw. zu bieten, aber zugleich spezifische Attribute wie Bildauflösung oder Audiodauer zu berücksichtigen. -* **E-Commerce-Systeme**: Eine E-Commerce-Plattform könnte verschiedene Produkttypen haben, wie physische Produkte, digitale Downloads und Abonnements. Jeder Typ könnte gemeinsame Attribute wie Name, Preis und Beschreibung haben, aber auch einzigartige Attribute wie Versandgewicht für physische Produkte oder Download-Link für digitale Produkte. +* **E-Commerce-Systeme**: Eine E-Commerce-Plattform kann verschiedene Produkttypen haben, +wie physische Produkte, digitale Downloads und Abonnements. +Alle Typen haben gemeinsame Attribute wie Name, Preis und Beschreibung, +aber auch einzigartige Attribute wie Versandgewicht für physische Produkte +oder Download-Link für digitale Produkte. -* **Medizinische Aufzeichnungssysteme**: Im Gesundheitswesen könnten Patientenakten verschiedene Datentypen enthalten, wie demografische Daten, medizinische Vorgeschichte, Testergebnisse und Rezepte. Das Abstract Document Pattern kann helfen, gemeinsame Attribute wie Patienten-ID und Geburtsdatum zu verwalten, während spezialisierte Attribute wie Testergebnisse oder verschriebene Medikamente berücksichtigt werden. +* **Medizindatensysteme**: Im Gesundheitswesen enthalten Patientenakten verschiedene +Datentypen wie demografische Daten, medizinische Vorgeschichte, Testergebnisse und Rezepte. +Das Abstract Document Pattern kann helfen, gemeinsame Attribute wie Patienten-ID und Geburtsdatum zu +verwalten und zusätzlich spezielle Attribute wie Testergebnisse oder verschriebene Medikamente zu berücksichtigt werden. -* **Konfigurationsmanagement**: Bei der Verwaltung von Konfigurationseinstellungen für Softwareanwendungen gibt es möglicherweise verschiedene Arten von Konfigurationselementen, jedes mit einer eigenen Reihe von Attributen. Das Abstract Document Pattern kann verwendet werden, um diese Konfigurationselemente zu verwalten, während eine konsistente Möglichkeit zum Zugriff auf und Bearbeiten der Attribute sichergestellt wird. +* **Konfigurationsmanagement**: Bei der Verwaltung von Konfigurationseinstellungen für +Software gibt es verschiedene Arten von Konfigurationselementen, jedes mit einer eigenen Reihe +von Attributen. Mit dem Abstract Document Pattern können diese Konfigurationselemente +konsistent verwaltet werden. -* **Bildungsplattformen**: Bildungssysteme könnten verschiedene Arten von Lernmaterialien wie textbasierte Inhalte, Videos, Quizze und Aufgaben haben. Gemeinsame Attribute wie Titel, Autor und Veröffentlichungsdatum können geteilt werden, während spezifische Attribute wie Videodauer oder Aufgabenfälligkeit für jeden Typ einzigartig sind. +* **Bildungsplattformen**: Bildungssysteme nutzen verschiedene Arten von Lernmaterialien wie textbasierte Inhalte, +Videos, Quiz und Übungsaufgaben. Gemeinsame Attribute können Titel, Autor und Veröffentlichungsdatum sein, +während spezifische Attribute wie Videodauer oder Aufgabenfälligkeit typabhängig sind. -* **Projektmanagement-Tools**: In Projektmanagement-Anwendungen könnten unterschiedliche Aufgabenarten wie To-Do-Items, Meilensteine und Probleme vorliegen. Das Abstract Document Pattern könnte verwendet werden, um allgemeine Attribute wie Aufgabenname und Zuweisung zu handhaben, während spezifische Attribute wie Meilensteindaten oder Problemprioritäten zugelassen werden. +* **Projektmanagement-Tools**: In Projektmanagement-Anwendungen können unterschiedliche Aufgabenarten +wie To-Dos, Meilensteine und Probleme vorliegen. Das Abstract Document Pattern kann verwendet werden, um allgemeine +Attribute wie Aufgabenname und Zuständigkeit zu handhaben, während spezifische Attribute wie Meilensteindaten oder +Aufgabenprioritäten zugelassen sind. -* **Dokumente haben vielfältige und sich entwickelnde Attributstrukturen.** +* **Dokumente haben vielfältige und sich verändernde Attributstrukturen.** -* **Dynamisches Hinzufügen neuer Eigenschaften ist eine häufige Anforderung.** +* **Häufig ist es erforderlich, neue Eigenschaften dynamisch hinzuzufügen.** -* **Entkopplung des Datenzugriffs von spezifischen Formaten ist entscheidend.** +* **Entscheidend ist die Entkopplung des Datenzugriffs von spezifischen Formaten.** -* **Wartbarkeit und Flexibilität sind entscheidend für die Codebasis.** +* **Wartbarkeit und Flexibilität sind wesentlich für die Codebasis.** -Die Hauptidee hinter dem Abstract Document Design Pattern ist es, eine flexible und erweiterbare Möglichkeit zur Verwaltung unterschiedlicher Dokumenttypen oder Entitäten mit gemeinsamen und spezifischen Attributen bereitzustellen. Durch die Definition einer gemeinsamen Schnittstelle und deren Implementierung über verschiedene Dokumenttypen hinweg können Sie einen besser organisierten und konsistenteren Ansatz zur Handhabung komplexer Datenstrukturen erreichen. +Die Kernidee des Abstract Document Pattern ist es, eine flexible und erweiterbare Möglichkeit zur Verwaltung +unterschiedlicher Dokumenttypen oder Entitäten mit gemeinsamen und spezifischen Attributen bereitzustellen. +Durch die Definition einer gemeinsamen Schnittstelle und deren Implementierung über verschiedene Dokumenttypen +hinweg können Sie komplexe Datenstrukturen besser organisiert und einheitlich verarbeiten. -## Vorteile und Abwägungen des Abstract Document Patterns +## Vor- und Nachteile **Vorteile:** @@ -206,12 +239,12 @@ Die Hauptidee hinter dem Abstract Document Design Pattern ist es, eine flexible * **Wartbarkeit**: Fördert sauberen und anpassungsfähigen Code durch Trennung der Verantwortlichkeiten. * **Wiederverwendbarkeit**: Typspezifische Ansichten ermöglichen eine Wiederverwendung des Codes zum Zugriff auf bestimmte Attributtypen. -**Abwägungen:** +**Nachteile:** -* **Komplexität**: Erfordert die Definition von Schnittstellen und Ansichten, was zu zusätzlichem Implementierungsaufwand führt. -* **Leistung**: Kann im Vergleich zum direkten Datenzugriff zu leichtem Leistungsaufwand führen. +* **Komplexität**: Die Definition von Schnittstellen und spezifischen Ansichten erfordert zusätzlichen Implementierungsaufwand. +* **Performance**: Leicht verringerte Performance im Vergleich zum direkten Datenzugriff möglich. -## Quellen und Danksagungen +## Quellen * [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) * [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) diff --git a/localization/de/abstract-document/etc/abstract-document.png b/localization/de/abstract-document/etc/abstract-document.png deleted file mode 100644 index 6bc0b29a4e77680d8eda277c93b97277bbe7193b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96228 zcmcG$XIPY5vn>i{K}4ky1pyIJ5CJ7M8I>qGNe)WRIY?F!5fG4^a}vop2T>5o8G!~Q z=NuavIMuFipRM2C=k9Z#=ic=P9~Zto-#M#BjWMcbd&@|P5a5yG;o#s9JQWp`!@)UC zf`fC??A!_X8&9d>032M0%%_5n6<)?Hjhs~`+C4tIR?;7DhmWi4a}%%GlK!5L8p_!M zA(HJpE_j*vuDO*5E$zK$H=dss(&Jco(p!-|aS9=`v+ur8yel32@kG5V)0!J^yw~hT z+w_V}_)Fx}z8$MM&) zl{%9!l}L+M#)MCQAR7=D5n(oHe=t*d?%)1tl$oBMCnbN){!nps^I1=cuE@w2ML8iM zzK$wVq4$U>__hwiq;j;zM99RWG4UR>ihq4@)H9mfrz*=OGgW#L94v+nIxry@W-#1B z&M)sXv#{LPI!fQ)HnDo@T>o~|i?GttCXOS2=u2XH{a}i(cvoQHS>X?JJbKMIcH3fh zi&3cZNg;>r#esMI&oaXvOGrEyZDOaV4{i=^k>|G!Ua58+HkoQ-jO9kMux0D($nPGk z*0Mb8N*AJ2A8GI%jz*UDb_Ghr{Pgmj-oQ_3OEFSCXU1X1xBJNR-&d`==X9{cdRmEr zflaJ7fC7E*`joG9mn{iRUo?`}D5~4~yT9bzXtgtm?PC9%=tB475^e{sdohv~We7>D zT`$TStpeSpXk@x!wMHd-2YR2^K$T>B^XM?rhq%Sjk+Z8hS=cW2q0WO5vdj6E3K^6! zF^w@iYp+%JxU6+gpYD>3*4Nd4M@NZWGeSK%smka!AK!cHj8r|pnB4MGxm0U!?=L@o zP(Ays@ZOg@(~^CDLY}p)!|&}|Qx+t$IdEUFwDLgR#KcAw(Kq>Bq_y>eO--61UMt4h zaDSw-2T#diFVEN0^C5CLQ|YMGd|9dNQH^1B5xR)T#WkFsQt-UGXcrES_B$O`oL8M6 zlOlWPdlpSi7f7$qn~w6Z(9sG0xT)mg)86i{T+~#f$Z*ok%q}XjrCNd4xnyhIiqGCu zFPzamR=VAcy=D&~xoJr~kh=;e8b%$OM8bGOk}5K+PRX{2Kh@BjJ*NzjZE4ruesO1K zBt_}7lW=jqUHDfPv1GM`k8nGfrzOgA-ZxFJ|3c1v zgO``2=VodfrThKRz{?Bc`Je2U7aUe8TG9K&b6j?xZ32?c@jic4NhQFwGPWABxh>v> zXD|s{>vB6xy6fo3gv)mCIN(jKn`=-vbE@Hdsui8;_(F+kWM7geF><&i{4NHgPR#g# z$A!e~zS%~q_zFe?@2qSV9vx(DtK|p40#Z5F%?djc{&4>3vvg#o<|Dsa!tpB|I&xJu zbAuZf2c(y~lJ(jL3frokhpjynSOenX(sFXn?Dn*kw>5?bAtaxrNfv|HQYiVpYPmJ~6%LX#v1usbbw+6D)8(PQaHe>f#3w38g<~FP?B;sX*^t?~>^ULn zhTPnXuz|$H)75${_nUtd8(;6uHmQ$&pcIj0qZS)I%o_FOn_&FaYh=#svy11ABTpxN z)A}n)8noj1VuR7sx?(AgXohK?_O!ejm-0GEh-53=vgesCP3Qaq2!kko9GsB7MfcZ| zX%S+MR6-|l-e32JxO*btBb+GHjQ`j6;(5wx{`GOPv>_Y6ahT;sGA_>BcL={Hi6JC% z5U~;C*8pW%Qw$M!sa1akk8imfVZi7LDW6WSw-L3!G^Jxqn$cTFrB6YMe?41BEl$ln zeXVLP{81@Qcv+GWX`)pmXHSnnd2`b_y;1hhd&GZzkkwToJuf$}0jBbomfsm_J!I9p zSp7Q7Bt9}eTku*vlFg7SciJ}I-{UYa5P2}>Q#Am{k|ss|{`mAIgTLPU>I+`SOWYOd z9iP!87nf@o4t06UHsgf*?^it9?dE|n^cgKN+wmv&&&lDJ_eqN`)F*gRL*>Zi>MFUw z$xBYB`r&Upd0RZf=F-K4+oFG3c6sDwtaDoZ8%;}Ug?5(q75mEOj*iqhr~|0Bh=@7> zwyq{$l3Hu(OhrlK?i8u%=4rL!&kobg=0~r!YSj18vo#^lGoNL0S!u^Z6)=3jwjBh3 zbdfyDax;dn+TUD`BYi%cNxE|jgQgB=wCn8ad%(hS;hZJ6vwgCsXMRb^KC1j{xmT6D zdz!@x>ZN-;AB8qbnrWh)Fj6}w4NO6v#;;;S*?#Sicy+* z&k>U0j2b>qm?UL1tL@F0kZK)q3`Qx&&$iPf+l-Q24;on`Vs1R?Ideu8#dDUBF*RB~ z?Lxx*U1|Sr+ra|84}Nx)_GVH&)6Jn73K=&f!|CLs%=Zs+6N}Vq-58?GQDr58ffpt3 zYw^9Nhz=!|>OrisvEJLA@2Pm=Szv3kI(phx>G;U3T=D^1ws3w7`bgvl;;#t09OlXt z|00(6ox}PKlo1p0t^}IA?CVI%I#ukB-^zSj2UC1f`TNE3{JFye7WMw=cJW;0hk@oL zMm?|6R!26+Z?W#y0lvwVxgPH8YRa)Pgqio}XvCW5XddF%>h3%5Z*fH#4&+=W=nkS| zkT-2_y)Y@qTJB^=I3g5~G(X>S*2<)-U-A3h3L&-sy2sc0dYoS>bx_$Kd@3_&UVVOB z(uU4SnS^k9Hc720FDY>HyV3!=yjw7wv8{X^X(81mDONH#c)6yg#i&B7mYvxo{At(O zi}wSccCnd|S~?UPKMOF|tSXC5b6Aa&?y;GrMUvIbm`|ti`MnkVj;^jFbst8p zqq{5lBK}zk(K_FEewp7A@-6>6oAc}|HSFe`n`#EW$nx$6%#HuxmA~tfWEdsS<{xDR7nwsziSJ8(%?+6MfSHvVP9IbzsJ3bf-05){6%iX1M@glEY ze|xH-h6cgP%xE>ft{f|k?n+L7Hd$v|r32wcp{$R+-C?Bo5IGm?xGzOhs-a}tJ(LdJ zIJHow*uQ0QwaeA9+U1%IYK$UBT(Da~{hRo%rY+gKbDC%q+fBMCZU*&Adpn3E7{ zBj6}eX_aO2J=+U?Df4-Gv8*ErujzJa@rv4_RAkoD%ETW=b8AUX;*4?rs+j+T}8DZ9l%?^?{@*7T!T6~Ev==hD$B%|{S3!%*+bdo)V z285}Pp|Hfb=P-t;`LILqBQyLuJIPxe_{7rwKFku@djWG!&v%rM2X&+|@<*(rW@Qf~(DnyAoEQy4iW>k`7adNomY9)koZl%OV^_?O zd)?^gXIE+#9h-}g>`}^H$x!KeWq!2k&fl%ARm&H-sYN%`pvN=7pY4y1`}ahAIIue2 zrKa@mka_Fpr?}Cr0av?Ieh5?9>(>(@Dp6iVdJ8@2Hs{ZOVfH{cja6}OGqingj7!Cd z&qedQVf@g1B0v6zBJ_Wu1O7j$hi!R4<~rhdds|wJzPyn=ttsl_(wQd7f`_rBq?|3c z@giB-n5GO0vd#y(RKGfIf#Rgi`RhzrvWkjYfRl_xBti0Q&2<&j5gvCSG+s@&@V|ZL zbJQ5?G4U4(vVBd@!eRW?zwkggG z_dk?c#0xkK{_L%G8I0Ac{}F7Wq26dixBoLg6iQGtnv}!LY_Uhs>!Ktd>}17+;^KVyUAgYs46ILPW<;tMUucgV{+2E4 zMj_T^HpF_3tBA-Cv%h$cwA_6x-EQ&BNJVkNJ00y4=;=-IgKZ_HNYADvydx?jqwuo? z3!Noq0!}x>lcslrT6Ly(1yjaptd8@}{g0!Z zty&ECH2%U)e0Aqt#=O#1VIo4x{ff#CjY|8Cl&7xqGoSt0d~^}cEH;x4m)FVWI9GO$T17!)?|k49*cKBGLc-GXF7;RHA>&$1h*hg#8x8h(KDb_GJcUF5?YDqGDrQGh!#Vs2LSv=F+| z&`q_*wqs*chBX#xampb#H1x;8uEE4ayA)s#Xb!yPjyUwwbVKw1cpt;~J#@J>S;Oh) z=<3^>%IL$7!{#aaw8v0|qkOd4^^DxwmzLfy^x0W|Ov2CjE6_>GPMkmiArmEH(!_At z%v@@&fU1-n9nT-HB%c`(cv&pbpDc0jd+Zy}2`F68SNg0>r!OdKo&*6;aNDFgLV}*f- zIu-J7B*AU?cu9hYk#TZ*b;5?JRv7I_D^zMS@Cou83gh_;C|F-`U$z?Z8b=FKp{|F0Xv#zn|-j_xn?WI z#b<{5#gVb>{9io(&`;>G?93gZvJ*@Ue0+2Kvp<^gq$MtdT~8FvSj(y6iSeOe>?yIm zi`fWe5_D1$qUu7m;Mz3|G%Je&G8X84i3#6?U(&W zr*Uw~>wo(^W8><`nQUs6O<$`&*X~PBXeirqi_FcD} z*@}JMy&LNL{EYlT!U$l15oV!}x7b7}JW^%+xn>C?&9ru@IRi8ElhoCM{ESNdHr@F^ zKeBX(rJsW1)(G<%(Ba@DU70a@k~sB;R*ZT;$Hl_(K~az@I1QW=k$@FpBFMM?GiNOl z=d-fb2*}c|U!QMkZ6#^L%(P{kKt6c!#DbgKgs~z$-K(PFNMinQdodXAB#Y3>oZ;~s zv)IzoLQuc+&JN2_10bWfL?;`Ijo3YX<;o&q-%9=vT+3>5wz^ZVAA4|pxG^XsUnmwp z!7x_KFW?cPU=$TS4yj)4RGj4Pb~x1OW8BC5-uwJgcdFx~S7ZcoOZVl|wx(NFP^~~T z9zTwrXX4-V#2+>s|HlinUmhBjijA_SCx4i<8A5lmw~xLr+r)adeJnjUfL!eDn^3qx?!ls^9XL47?v zIj{&utIaYT&DSOxmfND$7Uo3nNG%DdQB~VP<*%q9g*w1W)+T_-#A%sL?T zyejGLd3#k321UtiZBSC>J4s1ZbrkFRd=F<-@EdJ=d%*^u>AlU? zmN35qVC(=6iH{B@8gfxL`E6eA<;bPFSz43YY)q*hCASxKQ@ZWBL6x=`jfr}Y=rEAu z-Y^0h&e%|4XVaz{>b@*>Ayj~r10GkW*!=t)iB0^gA4vI7{&K9@CNr&6xmxilmQr0@ zA`3(#lzgXTN;Ng5iWtR)Ah6RO8-M68c36G$^JgJY2TPmiJJoiq0@3UQhF^`eM=I!g zuSs4Y?R_yXchw}u4sCj*7F0J(f!jSId-8*M`w!qD!T~ABXl#570 zcksw7r&`ihU-HSqidB^O;LF4PjBXYY!6mGAGH0JhXrzjrHh*wiH@dw1vLtwSg#uo+ zwMJD29Va3Y%V3ll$=gKEl$yu(LExx5&v&Qtx${X=htwHWv$mxhI_#GB_s;;=RVaF` zum6tq?`ftf;E*Oh>y#ynm1p(;5K^0UgBsYZvOGAl=#cz zqYJf>MGK1A3s$>wGXMUr<*9S?2K@wUk@i#l{_f4O=G_TfJP5^>Pk!ND|1ejXLUc!UL4r9Vv&gFGh9K9qn_(d z;YK1{C*OJH7uT3yB~>0UbnTqU25Sh>z1RkxjK_BMcx#Pni0E|A^19GtW~A(U8k^>gQwT(lYcuo zcpEwKr5KM`jrK~628sII9Rjfqf!8Hq*CH+(?RW48gx}j1u(m!Yq{TN)!CUd=B zv{t#bc+FvpRpl$hSw#kKwn;@$Q5&;fEDqi;UM>M@q& zaW?#xQ1Z2_|LIl~q2!9b4B_t7^rXc{Y!>VHXjMG*=-#v(^G*9CF=!3(ze3am!j@jG zL;_4+f}Pc|Fn$${G>LhK)uW16VNt3Lgp?<&YmOvXJuM9k&PFBN6tgMy{yJL!!_sf?J#NCj?ulF?hW1OVaud`1U9^X4C4y@u_Ue!eYW-L0MjDcQR`(XhkL zZfBEHLlO%Xj&HSN56i3xM=2;(*U`#Z0kW6JHG~9Gaj3B$Mjy8Nr(F(fU(qYs_k2Td zs-f|NMyj1ZQb_s9uFdRH=pB5bUCqj}9CAjbe?zxb*?iBmp56e+ljB$&EToZR^?C7! zpl)Fh3fNXNU*zlFUXmNAOU*nH-u-rYN0ybAmvFl7^Rqs>8w-mja_6Qt$LG36XbH(k zjk&q}f5{ic#%^P6txiJ|HU8VWWJpomJ{0PGBXB|tDpzxzg_5U?HGnS47;K}WQw!g| zB;Ivrj=6GBZWCQL53K>2U{cc1j58MuMO3(EO`fMcQ&x*6yFTBWW%Ouy8gsClRB9S2 zq!NBrl&s!0o^y7QB-E%Abp8I699OMfNNc7-#@cktY0}=_ta=T480C?_m64L3&T0AF8SK=rfAFxhsRiw2`{QoC@UJ`1m1cXS zSRW(x^naZ+Q%9*pR!&TMbaykhT(BMtDp&`Q=$?dPg5gw)jNDWP+J5@9*-RQCrF~*T zyJW8BVT;FEuawyo#lnL6>F~N(idmm0Zs6Tv+JIIw-V-ND)mxd((k0#5u@4*Mnigsa z)Z);BL_jqR%lutq&`cVVy!lZFsq|4FYnAqkEJx|Nxs#q{I$^vQpJb$@Tyk}7qY-b+ zQDytlBsx3wqZqZfGP1c@`DwVcdVkk~+sU>R!}pP%EV?3B6OA8fDf20b@egQjmM_}y z@jlPvWGjSA@p9H*$#BlU-ZlAnXW2-)qahmEF~t|E@e2=sxLn7Jx?$tZ@+GaY>C-Q7 z;?d0fv2!~N*v?<*+duy5|H{1nA6cA)oGr-h07~~si^lI~Y3`CtMg2sp`nojyCT73TJ4?yChwmw|<06ml74I1&zoqaB@E8Zz`Z~_2=KRR0bR%@MmKkI$W zWlKv@U+T{m5*Gf{%8|M#eNPX^F*(HN zYk$hd7jm}x`q#4GYcoiS2ss8&jQHK5HI@q@xH$Tx2Q(`gy95h!cVJ{BQxv)_S{|*D z`w#bu{BoYiX?Re@<{=+1Z*SkWf!GEVYK3bNbk-sw2PCHAvY#eo|Byg64}~bXOA5?2 zh9XBXy02BVBg?TK9Y?%KSjVi*x#yczz z@svuH8TX{&dKyG2mzv|X*@K;|qoWZ?ppy5zcWvB0B+00n#o(gj;r{K@c0T=_a`AJD zWg5M=vmF4!0M;w*OvY!}CI7n@3qp*Hn9PWdsifc9E%UNSIA1}>@^z+-1$qJXk^s7| zT5?uaY_hZ4h_1ZJpy21z*4K}q-sUvG`*h_g&Ag|KL@cu&4sTe&`u?_js)7IepBgn7 zX_RRH8aMv=pi-l9W*y1PbCu1^n6Z#bt+d@39C16j3fqj1_>P`) zsa6ZG)6me4th`8RpP%<&=IX{m=yA5%!MeA(!aDsQK=5CA%dgs*$bYy8C;(i>N=9{# zsHEJI5-u%p4P8nu5R818?uf}XiuBD=M<3+UL708@s_CX1>MbI5$hGyEVPdfd6W9EV zXRIZgPUA1IeKwGglF&r?IH)Z0{W2@r=^5xDZFm$B_g;ukA~p{%EcB>$Ma~PsWPy*? z-(@LWReScv(vtP)^lHVgCrBe1CkjeRgO$o=1>m#l_NfnA7zO)o4wDcQ+`cucQAOGXAx3+F1G>WjPTvdp#CdPvC_ z{@T#WiSYk3jX(szEJbO4Ml|(ywV~&*9dst3@3S(toA?C`Om0rUz)?W6mw%uc@SrW_ z+Ub%NYK;y?I|B8JdzN&PKg}tHJeUiYM=I+&Wz@8^dZ2h8KVD=|(+_1jCK}078@PSn z^e)oSz~FE)AQeOtSe#yOO()OLg+xV@b#c&0t6tpARKm1E52{Var#+jfxe>bjdmGay zBu$JJ$8!jzij8_M;N$CnEv^9efAamz@=$3ob+6zoo{X<@sgnSZL(+Mj^5J ziSGM)li+uzd=Cy5m~toaiRKIlRl5tuBlBVqw&4u$y)lW(u+E`fLz)_NMkZDNx!@{AH?mAY16120WUgfyi>f-te-A!EWR64Qhc8I;mz{z#o%%#XuH@w2f^r!z1PX!BlwH62dpam9 zFY|-~l-=c0JmO|hRsNaw%cQQ8cPz=>#Fe^107;V%{p<~;xWQd=mY~MneP%eEsnx9= z9VJe}PyqI)q2VWuY}G#S+pArjqZ)HHN93V*6&Xo(n$9t-t=#KwK6uykN8+&J%CSzr1*tKOQ1S8i*#Id-R(i`v4P0YG zE_!;GukVb6g}FG7-)f3+;8osxWQC8}?3nZ{9^1QEn@Vq<89=Ee*>NIu4vLhfv~+Mw zi~?dAMqFxXgf{U>O!?&{BRYrM+oKMcg0{9~lm_DI{A=7?d^O?*I6K5T zbai@jana-*VObS~K)L>7s%(!F@vOc4sQl)8K~>TDW-i z@(d6YFXIl`4+X=Z&Q!gnxp=ae=()5t#lkdP-l;(re!SpRvBO7~ZHG$+Q5Ot4%xx{_ zexw@`1_&WOw}c;i+w+Cz8ji!?z6t=CoN{iKyAIajr3R?|#>Ll){VInt!M^yx$8hn!Jtk#6~d{mhgQ(@p~)? za=-8-dx+-Hpz$ItQ2+1=zjwmZFx~a7F>bj(`*bya`tEMgBa-lS+X0{}>OmpEa;hi8 zMeiL#LrCld;#wJk{BnNuoA}_Kh~T>eZhMzx^0hgcn9?CiW#ytC>R7f95RLF-)((Sc zbc{Z3yZ~oumL@8gKe5zwungvA`to&%@Km9D&`jXAZ|h%?6juM$VLkI#rCixh><~d3 z8eKkGyV~<9P-T08YlF^dy4f2h&a8zpp6(x?qvh_)RAMRhY*|It2>6VtD}|W-r)@-s z>b^>+LMkK=ePU9_t)_63SK?hEF=%xzeTiKd?_m_`F%9`{KDve3TSxlzW9sKeIc?rG zG{ll4b4YgiPvDU-{&WM=3F~*YW|~7QaH~5BA-NdEY16bgaFccgaH!+Q$M{+Hbyl@Y&Tj}PJ<*|#$`Obr#=)&O;76qZ|rfk-k~XV z4ltzI4?)Vp{6tb>i%#9DC9#^6csh1-+exYDxV*$@JY?$%kw-aO_g5n~Pb~hxV5IR- zueyHqzX)b_HFV0Mlazj0>{pRy)Qo)5@115mZ0&CBzH_k87=BDbMaf6Zr~3~@B{p@S zTjD95%~UUEMkVXF-{`KcBtS|!N3Y0je4BO^*!x2`LQ_4?O@9O@-bloJc`qF`kF}g8 z|7B>s9j)0652}D^vLH48Bm}QX|3~bgMt2Oq$ zO`>Hg=nTopGUbNQ+T$o@Ju!ZlIeK!Xy=S87+~@{5XPeoJvuB_gOe@jF96uK()kVT& zJ}duwE2CX};<)T?I#2}Bd#7C4jYn*Vx1gQc`y118U^d3HJ0+zy=R{koVHCC#o7z)X zM?fuN|D)aimmI6)eN|m)-z0Kz!l@Gs3{@c9-26buBx|Hwj=x!+B}4LnuF}vl>S^_>8u}XHsW@11kDn zRYYz5GXHKs9T7uGDMbZ@xrPq-;1KvcLXsnO>zI$e*@~qJr(%GH!3{~JaqB6vX zSe?qYI+&j_0YJyZQHTWw9oVueL3aVV0bR+o4@`_QtUNm654xN{S%K>Ly^~&Et4Wf{ z1RFFrX$Y_XV;5rDT$ULl&7+Dti^HpxMeQ!=J z6ZXT@XmG(gs-5}tTEd{;?v-{|dS!Kr^-ciYemgmnPYu>ndpkE+nCjw_h7tDm53BQ} zcR~pHqnJ~oRE1UsoM;WYlVf7Z4d2Y9M<^sd83fneR_QnM=Z@XAB_VMLyGjfyLCy(O z!k(=Nb2&+zJ@qn-+a!0$iq8pMg%Aft#l7y-izt!6&~(Eb z^N}HGD;NQN`jqO*)6^(70z;)uI#5IzsDU`66bB2n3gm43s*wCq`eRk<<3MM$Cw@u1 zO^xQp&`;&?N@3*m)cDtBm_&G@5_O=-TAlQ17g3syaOo~iE$N@#LG!N>BIP}X<$9t}E?sUX zgo3U(+|!|Jz6;$pR0saFOLZO#0rON^x{l5oI&+D~M zx7?NKKma^G%lzC!Bp5AW;sPFYkTOlH+e{kLEb8&0p`k(=>4OAv2XZ64)*?LUpHowl zi-n>F-le)9i5+1R+lDZlX`bEM8qJk2AzPm-ms%grL}I8aUx??hy;rsRPe@Ml3biO` zvI|!HDF(_blq*MSZ3n0Gcz^c6T(e|n8%q1+ZY3W&8vuPpRk57d^VvMhYxwaID{Dl+ zyV;9BH{pxV?wAE#8|Yx#^n{qweX{AvR65@H^@WOtFhwIU%$}1e^W&Js26;D+rfxa7wRqb30zT)Wy-6yQPX0 zKMziyant3z${&tZ$Z>aHFHvT>Rz=eJI~HS`a^T%V0hD)JVXX}fK_unomh1lb304-g zF0pgwWMhz8o68JIL42ij%ES|HHLk;%FvOlL;?S~sGE@O~DDSsss;#Tc|MZ8b03Rv) zp54EkON|-my29)<*t{&I0S8wL|M50G*A^MF4gqOwzF!oH^p(Z0B_uu)4Ey{iR!#&$ zpIM>n?4`s_DvB0oPr zpu^ObC*%2Cp+YrF^B>+`bK0b*qIw;bQkzBgBN&hP-UkX^EL?R+0G_#SbBb9dpMdvJJ zOCMXcH#Q1$wd?8X%G7aNPl?Lr?vrI}Ru6so^7;<#Ubbqnj~%z;1_+78#l=knr}E>f zghNUS3PxqZLW7Qyk`gH?sdlq>?XleOmU4M+I5-JYkKo46D~k>E=IrNZnWGhU;zv1f zu0zEptHY(aqGT`Eem&0BtfuXCeECw;y=V{i$;rtnGBQ%AV#mTjPtR_BLMW=ta{Pp3 zq50k1p%Sx7_hYxCJIjtk$7jx**;4Ohxg|mP)r)X-s5rAez>Jd5xZTJwkR4Gr^ibC&T7 zaBqp$_IGGyU%7IH_6QvEWMf7kbWy$gAiz-3iFQTd30o*trOLUoO*m$FB` zotS}?1}19iuXT05_O}-?qPDhMu>be(-`A{hq0_xvr0MGF%EZKE{G+>jqcc%JMMXue z#58fBacjPZh=|D3^b8J;4=>jDZ7N+_T7vmKBV*(CXe1L2jVD=^-C|ft2|G<#(h*nD z1)olEKf*3{i}>HT44;4b>{&06bS)P)!j}}!LyFD~nv$-wF{BwX>lGt`M2ZTMCn5xA{)(aMtc1^oy|Z~AT?dl zxt+z%n9bP^c^^f2`ALr=F-+YvRn@3^%J(yFd{HZU-Ot=y(Hlay0(l%arlwoMuU@@M zbVowDK-asxoHN)W1x`VhWlKpP1MyD)iv#(y#~%lm+wS3Fp-HX53%E9Bf-LKcd9r>r1IJH*&GZ8GgM@hyv9hH?tFSBz3wWbx}k+dZgO%V zAb`2xTiN3be9YzyF3R%>f3Y`XaE zAYyt&U0vNg^I5G=rI0l8?DYC$CT3$bhZePmjTOH2A{|P#a7Sy5VAnv=5v!8%s!-cbQJI4^Ny(`ZjkPOiH(lBKw)h_)+#MJOK- zjNNQVp@}m2-IKtuFnt39q;Authwhg95Z(ahVWPLmkmd-RUw~{g*m(KHgo}&&?%g}U z+5m6w7bCvfivzhx78YM$U!4)rKn{2x_+KgxvTx<&KGv@Ytzr4djO|d&ObuK!^2;{{sQ5sjFeLV)R+als_;z; z4GGcJ(P4Q}f2!XPQ%Wu34{QK}XAd?f%NZ93r|U6P7~1lJ!a~6B?2HTmWZL?8>WNrR z8)0#AaT>SN6?GS(F3h%*_iG@^JL35vW_2NbvdGXDA!w5O$_Y6+HTrE)6T7@Fuv1sD zFiz78F9UHy*ZrQSN=Q%;=ILNz1?H#lL|j~44)?do$;q({B!H5C1yx=c8L1*8bLscn z-N$a0SWHn-QL1?O=gdrtp`xd)O3t_7bq9KTFI>2w3%kW_w-C~F%$z)zvD< zTc-f<$hqzFR-SOcOFm$O(Ox^f5mC+5l$84_1%i^2Z4C`H3=DpDFb`RG1>)+_Q<(5d zx0-C6Us#~vw*LUZ&%n+eCfEOtfJ_;A>yo?sF}+d_JWs}AtR`DF`CW80*`n~qI8<<0 z95Xxn#dGJLkKp6rJn(?RAaiSPe_zh+2t6B5bmfZj?#3A8Zg-j0B>Z}z`6(YPynI&5 zt$~c}_nVS_{`}_jF~qIRC;i`#z?Nv4)@m1Yfm*3Kkeu=HaR`Ort*xz#12L<*ys;Wai#Pq$ry)iK{5O2z*CvkAzVC@;&5~!6Z6sotc zPeWZ@VLIIj0^{t(8$T-@R$E&o`m4_w?<@^M)zlt2O$Mje-`B@$`3nbLa2d+R;lVDF zm6gY8;?(c6`pY3jfgCq0&_p>A+4T00Lva#&~A*=|;SXo)+7Zk{O zTbK(Z`hNJ(+ubeK6@9gv&dddZa~#x)PR@ML7JmFJ3D1Y;?JfltpbKY#3*c~Z~?c!jE#ba z>*HU&s07~0Tsnj|P~Hu)aC39x;^LBy<9RW1js-$29zJ`K@n@y=w2$B|PWL08MPWR+ zxX=Pc&1|@&+WnXhyGaS6Hz7z7XPtMJx;i@}SPZ1Bt(g}!H?ZALqx}}xpO)5ERFM(UVQ>tmjlQ<_twnoy)<e<}fO0ELL%9JL2jGRv9n z99{<^kxmriN$@rYN5ri;DEZ3B4aw13cYc5wa`IS@vxEg$SwP~U4!Q%SU)03IZg*p2Be%nf?#O#u(~%0hiErLnm6yVa z?n)UN84-J|MTUk>udL)GCO!lzu($WJe;M+x6dR&454RXy>ffG+k|+{Dp*JG_h358c zWfhh3va&pL!TUK{wQiU_tA365{<*o($lif>14KMGF)`5y4H&QjTn~1j&J~&iG~;0_ z;-kE_3&z`2oSe88?Q8mA5Rl7$ zN%;bMiX}PEOUt!iUtqs-A(EcuYHHZ!p18RROdrz=?m0^$@DDGOBDdN`97Ko%DOKd})d&3rZrQuh^j2v%qeewk-e&2wTGI%qc%low2a6;N^wRsaAoxUoY;i``S$HPi$16|i_t1h7M5TvA}3tH#%r03DFv79r@+9=r;Yln z5m9w@j~E!Top)FA%>}EZ;`v6(Z4CM~KD~nq0NWs%$|N5jeXzS)YSh!%+pT5*}y{KkzN zreh^l45O3BZO7NMS4~!RGf7B`gd_ z{KbnGb_>1pAnMmEmlW02Ve8o7nVD`s>NbgUf{=%53D8xH8e(mUF5B#uF=rYu$c|nLS@e)lf91k2wbnd z0>3X9J_WWD`{f0z0latb-euCPQkIl71Mb;yPFT=9@8*(U)&5{Q z5)6)^;bA~8vA0mzax^MIf#v-?e$)#*tHNQ`Tw7Z%hVd8SzlixMxQv(y0TdA#=?Ry2 zS5ifF4GbX2-j?M56p5ti4H_&jzP-QPu+)444+u}=&!1(myRa^7 zg?@DY_t?iJC-+*To;%)x6H7}mSjrij#0>o!vYh4eZ{>xYcJhB@18un+YWRYE#l97=CBcj4~eq-tf z5jLko5ZH7SngbdsEG!HW>UMm@3*po6O?3COV)p*tx=z2}C%7W?4NRN-l_ZY6t@+^4 z&^{IO z{g;WL;CDl%Nk*R`AVvL#@+U8MmY_@14)~~oJaKaoDjd`&nl+mZ;1cHM<_il85N$^o zGz+%S`cPrHL_G))U~AUif=^bp#Onk4gMg&Ui&;517>tNoeGCgzJRu!(wV3}HQwZ2d zv*}d^<|h(tAq@=;(0|yyMnomENu4!ZK6!AzW=|50(79a43%KikB_gp8QD0f6<@#7U@TzoKO#FhD2490A(i zT0t_Nl9tweuo1NRwdzDubF*sI%ZH1MKIuRbj7>}^xoqFtQJZ#(o4}*4cw>3JZIw3g zrAJo3xuqqr8ZeY58~qMI4lioH6|iUqUj?tf+?)-Hr4?J<~>ngD>UwY ze4vGeK1Lsw=8s!UyI5gF_JWR^+j$^IgOrpMPQu1}{}KVtBPwiNZ1QSqYJwmrG45Lk z;6H*7ISG6*N2O3-LgK=ru+LosgW0VuTL>u|08GS97!U*Ub8Xr{tgDFLes$DO`Vp`} zth@Xu4$g?1i>o`j9lVy%R%EQ#Me^>R9_QbM9;fEKkm0_UgjJLs_0mXRth>;be4q$j)E!7@@(QWB#q6{uQju7Rb6jAEypc;!C| z+rl@5;95vacYr4d=*SNG1DkfAu`bA?$cTst06Ca#T?WOP<@{m>+!79lyEsr2q0&PJ zr*MFNf+ELQ&;XGZ!EP1>#Rcvm=TsBoti@vmnDzAh{L?S`Gp&(NpFYJt0`}(<1o8RW zg8T=Hxtg&N5lt1oSEk^!w}xuqD@zuIzumfb50;~dEqH{42G|q(ggtxOwW%M$K>pYa zJAc7p!o%pexGLaT;MQi5;nH5=gywasC|m>IxfyfGHjZ;|7dE0 zZ(Hz$+E`(?2w&Z!Qu-A}k|-B@GXNS%`~5-?AbwI^+hIZ9dwS%hrLn#bKwThI=Z;7g zkz0YLKl5H+^v)W_#koX|edIBGIRr62zAvLj1vXV+O<3d}8gc?kl0`=MSVB^glILYz zg>R4{ct2p2GHKNSQ7yx)f2V{XMIw>k2|aLeny}{Vp18L51b8V$#l?i=T;D24cEB9x za#-Op?)?;mj@Hb=x>VmZPsNo3d|oFb1MdRjAjxLw=fjgHJsx|Uc`*x)`tMD5JKR>{ z<>duM3g%J%iYKpFJLr_f(Q0nKALnVB0nor?^JF^NA}%Eb7eNwXN1)dA^z^8JeygK^ zFbXk*=_)WyNitp|(xl@@ zQ=SrG>>bR(9|Do{IW4UO?rKHpV-?#;z($z@aJyThkIgNri|g7&epNc?VQJ4o*EdC9kef zv9sGxH3h=;KW^83uoDDl;a3oeRt-02xa<}XmoC*+;P0vZZ{KSzQE$4tyIV0wJp}6wi;Rz6hlGTHN9Rw$OG>iSkqn0E zMHr|DbQ>55$L_l)A$F@mfq($(fpSOfM;i$I1Ag!5@L&=Z_2~w$(-s6?RwYgY_>iWi zrgtPF>MAZjy848c+A$>wKTQB3g$;8u zTp5~pes}ZklpjS#J<7-=F#sH-#pwM&QT^74KrHN$L*;*seZMc@;6YW?F*bIBE=zy) z``F-MdDyHqd&Rd>;FmA`i&~PHv)zu(Np&5WpH<@#g`j3i1 zkXj6vNZty(uUU1Ce{nzFP^<5gtjA~<=qbcC_<{y_KNSbuV=6|*_U`U0;nVc5fJ(DN z%TLJns>2HE1>kKR5^LoVUnM5iGc%K1{b8v$S+%yk-3N`dBMj%F@S}XtryAwfo^~W_ zV<66+8yf?yX|A~32XwAj=lex4yTF^71|5loO4^$Ml`>E1=;-jT-Ullr0jXPNY_53< zzUGU2ps7i;-w$jHP>O61AF9;4@h%E0$f>KN-kv7{J^-{_^F|%+BVyR^R|{D4quPBL zZj@FB>W%ms@4?I^Sirxjz-5^`w6wHX6Pe^AQ19x`n$`Od46yT`fhTssA%NoU#Pz`j z0vhX>eZI}eXx{rt7En1|Di)%z`6XDvu%SR#Ax4kCz?TLz_z-7RzH)g9uTAa`m=0>| zS!ir*HLMm}G0Bkr7gw>b*o4)5GS|W1!V*g`bg_bXH;EZgO~=r%3|;~v6R`c@~F!9H)*Nh+_AaHPSz`Ww*TVTwacb z4~3=4#EjIsYpJOnfV~XD$PA2UsN4jktaWTVIFB&cIOv7iL3;`WC!0yXuD*VOxkxB5 z3y41#D8*pVS5?3;0t{;@JK&yvd|pOe9Dgi&&mOye5KO#ItZp9(;Ty*wUA`?s(N|Pd zgfOfRV3}3|KLR)qa6bRVvCo&3{uf#Q9mwVXz7ONtMUfIkcI0W6j8OK!2iQX!kn6p3slTiInL5gEVZ>h<~F-_P&9|9iiCak;L?IM3rej^lhh3_B&< zMqf>Dq#UmeMbu`zapMNw$P3~gM6n3fLy&E%{Sr6&A1CH-KbDUdIu{ZDe=jW9^#!Xz z-Nl(XW_VeA*3xcz`rA9x+OnX`cFiEDAgWSN4^$2mUNQxNyiyF+U^imR-TRf5l@%2g zP?M3pAqG4GMbd{Nny9oxDI$*3E%B&w{@F)wVPSzNn5=N;+m&4#Wc7$~QN)b2W5Xi_ zep9R2QV2YO?;Da~(`&`vg7Aj{8Q?vB+(Kt4!zG)&v+4MkW~>=5pyZ4`}%x)i(RmItnuZ`M~IM1ywzraU%b(0*tQ9>VOl9LLE6_uUH!*DG+DQvbA`oH``|iL=b_3N zdz?08zmd$5#N$a)9H) z>kWM_9G9GC`kQ}ApYU-jb(;}<`>|rOpTCZq?lpn!d$!au-#;iJ@Am*hGkQt!MUqU| zBQAAMl=dK`%1~dpGh$IvoZho{Z@R`~jz~3}eQ~oZ#ZBJQGO40s4aa4C=-Ey&$ht7y zcfrPHe(=qve&zh2TeofjKp~Z0Lj{kKEJM0-rz0LDE_k-s5)n1$+KLmXzn@erF-_VX%aX_x6CU_;zXYa0Cc7JnwN4RanDCM1qcvd2r%oq4w;DPbc!5 zy>`dX@#y_p*htYLKs;`#5lA>BB;+;?D+?1-Lr?Jd4jP)G+}ydJKfmH}8^KgPWoyKc z`5I)J*jicL$etVBg0F)>+}hqAcl4aHy!=LIplCB9Gl%)Xm(cOyLxxVO+Mi{otlf~F zLEnQGoE6(h@rP19ia#em|DD2vUw1K3?vr0ytE<1kp7w9hH)5=0uZKN)lxz8BBdSB0 zpH*_8+GK)@uwilKD_g%=^T zu{H0YrpCU?4G(WeRQB>|-2*HEaM=qj+hlNR%P=EiAX#Q_zo0COFhp`GsZvB{Okxxm z0mO;#6BC-TA`_s0h)K++Cti$Y4-=ErwLg~?6y5^M{#qdG?_?BtX7%|kx33%;`-d)tKIq1ZZ$VUK3 z4bG_!dy%bERa4Ugs)na$?XUH@JD}beQ=SPiOJ6&l7KN`Ql8mg@&&5To?C&kfZ&9#b z^=Z`topI5|#{JK%Rll-q{~i{W`xjbYE4#Y7La8}xW=7J+H1jDcD$Y;!bRv~^b~3Cl zY@x8BA)dCdgyo3Li=v0nUV4H*&taTV9f7yRVxNmg)&SWRg>f4=#LbN?+0oa>{J^jI zbimD<7doDO9UQ#;YgCgMxPJshn5O4+uYkYhASoA%#6D?h?SEx;Q;!$gG280zpM{$!cJC#o)Oi%NEh_$^yu81^ znq{yD>|hZ&$jqz~vi}V+V$Ju0gWWD)-Y;yk-I-HTMNh9|@Xbw{5?fsxW+W@gr~P8JGG~2A}P8Uq)WZ4t^H<_F9`31F32$e!&xzMFyi3x zLs#H%yGDFxjY(Ge551IYDEo}H%TB%XGS3)*}` zLolB9`0m}iAW52IMT3iInYp;R?NEY%t^su#GqZ~#>;N%R*|5L696OeWU<)E|Zh^e_ zs*jJUsp*jYrlhfC`$VM$`s=GgXrjK>eJ4i+d$v1?4E$-i#3}M;KU$!7BQ0|iI#{wYfn&6z#x=ktUv3Yx-yJfLMLM$<^+5x zg$Px>GsY0#HhO7u9W~1ddnc#q@83~w^AYPjo&ee_Z)<`Xz?DN>S;tAj*!C!M%wu9> zr@!Rf#0NgXx;Yrj8D>PDMJihAz-eApqJ#~v>T$q?Sq0>B5?dddI zN>KV?*xj&GAuy^biNO`;{NZKz2`r#9Ljgf$6o3AYH=htRFtw+o&6USI6WJ>L}n z6<=1h4I|~A01oN^BO~r|vuR~(Pw`p2oCla9^;|?{@h~pt!p#wD# zS<$Okmt9js56R7qHA2mc{w`ck7iDEhJ>-7A4g77@3zKE=NWJRjyoS$M-|hY-(zn zFU5q|?}o@!&D^3#C36jEzU?v{Rix)#CR{gyp`Dn^XLg_4`on;+gv<6~MPO!_SkdJ+G|QN{xYE*66-C9_1#@0M7Ag+yE+DyS_4Tize-u@~?wti)Q z4n$g450BIh3^a!~$p&K~$^P|PoMsLkx2=zmxH5eZgWLq{3nY_x!V8I}mD4(>ac$bDx)0bx~xp!u_9LsBF$VU0NR0D;fk!om-;{fAQU%9nguq|f0? zo9zV=EZ%-n3iANNqC-~PagEmS81RoV+*Ob`v80B+eY=XHXqX#=WG{g2_6+D5$#e#% zpY~9NX!R*!O?iY!lot=etg>uQMr!cgL0hyDSJ@qen=O4gAgrxJ6)u|DCAP0LA zyxq{H&3A8u^E>Ic7GFfgX27i#Zv?9<@=IGy#xJQKx3NPYg}*nAhd za-o(IW(qH#4eO^J9iQjrxuMoVc*8$Xj8j5m%P%T=U#Tnl1X3bMhEu6+kV}SGSt;&P zW26*!j^uNx!+-P$iVzg4*}_e03Xnt+;^QBMhkG$?u(k#Tbk&izjvYe}UjE(FNX0kU z{}YS0Fo+Pt*sza+7WI<9Q3?JZh%P2kM}(Yn{pS805SX*f%O#tv-xRe$CP$q9<+NB`0@WqF@x#t!(<|;x2g`EHJp*9Gvqe=%UVhKRS zF$8WIwihG>71eePo-L1KV{ZorBG6K_I3Vi4C)5Gk$+c_*RFGz@(r2+TpbvuSA@;BE z7U0*`Swwyi!4ZOH%ZLMb-A{j(mN2L&>F}U;_4v=N*JYg^!r_J_jRkXtJUX@I+9sgz z3~UgrK_sGTEOl8?Y@ECP5X69-&YXxlVzseiEG-8IrfOPP$nfyoEuv+!22dvCP^2jq za8N7w76HU-WjtL_6^90eJiWkl+DysDOLGLWYrpt2TDiKY- zz1x9kQY>+GmMxK$$~78b1>+4DuqCB^D=iQ{gx`CLxgb+}&rtX)6Vo~RC?Z0{ZB&C% z8Z^iKhV8K*fvq9Q;Hzp8%qgCs4Zax$a@fML$8GMwy+CMn@`03Cf8UT4W@(7Xzyl*2 zLJ44cA1Ek<=IBCP12S5!H7cati zS=T~tyZZ-Z9!&kw(G1RaX}LKRk$e^ ziZdqwEDT?$a7=1|6E^>J35%CTm_<9RI zFuug=mmS^;zKlQrwxz7W&$+qh&`9+3=$tuadtyW!+OU-I#BQQ|65!`Y$yE*pp2l2*VfjsD--Z)Lj5psB;E7T!%qEnpgij%*?L6?`8 zuf_}2Nr5s1DItNtO#KsV1xi?$d9X`e?_f!T_sFpM@CZ(30t;Q*N@DcCW(%NzVh|ms zM9wCjhL@W!RjA(JRUfd0sy5`nTP#!ov?W}!wDfOD)oeKf^0W`jpjTpxEDN@ctn|;> zuW!M=cY=?t22U{<=e0baaqr#^!A}3OQ4|9x!M{yy{0B`sJ3Cc++PPt=!=gkk7I*pf z4%iKo?q5heD=|DiesW@h^iY+ksG_23d#L}|;gc=WG#(@5W5H8Uc-7#4kyM8~nFNMV z_W;a66s_^Qv7ye47$H-*>d_n0iB*ViCSs$4hK2?FvI(*#?@Bw~N$>Z~OqOct6V zma(A_=G~*=xrYnhqTD+YQ`ms~y8P!)i_jIE!g=)QQAAWWZ{iL2f~!7nZ7mFq7-{t< z-tZJm-mtK|c)>UQcH2@dzKW2_Fz^oOVIf7T{XDWUa~P!)3k!?;^;|H~2!Oi@X?$21 zb+J7F=hEB=u}6G1NRZ+00;d5$0hS0DED{NE|Ni}8MB?yLhtHO{BFXY1FP5X_6H(^w zK76HX=zoS%Fsl$>x&CcK*LPULNWt_3TeQ7J07ZWAj6a2@B{B?*y1+k(g2Ox9YjaWM zOP)I*>244IC>WxYF%ZO_&C-wBiZ>0ZOOY*~=KWCb`yBg*(*PHnV{M zvT-pngE!uqXu#PFw+>iifHJ~Nf<0}GHWvSQqQe8Unp$cbAOptC^#+n!G>`VTf20?M z*)VcE!Hi99^!NJ$Z&*eKX<1=vG`n&wx2Px^MGn%FnDDg-f0B)lkDX@}cLKpf5%eD+Hkid{Hi&JCx6d-j1kc+^ ze3%=+)?g2~er-rBu*9+uGz?Xps5#EnMsWta7$(sJwQnJ!W4|E9nK#f5(EI@N9n#Vg zQD6g86E5+4VjIp7n!7QVgoGDhD(Ywi#Nzf-aYQ)9N(0CxxEKn15d?Ge??|$Qq;R5I z3}F<7GtwFA0=ls^|F7^dZeai#{E(ZrCEnR_t>+VQA!~)j2PcSH4Eu~=7 zMXmCEa1dM~-nH&9!I3A)Z35CIu%`UJgxBki!U$HP*YO_QUW%( zF=n%I7yI$!#nAq+vXbuOCq8Feu(k(`(}BVwX_FOU7(MdgAO&&fPe%?2EFf&`?xC$> zQ#T*E0ht4_Xd1_2_pjY(Is?H4j3~wTq^9=1zH+dWL|s_!zk-6%30W4#5Ad9Cig!?8 zw4UQAK3iy`h&^}4SRD9JK|P0_bnV&+XHHxqBn(hbumS*u|2Qz∈MtPMEwTr6eK$ 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 Stellen Sie sich einen Möbelhersteller vor, der Möbelstücke in verschiedenen Stilen anbietet, z.B. modern, viktorianisch, rustikal. Zu jedem Stil gibt es Produkte wie Stühle, Tische und Sessel. Um Produkte unabhängig vom Stil einheitlich verwalten zu können, wird das Abstract-Factory-Pattern eingesetzt. +> +> Dabei ist die Abstract Factory ein Interface, mit dem mehrere Familien zusammengehöriger Möbelstücke (Stühle, Tische, Sessel) erzeugt werden. Jede einzelne konkrete Factory (ModernFurnitureFactory, VictorianFurnitureFactory, RusticFurnitureFactory) implementiert dieses Interface und erzeugt Möbelstücke des jeweiligen Stils. Auf diese Weise können ganze Einrichtungen in einem bestimmten Stil produziert werden, ohne dass man sich um die Details der Instantiierung kümmern muss. Das erlaubt eine einheitliche Bearbeitung und einen einfachen Wechsel des Einrichtungsstils. + +In einfachen Worten + +> Eine Factory für Factories - eine Factory, die mehrere zusammengehörende Factories vereinigt, ohne die konkrete Klasse der Objekte festzulegen. + +Wikipedia sagt + +> Das Abstract-Factory-Pattern dient zur Kapselung einer Gruppe einzelner Factories mit gemeinsamem Thema, wobei deren konkrete Klasse variabel bleibt. + +Klassendiagramm + +![Abstract Factory class diagram](/abstract-factory/etc/abstract-factory.urm.png "Abstract Factory class diagram") + +## Programmbeispiel + +Um ein Königreich mit dem Abstract-Factory-Pattern zu erzeugen, brauchen wir ein gemeinsames Thema. Das Elben-Königreich hat einen Elbenkönig, ein Elbenschlos und eine Elbenarmee, das Ork-Königreich dagegen einen Orkkönig, ein Orkschloss und eine Orkarmee. Die Objekte des jeweiligen Königreichs hängen voneinander ab. + +Zunächst definieren wir die Interfaces und implementieren sie für die einzelnen Königreiche. + +```java +public interface Castle { + String getDescription(); +} + +public interface King { + String getDescription(); +} + +public interface Army { + String getDescription(); +} + +// Elben-Implementationen -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the elven castle!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfKing implements King { + static final String DESCRIPTION = "This is the elven king!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the elven Army!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// Ork-Implementations analog -> ... +``` + +Nun kommt das Interface für die Königreich-Factory und seine Implementationen. + +```java +public interface KingdomFactory { + Castle createCastle(); + + King createKing(); + + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + + @Override + public Castle createCastle() { + return new ElfCastle(); + } + + @Override + public King createKing() { + return new ElfKing(); + } + + @Override + public Army createArmy() { + return new ElfArmy(); + } +} + +// Ork-Implementationen analog -> ... +``` + +Jetzt können wir eine Factory bauen, die eine Instanz von entweder `ElfKingdomFactory` oder `OrcKingdomFactory` erstellt. Diese nennen wir `FactoryMaker`. Der Client kann `FactoryMaker` verwenden, um die gewünschte Factory zu erzeugen, mit der dann wiederum konkrete Objekte (abgeleitet von `Army`, `King`, `Castle`) erzeugt werden können. In diesem Beispiel nutzen wir ein Enum als Parameter für die gewünschte Art der Factory. + +```java +public static class FactoryMaker { + + public enum KingdomType { + ELF, ORC + } + + public static KingdomFactory makeFactory(KingdomType type) { + return switch (type) { + case ELF -> new ElfKingdomFactory(); + case ORC -> new OrcKingdomFactory(); + }; + } +} +``` + +Hier die main-Methode der Beispielanwendung: + +```java +LOGGER.info("elf kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); + +LOGGER.info("orc kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); +``` + +Ausgabe: + +``` +07:35:46.340 [main] INFO com.iluwatar.abstractfactory.App -- elf kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven king! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- orc kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc king! +``` + +## Verwendung + +Einsatzkriterien für Abstract Factory: +* Das System sollte nicht davon abhängig sein, wie die Produkte erzeugt, zusammengesetzt und dargestellt werden. +* Nötige Konfiguration für eine oder mehrere Produktfamilien. +* Eine Familie ähnlicher Produkte muss gemeinsam auf gleiche Art genutzt werden. +* Die Klassenbibliothek der Produkte zeigt dem Anwender nur ihre Interfaces, nicht ihre Implementation. +* Abhängigkeiten zwischen den Produkten existieren kürzer als die Verwendung dauert. +* Abhängigkeiten müssen zur Laufzeit durch Parameter konstruiert werden. +* Zur Laufzeit wird ein Produkt aus einer Familie ausgewählt. +* Keine Code-Änderungen bei Hinzufügen weiterer Familien oder Produkte. + +## Tutorials + +* [Abstract Factory Design Pattern in Java (DigitalOcean)](https://www.digitalocean.com/community/tutorials/abstract-factory-design-pattern-in-java) +* [Abstract Factory(Refactoring Guru)](https://refactoring.guru/design-patterns/abstract-factory) + +## Vor- und Nachteile + +Vorteile: + +* Flexibilität: Einfacher Wechsel zwischen Produktfamilien ohne Codeänderung. + +* Entkopplung: Der Verwender sieht nur abstrakte Interfaces, wodurch sich Portabilität und Wartbarkeit verbessern. + +* Wiederverwendbarkeit: Objekte aus einer Abstract Factory können projektübergreifend eingesetzt werden. + +* Wartbarkeit: Änderungen an einer einzelnen Produktfamilie sind nur lokal in deren Implementation nötig, was Updates erleichtert. +* +Nachteile: + +* Komplexität: Anfänglicher Zusatzaufwand für die Definition von Interfaces und konkreten Factories. +* +* Intransparenz: Die Transparenz könnte leiden, weil der Client-Code mit den Produkten nur indirekt über den Umweg der Factories interagiert. + +## Reale Anwendungen + +* Die `LookAndFeel` Klassen von Java Swing stellen mittels Abstract Factory verschiedene optische Darstellungen zur Verfügung. +* Verschiedene Implementationen im Java Abstract Window Toolkit (AWT) verwenden das Pattern zur Erzeugung diverser GUI-Komponenten. +* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) + +## Verwandte Patterns + +* [Factory-Methoden](https://java-design-patterns.com/patterns/factory-method/): Abstract Factory verwendet Factory-Methoden zur Erzeugung von Produkten. +* [Singleton](https://java-design-patterns.com/patterns/singleton/): Abstract-Factory-Klassen sind häufig als Singletons implementiert. +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): Ähnlich wie Abstract Factory, aber mit Schwerpunkt auf flexibler Konfiguration und Verwaltung verwandter Objekte . + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Design Patterns in Java](https://amzn.to/3Syw0vC) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3HWNf4U) diff --git a/localization/de/active-object/README.md b/localization/de/active-object/README.md new file mode 100644 index 000000000000..d37a52e7a09d --- /dev/null +++ b/localization/de/active-object/README.md @@ -0,0 +1,232 @@ +--- +shortTitle: Active Object +category: Concurrency +language: de +tag: + - Asynchronous + - Decoupling + - Messaging + - Synchronization + - Thread management +--- + +## Zweck + +Active Object bietet eine zuverlässige Methode zur Behandlung asynchroner Prozesse, mit der reaktionsfähige Anwendungen +und effizientes Thread-Management gesichert werden. +Dies wird dadurch erreicht, dass die einzelnen Aufgaben in Objekte gekapselt werden, die in eigenen Threads (Steuerungsflüssen) +mit eigener Nachrichtenwarteschlange aktiv sind. Durch diese Trennung bleibt der Hauptthread +reaktionsfähig und Probleme wie direkte Threadmanipulation oder gemeinsamer Zugriff auf Zustände werden vermieden. + +## Detaillierte Erklärung + +Reales Beispiel + +> Stellen Sie sich ein gut besuchtes Restaurant vor, in dem die Gäste Bestellungen bei den +> Kellner aufgeben. Die Kellner gehen nicht selbst in die Küche, um die Essen selbst zuzubereiten, +> sondern sie schreiben die Bestellungen auf Zettel und geben diese dem Küchenmanager. +> Der Manager organisiert eine Gruppe von Köchen, die die verschiedenen Mahlzeiten parallel zubereiten. +> Wenn ein Koch frei ist, nimmt er eine Bestellung aus der Warteschlange, bereitet das Essen zu +> und benachrichtigt den Kellner, sobald es fertig zum Servieren ist. +> +> In dieser Analogie stehen die Kellner für die Client-Threads, +> der Küchenmanager für den Thread-Scheduler, und die Köche für die Methodenausführung +> in verschiedenen Threads. +> Die Organisation ermöglicht es, dass die Kellner immer weiter Bestellungen annehmen können, +> ohne durch die Essenszubereitung aufgehalten zu werden; so wie das Active-Object-Pattern +> den Methodenaufruf von der Ausführung trennt, um die Effizienz zu verbessern. + +In einfachen Worten + +> Das Active-Object-Pattern trennt Methodenausführung und Methodenaufruf, +> um Parallelitätsgrad und Reaktionsfähigkeit in Multithread-Anwendungen zu verbessern. + +Wikipedia sagt + +> Das Design-Pattern Active Object entkoppelt die Methodenausführung vom Methodenaufruf +> für Objekte, die in ihrem jeweils eigenen Thread arbeiten. +> Ziel ist, Parallelität dadurch zu ermöglichen, dass Methoden asynchron aufgerufen werden und ein +> Scheduler die Anfragen organisiert. +> +> Das Pattern besteht aus sechs Elementen. +> +> * Ein Proxy stellt für Clients ein Interface mit öffentlich zugänglichen Methoden zur Verfügung. +> * Ein weiteres Interface definiert die Anfragen an ein aktives Objekt. +> * Eine Liste offener Client-Anfragen. +> * Ein Scheduler entscheidet, welche Anfrage als nächstes ausgeführt wird. +> * Die Implementation der Methoden. +> * Eine Callback-Variable zur Rückmeldung des Ergebnisses. + +Ablaufdiagramm + +![Active Object sequence diagram](/active-object/etc/active-object-sequence-diagram.png) + + +## Programmbeispiel in Java + +Die Orcs sind wilde und nicht zu bändigende Kreaturen. Anscheinend haben sie ihre eigene Steuerung, die nur von ihrem vorherigen Verhalten bestimmt wird. +Um eine derartige Kreatur zu implementieren, können wir das Active-Objekt-Pattern benutzen. + +```java +public abstract class ActiveCreature { + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + thread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + requests.take().run(); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + } + } + ); + thread.start(); + } + + public void eat() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} is eating!", name()); + logger.info("{} has finished eating!", name()); + } + } + ); + } + + public void roam() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} has started to roam the wastelands.", name()); + } + } + ); + } + + public String name() { + return this.name; + } +} +``` + +Man sieht, dass jede Klasse, die `ActiveCreature` erweitert, ihren eigenen Kontrollfluss für den Aufruf und die Ausführung der Methoden zum Herumstreifen und Essen hat. + +Beispielsweise die Klasse `Orc`: + +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } +} +``` +Nun können wir etliche Kreaturen dieser Art schaffen, sie zum Essen und Herumstreifen auffordern, aber jede von ihnen wird das in Eigenregie (eigener Thread) ausführen. + +```java +public class App implements Runnable { + + private static final Logger logger = LoggerFactory.getLogger(App.class.getName()); + + private static final int NUM_CREATURES = 3; + + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + List creatures = new ArrayList<>(); + try { + for (int i = 0; i < NUM_CREATURES; i++) { + creatures.add(new Orc(Orc.class.getSimpleName() + i)); + creatures.get(i).eat(); + creatures.get(i).roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + Thread.currentThread().interrupt(); + } finally { + for (int i = 0; i < NUM_CREATURES; i++) { + creatures.get(i).kill(0); + } + } + } +} +``` + +Programmausgabe: + +``` +09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating! +09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating! +09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating! +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating! +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating! +09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands. +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating! +09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands. +09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands. +``` + +## Verwendung + +* Wenn asynchrone Aufgaben behandelt werden sollen, ohne dass der Hauptthread blockiert wird, um bessere Performance und Reaktionsfähigkeit zu gewährleisten. +* Bei asynchronen Interaktionen mit externen Ressourcen. +* Zur Verbesserung der Reaktionsfähigkeit. +* Zum Management parallel ablaufender Aufgaben in modularer und wartbarer Art und Weise. +* +## Tutorials + +* [Android and Java Concurrency: The Active Object Pattern(Douglas Schmidt)](https://www.youtube.com/watch?v=Cd8t2u5Qmvc) + +## Reale Anwendungen in Java + +* Echtzeit-Handelssysteme mit asynchroner Verarbeitung von Transaktionen. +* GUIs, bei denen langwierige Arbeiten im Hintergrund ablaufen, ohne dass die Benutzeroberfläche einfriert. +* Spiele, bei denen Aktualisierungen des Spielstatus oder KI-Berechnungen parallel abgearbeitet werden. + +## Vor- und Nachteile + +Vorteile + +* Reaktionsfähigkeit des Hauptthreads wird verbessert +* Parallelitätsprobleme sind in den Objekten gekapselt +* Ermöglicht bessere Codeorganisation und -wartbarkeit. +* Sorgt für Threadsicherheit und vermeidet Probleme beim gemeinsamen Zugriff auf Zustände. + +Nachteile + +* Zusatzaufwand für die Übermittlung von Benachrichtigungen und das Threadmanagement. +* Nicht für alle Arten von Nebenläufigkeitsproblemen geeignet. + +## Verwandte Patterns + +* [Command](https://java-design-patterns.com/patterns/command/): Kapselt Anfragen als Objekte, ähnlich wie Active Object es mit Methodenaufrufen macht. +* [Promise](https://java-design-patterns.com/patterns/promise/): Bietet einen Weg zur Abfrage von Ergebnissen eines asynchronen Methodenaufrufs, oft mit Active Object kombiniert. +* [Proxy](https://java-design-patterns.com/patterns/proxy/): Active Object kann einen Proxy verwenden, um asynchrone Methodenaufrufe zu behandeln. + +## Quellen + +* [Design Patterns: Elements of Reusable Object Software](https://amzn.to/3HYqrBE) +* [Concurrent Programming in Java: Design Principles and Patterns](https://amzn.to/498SRVq) +* [Java Concurrency in Practice](https://amzn.to/4aRMruW) +* [Learning Concurrent Programming in Scala](https://amzn.to/3UE07nV) +* [Pattern Languages of Program Design 3](https://amzn.to/3OI1j61) +* [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/3UgC24V) diff --git a/localization/de/actor-model/README.md b/localization/de/actor-model/README.md new file mode 100644 index 000000000000..3c3cb436eb97 --- /dev/null +++ b/localization/de/actor-model/README.md @@ -0,0 +1,203 @@ +--- +shortTitle: Actor Model +category: Concurrency +language: de +tag: + - Concurrency + - Messaging + - Isolation + - Asynchronous + - Distributed Systems + - Actor Model +--- + +## Alternativbezeichnungen + +- Message-passing concurrency +- Actor-based concurrency + +--- + +## Zweck + +Das Actor-Model-Pattern ermöglicht die Konstruktion von hochparallelen fehlertoleranten verteilten Systemen, +indem es isolierte Komponenten (Akteure) verwendet, die ausschließlich über asynchronen Nachrichtenaustausch interagieren. + +## Detaillierte Erklärung + +--- + +### 📦 Reales Beispiel + +Stellen Sie sich ein Kundendienstsystem vor. +- Jeder **Kundendienstmitarbeiter** ist ein **Aktor**. +- Kunden **senden Anfragen (Nachrichten)** an die Mitarbeiter. +- Jeder Mitarbeiter behandelt zu einem bestimmten Zeitpunkt genau eine Anfrage und kann diese **asynchron beantworten**, +ohne dabei anderen Mitarbeitern in die Quere zu kommen. + +--- + +### 🧠 In einfachen Worten + +> "Aktoren sind wie unabhängige Arbeiter, die keine Ressourcen teilen und nur über Nachrichten kommunizieren." + +--- + +### 📖 Wikipedia sagt + +> Das [Actor Model](https://en.wikipedia.org/wiki/Actor_model) ist ein mathematisches Modell +> für parallele Informationsverarbeitung, das "Aktoren" als universelle Ausführer von Aufgaben betrachtet. + +--- + +### 🧹 Klassendiagramm + +![UML Class Diagram](./etc/Actor_Model_UML_Class_Diagram.png) + +--- + +## Programmbeispiel in Java + +### Actor.java + +```java +public abstract class Actor implements Runnable { + + @Setter + @Getter + private String actorId; + private final BlockingQueue mailbox = new LinkedBlockingQueue<>(); + private volatile boolean active = true; + + + public void send(Message message) { + mailbox.add(message); + } + + public void stop() { + active = false; + } + + @Override + public void run() { + + } + + protected abstract void onReceive(Message message); +} + +``` + +### Message.java + +```java + +@AllArgsConstructor +@Getter +@Setter +public class Message { + private final String content; + private final String senderId; +} +``` + +### ActorSystem.java + +```java +public class ActorSystem { + public void startActor(Actor actor) { + String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID + actor.setActorId(actorId); // assign the actor it's ID + actorRegister.put(actorId, actor); // Register and save the actor with it's ID + executor.submit(actor); // Run the actor in a thread + } + public Actor getActorById(String actorId) { + return actorRegister.get(actorId); // Find by Id + } + + public void shutdown() { + executor.shutdownNow(); // Stop all threads + } +} +``` + +### App.java + +```java +public class App { + public static void main(String[] args) { + ActorSystem system = new ActorSystem(); + Actor srijan = new ExampleActor(system); + Actor ansh = new ExampleActor2(system); + + system.startActor(srijan); + system.startActor(ansh); + ansh.send(new Message("Hello ansh", srijan.getActorId())); + srijan.send(new Message("Hello srijan!", ansh.getActorId())); + + Thread.sleep(1000); // Give time for messages to process + + srijan.stop(); // Stop the actor gracefully + ansh.stop(); + system.shutdown(); // Stop the actor system + } +} +``` + +--- + +## Verwendung + +- Bei der Konstruktion **paralleler oder verteilter Systeme** +- Wenn **keine veränderlichen Zustände geteilt** werden sollen +- Wenn **asynchrone, nachrichtenbasierte Kommunikation** benötigt wird +- Wenn die Komponenten **isoliert und lose gekoppelt** sein sollen. + +--- + +## Tutorials + +- [Baeldung – Akka with Java](https://www.baeldung.com/java-akka) +- [Vaughn Vernon – Reactive Messaging Patterns](https://vaughnvernon.co/?p=1143) + +--- + +## Reale Anwendungen + +- [Akka Framework](https://akka.io/) +- [Concurrency in Erlang und Elixir](https://www.erlang.org/) +- [Microsoft Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/) +- JVM-basierte Spiel-Engines und Simulatoren + +--- + +## Vor- und Nachteile + +### ✅ Vorteile +- Unterstützt hohes Maß an Parallelität +- Leichte Skalierbarkeit über Zahl der Threads oder Prozessoren. +- Fehlerisolation und -behebbarkeit. +- Geordnete Nachrichten in den Aktoren + +### ⚠️ Nachteile +- Schwierigeres Debugging wegen asynchronen Verhaltens +- Leichte Performance-Einbußen durch die Nachrichten-Warteschlangen +- Komplexeres Design als bei einfachem Methodenaufruf +--- + +## Verwandte Patterns + +- [Command Pattern](../command) +- [Mediator Pattern](../mediator) +- [Event-Driven Architecture](../event-driven-architecture) +- [Observer Pattern](../observer) + +--- + +## Quellen + +- *Programming Erlang*, Joe Armstrong +- *Reactive Design Patterns*, Roland Kuhn +- *The Actor Model in 10 Minutes*, [InfoQ Article](https://www.infoq.com/articles/actor-model/) +- [Akka Documentation](https://doc.akka.io/docs/akka/current/index.html) + diff --git a/localization/de/acyclic-visitor/README.md b/localization/de/acyclic-visitor/README.md new file mode 100644 index 000000000000..d60f456e528a --- /dev/null +++ b/localization/de/acyclic-visitor/README.md @@ -0,0 +1,192 @@ +--- +shortTitle: Acyclic Visitor +category: Behavioral +language: de +tag: + - Decoupling + - Extensibility + - Interface + - Object composition +--- + +## Zweck + +Das Acyclic-Visitor-Pattern entkoppelt Operationen von der Objekthierarchie und erlaubt so ein flexibles Design für verschiedenste Anwendungen. + +## Detailierte Erklärung + +Reales Beispiel + +> Als Vergleich aus der realen analogen Welt soll ein System von Museumsführern dienen. +> Stellen Sie sich ein Museum mit verschiedensten Ausstellungsstücken (Bilder, Skulpturen, historische Artefakte, ...) vor. +> Es gibt dort verschiedene Typen von Führern (Menschen, Audio-Guides, VR-Führer), die zu jedem Objekt Informationen geben. +> Wenn nun eine neue Art der Führung eingeführt wird, muss nicht jedes Ausstellungsstück dafür angepasst werden. +> Stattdessen implementiert jeder Führer eine Schnittstelle zu den jeweiligen Ausstellungstücken. +> Auf diese Weise ist das System leicht erweiterbar. + +In einfachen Worten + +> Acyclic Visitor erlaubt das Hinzufügen von Funktionen, ohne die bestehende Hierarchie anpassen zu müssen. + +[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) sagt: + +> Das Acyclic-Visitor-Pattern erlaubt es, neue Funktionen zu einer bestehenden Klassenhierarchie +> hinzuzufügen, ohne diese Hierarchie zu verändern und ohne Abhängigkeitszyklen (wie beim Visitor Pattern) zu schaffen. + +Ablaufdiagramm + +![Acyclic Visitor sequence diagram](/acyclic-visitor/etc/acyclic-visitor-sequence-diagram.png "Acyclic Visitor sequence diagram") + + +## Programmbeispiel + +Wir betrachten eine Hierarchie von Modem-Klassen. Die Modems werden besucht von einem externen Algorithmus, +der auf Filterkritien (Unix- oder DOS-Kompatibilität) basiert. + +Here die `Modem` Hierarchie. + +```java +public abstract class Modem { + public abstract void accept(ModemVisitor modemVisitor); +} + +public class Zoom extends Modem { + + // Weitere Eigenschaften und Methoden ... + + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof ZoomVisitor) { + ((ZoomVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem"); + } + } +} + +public class Hayes extends Modem { + + // Weitere Eigenschaften und Methoden... + + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof HayesVisitor) { + ((HayesVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem"); + } + } +} +``` + +Danach führen wir die `ModemVisitor` Hierarchie ein. + +```java +public interface ModemVisitor { +} + +public interface HayesVisitor extends ModemVisitor { + void visit(Hayes hayes); +} + +public interface ZoomVisitor extends ModemVisitor { + void visit(Zoom zoom); +} + +public interface AllModemVisitor extends ZoomVisitor, HayesVisitor { +} + +public class ConfigureForDosVisitor implements AllModemVisitor { + + // Weitere Eigenschaften und Methoden... + + @Override + public void visit(Hayes hayes) { + LOGGER.info(hayes + " used with Dos configurator."); + } + + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Dos configurator."); + } +} + +public class ConfigureForUnixVisitor implements ZoomVisitor { + + // Weitere Eigenschaften und Methoden... + + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Unix configurator."); + } +} +``` + +Schließlich die Visitors im Einsatz. + +```java +public static void main(String[] args) { + var conUnix = new ConfigureForUnixVisitor(); + var conDos = new ConfigureForDosVisitor(); + + var zoom = new Zoom(); + var hayes = new Hayes(); + + hayes.accept(conDos); // Hayes modem with Dos configurator + zoom.accept(conDos); // Zoom modem with Dos configurator + hayes.accept(conUnix); // Hayes modem with Unix configurator + zoom.accept(conUnix); // Zoom modem with Unix configurator +} +``` + +Programausgabe: + +``` +09:15:11.125 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForDosVisitor -- Hayes modem used with Dos configurator. +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForDosVisitor -- Zoom modem used with Dos configurator. +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.Hayes -- Only HayesVisitor is allowed to visit Hayes modem +09:15:11.127 [main] INFO com.iluwatar.acyclicvisitor.ConfigureForUnixVisitor -- Zoom modem used with Unix configurator. +``` + +## Verwendung + +* Wenn Sie zu einer bestehenden Hierarchie eine neue Funktion hinzufügen müssen, ohne die Hierarchie zu verändern. +* Wenn es Funktionen gibt, die zwar auf einer Hierarchie arbeiten, aber nicht selbst dazu gehören (Wie die Configure-Funktionen im obigen Beispiel). +* Wenn abhängig vom Objekttyp sehr unterschiedliche Funktionen auszuführen sind. +* Wenn die zu besuchende Klassenhierarchie häufig um neue Kindklassen erweitert wird. +* When the visited class hierarchy will be frequently extended with new derivatives of the Element class. +* Wenn es sehr aufwendig ist, die neuen Kindklassen zu kompilieren, zu verlinken, zu testen oder zu verteilen. + +## Tutorials + +* [The Acyclic Visitor Pattern (Code Crafter)](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html) + +## Vor- und Nachteile + +Vorteile: + +* Erweiterbarkeit: Neue Funktionen können leicht hinzugefügt werden, ohne die Objektstruktur zu verändern. +* Entkopplung: Kopplung zwischen Objekten und den auf ihnen stattfindenden Operationen wird reduziert. +* Keine Abhängigkeitszyklen: Abhängigkeiten sind azyklisch, Wartbarkeit verbessert sich, Komplexität wird reduziert. + +Nachteile: + +* Komplexität: Viele erforderliche Visitor-Interfaces können die Komplexität erhöhen. +* Wartbarkeit: Änderungen an der Objekthierarchie erfordern Updates aller Visitoren. + +## Verwandte Patterns + +* [Composite](https://java-design-patterns.com/patterns/composite/): +Wird oft zusammen mit Acyclic Visitor verwendet, um einzelne Objekte und Zusammensetzungen aus ihnen einheitlich zu behandeln. +* [Decorator](https://java-design-patterns.com/patterns/decorator/): +Can als Ergänzung eingesetzt werden, um Objekten Verantwortlichkeiten dynamisch zuzuweisen. +* [Visitor](https://java-design-patterns.com/patterns/visitor/): Acyclic Visitor ist eine Variante des Visitor Patterns, die zyklische Abhängigkeiten vermeidet. + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) +* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML](https://amzn.to/4bOtzwF) +* [Acyclic Visitor (Robert C. Martin)](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf) +* [Acyclic Visitor (WikiWikiWeb)](https://wiki.c2.com/?AcyclicVisitor) diff --git a/localization/de/adapter/README.md b/localization/de/adapter/README.md new file mode 100644 index 000000000000..301e7a881508 --- /dev/null +++ b/localization/de/adapter/README.md @@ -0,0 +1,168 @@ +--- +shortTitle: Adapter +category: Structural +language: de +tag: + - Compatibility + - Decoupling + - Gang of Four + - Interface + - Object composition + - Wrapping +--- + +## Alternativbezeichnung + +* Wrapper + +## Zweck + +Das Adapter-Pattern konvertiert die Schnittstelle einer Klasse in eine andere Schnittstelle, die zu den Bedürfnissen der Anwender passt, und sorgt so für Kompatibilität. + +## Detaillierte Erklärung +Vergleich mit der analogen Welt + +> Stellen Sie sich vor, Sie haben einige Bilder auf Ihrer Speicherkarte und wollen diese auf +> Ihren Computer übertragen. Dafür brauchen Sie einen Kartenleser, der mit den Anschlüssen des Rechners +> kompatibel ist, sodass dieser auf die Daten auf der Karten zugreifen kann. Dieser Kartenleser +> ist ein Beispiel für einen Adapter. +> Ein anderes Beispiel sind die Adapter, mit denen man deutsche Netzstecker in ausländischen +> Steckdosen verwenden kann, in die sie sonst nicht passen würden. Auch ein Übersetzer, der die +> Worte eines Sprechers in die Sprache des ausländischen Publikums übersetzt, erfüllt die Funktion eines Adapters. + +In einfachen Worten + +> Das Adapter-Pattern verpackt ein normalerweise inkompatibles Objekt so, dass es mit einer +> anderen Klasse kompatibel wird. + +Wikipedia sagt + +> Das Adapter-Pattern in der Softwareentwicklung ist ein Entwurfsmuster, +> das die Schnittstelle einer bestehenden Klasse im Rahmen einer neuen Schnittstelle nutzbar macht. +> Es wird oft verwendet, damit Klassen zusammenarbeiten können, ohne ihren Quellcode zu verändern. + +Ablaufdiagramm + +![Adapter sequence diagram](/adapter/etc/adapter-sequence-diagram.png "Adapter sequence diagram") + +## Programmbeispiel + +Betrachten wir einen Möchtegern-Kapität, der zwar rudern kann, aber noch nie gesegelt ist. + +Wir beginnen mit dem Interface `RowingBoat` und der Klasse `FishingBoat` + +```java +public interface RowingBoat { + void row(); +} + +public class FishingBoat { + public void sail() { + LOGGER.info("The fishing boat is sailing"); + } +} +``` + +Der Kapität erwartet, dass sich ein Schiff mit der `row`-Methode von `RowingBoat` steuern lässt. + +```java +public class Captain { + + private final RowingBoat rowingBoat; + + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; + } + + public void row() { + rowingBoat.row(); + } +} +``` + +Nun kommen Piraten und unser Kapitän muss fliehen, hat aber nur ein Fischerboot zur Verfügung. +Wir brauchen einen Adapter, mit dem er auch dieses Boot durch Rudern steuern kann. + +```java +public class FishingBoatAdapter implements RowingBoat { + + private final FishingBoat boat; + + public FishingBoatAdapter() { + boat = new FishingBoat(); + } + + @Override + public void row() { + boat.sail(); + } +} +``` + +Nun segelt das `FishingBoat`, indem der Kapitän rudert, und er kann fliehen. + +```java + public static void main(final String[] args) { + // The captain can only operate rowing boats but with adapter he is able to + // use fishing boats as well + var captain = new Captain(new FishingBoatAdapter()); + captain.row(); +} +``` + +Programmausgabe: + +``` +10:25:08.074 [main] INFO com.iluwatar.adapter.FishingBoat -- The fishing boat is sailing +``` + +## Verwendung +Das Adapter-Pattern ist geeignet für diese Fälle +* Sie wollen eine bestehende Klasse benutzen, deren Schnittstelle anders als benötigt ist. +* Sie wollen eine wiederverwendbare Klasse schreiben, die auch mit fremden Klassen zusammen + arbeiten kann, die nicht unbedingt kompatible Schnittstellen haben. +* Sie müssen verschiedene Tochterklassen verwenden, bei denen es zu aufwendig wäre, zu jeder einzelnen eine Subklasse mit angepasster Schnittstelle zu erstellen. + Ein Adapter kann die Schnittstelle der Elternklasse bedarfsgerecht anpassen. +* Die meisten Anwendungen, die Fremdbibliotheken verwenden, nutzen einen Adapter für die Fremdklassen, + um die eigenen Anwendung vom fremden zu entkoppeln. + +## Tutorials + +* [Using the Adapter Design Pattern in Java (Dzone)](https://dzone.com/articles/adapter-design-pattern-in-java) +* [Adapter in Java (Refactoring Guru)](https://refactoring.guru/design-patterns/adapter/java/example) +* [The Adapter Pattern in Java (Baeldung)](https://www.baeldung.com/java-adapter-pattern) +* [Adapter Design Pattern (GeeksForGeeks)](https://www.geeksforgeeks.org/adapter-pattern/) + +## Vor- und Nachteile + +Die Vor- und Nachteile hängen davon ab, ob ein Klassen- oder ein Objektadapter implementiert wird. + +Ein Klassenadapter adaptiert durch Bindung an eine spezifische zu adaptierende Klasse. +Er kann das Verhalten der zu adaptierenden Klasse überschreiben, weil er +als deren Tochterklasse implementiert wird. +Das hat allerdings zur Folge, dass mit einer Klasse nicht auch all ihre Subklassen adaptiert werden können. +Bei diesem Adaptertyp wird lediglich ein neues Objekt eingeführt, ohne +dass mit einem extra Zeiger der Zugriff darauf ermöglicht werden muss. + +Ein Objektadapter hingegen kann mit verschiedenen zu adaptierenden Klassen arbeiten, auch mit +allen Subklassen. Er kann allen adaptierten Klassen zugleich Funktionalität hinzufügen. +Allerdings wird es damit schwerer, das Verhalten zu überschreiben, weil man dafür eine +Subklasse der adaptierten Klasse benötigt und der Adapter sich auf diese Subklasse statt +auf die ursprünglich adaptierte Klasse beziehen muss. + +## Reale Java-Anwendungen + +* `java.io.InputStreamReader` and `java.io.OutputStreamWriter` in der Java-IO-Bibliothek. +* GUI-Komponentenbibliotheken, die per Plugin oder Adapter zwischen verschiedenen Kompontentenschnittstellen konvertieren können. +* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) +* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) +* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) +* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [J2EE Design Patterns](https://amzn.to/4dpzgmx) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) diff --git a/localization/de/bridge/README.md b/localization/de/bridge/README.md new file mode 100644 index 000000000000..a7cbedf82e41 --- /dev/null +++ b/localization/de/bridge/README.md @@ -0,0 +1,282 @@ +--- +shortTitle: Bridge +category: Structural +language: de +tag: + - Abstraction + - Decoupling + - Extensibility + - Gang of Four + - Object composition +--- + +## Alternativbezeichnung + +* Handle/Body + +## Zweck + +Das Bridge-Pattern ist ein Entwurfsmuster, das eine Abstraktion von ihrer Implementation +entkoppelt, wodurch beide unabhängig voneinander variieren können. +Es ist wesentlich, um flexible und erweiterbare Softwaresysteme zu bauen. + +## Detaillierte Erklärung + +Reales Beispiel + +> In Java wird das Bridge-Pattern oft verwendet für GUI-Frameworks, Datenbanktreiber und Gerätetreiber. +> +> Denken Sie an eine Universalfernbedienung (Abstraktion), die verschiedene Geräte diverser Marken +> (Implementationen) schalten kann. Die Fernbedienung stellt eine einheitliche Schnittstelle bereit für +> Aktionen wie Ein- und Ausschalten, Programmwechsel und Lautstärkeregelung. Diese Aktionen sind +> bei jedem einzelnen Gerät unterschiedlich implementiert. Mit dem Bridge-Pattern werden diese +> spezifischen Implementationen von der Fernbedienungsschnittstelle entkoppelt, sodass alle Geräte bedient +> unabhängig von Marke und interner Funktionsweise bedient werden können. Diese Trennung erlaubt es, +> dass neue Geräte mit der gleichen Fernbedienung ohne Änderung an deren Schnittstelle gesteuert werden können, +> oder dass neue Fernbedienungen für den gleichen Gerätepool entwickelt werden können. + +In einfachen Worten + +> Beim Bridge-Pattern geht es um den Vorrang von Komposition vor Vererbung. +> Details der Implementation werden aus einer Hierarchie in ein anderes Objekt mit separater Hierarchie verschoben. + +Wikipedia sagt + +> Das Bridge-Pattern ist ein Entwurfsmuster der Softwareentwicklung mit dem Zweck, +> eine Abstraktion von ihrer Implementierung zu trennen, so dass beide unabhängig voneinander angepasst werden können. + +Ablaufdiagramm + +![Bridge sequence diagram](/bridge/etc/bridge-sequence-diagram.png) + +## Programmbeispiel + +Stellen Sie sich vor, eine Waffe kann diverse Verzauberungen haben und sie müssen +verschiedene Waffen mit verschiedenen Verzauberungen kombinieren. Wie realisieren Sie das? +Imagine you have a weapon that can have various enchantments, and you need to combine +different weapons with different enchantments. How would you handle this? +Durch viele Versionen einer Waffe mit jeweils einem anderen Zauber, oder würden Sie separate +Verzauberungen definieren und diese nach Bedarf einer Waffe zuordnen? Das Bridge-Pattern macht letzteres möglich. + +Hier ist die `Weapon`-Hierarchie: + +```java +public interface Weapon { + void wield(); + + void swing(); + + void unwield(); + + Enchantment getEnchantment(); +} + +public class Sword implements Weapon { + + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The sword is swung."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} + +public class Hammer implements Weapon { + + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The hammer is swung."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} +``` + +Hier die separate `Enchantment`-Hierarchie: + +```java +public interface Enchantment { + void onActivate(); + + void apply(); + + void onDeactivate(); +} + +public class FlyingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); + } + + @Override + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); + } + + @Override + public void onDeactivate() { + LOGGER.info("The item's glow fades."); + } +} + +public class SoulEatingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); + } + + @Override + public void apply() { + LOGGER.info("The item eats the soul of enemies."); + } + + @Override + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); + } +} +``` + +Hier werden beide Hierarchien aktiv: + +```java +public static void main(String[] args) { + LOGGER.info("The knight receives an enchanted sword."); + var enchantedSword = new Sword(new SoulEatingEnchantment()); + enchantedSword.wield(); + enchantedSword.swing(); + enchantedSword.unwield(); + + LOGGER.info("The valkyrie receives an enchanted hammer."); + var hammer = new Hammer(new FlyingEnchantment()); + hammer.wield(); + hammer.swing(); + hammer.unwield(); +} +``` + +Dies ist die Ausgabe: + +``` +The knight receives an enchanted sword. +The sword is wielded. +The item spreads bloodlust. +The sword is swung. +The item eats the soul of enemies. +The sword is unwielded. +Bloodlust slowly disappears. +The valkyrie receives an enchanted hammer. +The hammer is wielded. +The item begins to glow faintly. +The hammer is swung. +The item flies and strikes the enemies finally returning to owner's hand. +The hammer is unwielded. +The item's glow fades. +``` + +## Verwendung + +Das Bridge-Pattern kommt in diesen Fällen in Betracht: + +* Eine dauerhafte Bindung zwischen Abstration und Implementierung soll vermieden werden, etwa + wenn die Implementation zur Laufzeit ausgewählt oder ausgewechselt werden muss. +* Sowohl Abstraktion als auch Implementationen sollen durch Vererbung erweitert werden können, + um unabhängige Erweiterungen jeder Komponente zu ermöglichen. +* Änderungen an der Implementation einer Abstraktion sollen die Verwender nicht beeinflussen, d.h. sie sollen nicht neu kompiliert werden müssen. +* Die Hierarchie enthält eine große Anzahl Klassen, was dafür spricht, Objekte in zwei Teile zu spalten. + Dieses Konzept wird von Rumbaugh als "verschachtelte Generalisierungen" bezeichnet. +* Sie wollen eine Implementation mit mehreren Objekten teilen, eventuell unter Verwendung von + Referenzzählern, dabei aber dieses Detail aber vor den Verwendern verstecken. Beispiel dafür + ist die String-Klasse von Coplien, wo mehrere Objekte die gleiche Stringdarstellung haben. + +## Tutorials + +* [Bridge Pattern Tutorial (DigitalOcean)](https://www.digitalocean.com/community/tutorials/bridge-design-pattern-java) + +## Reale Anwendungen in Java + +* In GUI-Frameworks ist das Fenster die Abstraktion, die Implementation die Fensterkonstruktion des Betriebssystem. +* Bei Datenbanktreibern ist die Abstraktion eine generische Datenbankschnittstelle, die Implementationen sind datenbankspezifische Treiber. +* Bei Gerätetreibern ist der geräteunabhängige Code die Abstraktion, die Implementation betrifft das einzelne Gerät. + +## Vor- und Nachteile + +Vorteile: + +* Entkopplung von Schnittstelle und Implementation: Durch Trennung von Operationen der höheren (Schnittstelle) und der niedrigeren Ebene (Implementation) verbessert sich die Modularität. +* Bessere Erweiterbarkeit: Abstraktions- und Implementationshierarchien können unabhängig voneinander erweitert werden. +* Versteckte Implementationsdetails: Verwender sehen nur die Schnittstelle, nicht ihre Implementation. + +Nachteile: + +* Höhere Komplexität: Systemarchitektur und Code können sich verkomplizieren, vor allem wenn man nicht mit dem Pattern vertraut ist. +* Laufzeitkosten: Die zusätzliche Abstraktionsschicht kann zu Performanceeinbußen führen, auch wenn das in der Praxis oft vernachlässigbar ist. + + +## Verwandte Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): + Das Abstract-Factory-Pattern kann zusammen mit dem Bridge-Pattern verwendet werden, um Plattformen zu schaffen, die unabhängig von den konkreten Klassen zur Objekterzeugung sind. +* [Adapter](https://java-design-patterns.com/patterns/adapter/): + Das Adapter-Pattern stellt eine neue Schnittstelle für ein Objekt zur Verfügung, + das Bridge-Pattern trennt die Schnittstelle des Objekts von der Implementation. +* [Composite](https://java-design-patterns.com/patterns/composite/): + Das Bridge-Pattern wird häufig mit dem Composite-Pattern verwendet, um die Implementationsdetails + einer Komponente zu modellieren. +* [Strategy](https://java-design-patterns.com/patterns/strategy/): + Beide Patterns verwenden Komposition: Strategy für Veränderungen am Verhalten einer Klasse, Bridge für die Trennung von Abstraktion und Implementation. + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) +* [Pattern-Oriented Software Architecture Volume 1: A System of Patterns](https://amzn.to/3TEnhtl) +* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR) diff --git a/localization/de/builder/README.md b/localization/de/builder/README.md new file mode 100644 index 000000000000..450132d23928 --- /dev/null +++ b/localization/de/builder/README.md @@ -0,0 +1,221 @@ +--- +shortTitle: Builder +language: de +tag: + - Gang of Four + - Instantiation + - Object composition +--- + +## Zweck + +Das Builder-Pattern ist ein fundamentales Erzeugungsmuster, mit dem komplexe Objekte schrittweise konstruiert werden. +Es trennt die Konstruktion eines komplexen Objekts von seiner Darstellung, sodass im gleichen +Konstruktionsprozess verschiedene Ausprägungen erzeugt werden können. + +## Detaillierte Erklärung + +Beispiel aus der realen Welt + +> Das Builder-Pattern ist besonders nützlich, wenn zur Erzeugung eines Objekts viele Parameter benötigt werden. +> +> Stellen Sie sich vor, Sie bestellen ein individuell zusammengestelltes Sandwich. +> Das Builder-Pattern stellt dafür einen SandwichBuilder bereit, mit dem Sie jede einzelne +> Komponente auswählen können (Brotart, Fleisch, Käse, Gemüse, Würzung). Sie müssen nicht +> wissen, wie man so ein Sandwich tatsächlich zusammenbaut. Es genügt, dass Sie Schritt für +> Schritt alle gewünschten Komponenten angeben, um genau das gewünschte Sandwich zu erhalten. +> Diese Trennung der Konstruktion vom fertigen Produkt stellt sicher, dass viele verschiedene +> Sandwichtypen aus den Komponenten konstruiert werden können. + +In einfachen Worten + +> Man kann verschiedene Formen eines Objekts erzeugen, ohne eine Vielzahl von Konstruktoren +> oder einen Konstruktor mit vielen Parametern zu benötigen. Nützlich, wenn ein Objekt in +> mehreren Geschmacksrichtungen auftauchen kann, oder wenn die Erzeugung des Objekts aus +> vielen Schritten besteht. + +Wikipedia sagt + +> Das Builder-Pattern ist ein Entwurfsmuster zur Objekterzeugung, das eine Lösung für +> das Telescoping-Constructor-Antipattern bieten will. + +Was hat es mit diesem Antipattern auf sich? +Irgendwann treffen wir alle auf solche Konstruktoren: + +```java +public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon){ + // Wertzuweisungen +} +``` +Sie sehen, die Zahl der Parameter im Konstruktor kann schnell unübersichtlich werden, so dass +schwer zu erkennen ist, welche benötigt werden und in welcher Reihenfolge sie stehen müssen. +Dieses Problem verstärkt sich, wenn später noch weitere Optionen hinzugefügt werden. +Dies wird als Telescoping-Constructor-Antipattern bezeichnet. + +Ablaufdiagramm + +![Builder sequence diagram](/builder/etc/builder-sequence-diagram.png) + +## Programmbeispiel + +In diesem Beispiel konstruieren wir verschiedene Typen von `Hero`-Objekten mit wechselnden Attributen. + +Stellen Sie sich einen Charakter-Generator in einem Rollenspiel vor. Die einfachste Option ist es, +den Charakter komplett vom Computer erstellen zu lassen. Manchmal will der Spieler aber selbst bestimmte +Eigenschaften des Charakters auswählen, etwa Beruf, Geschlecht, Haarfarbe etc. Dies ist ein schrittweiser Prozess, der erst abgeschlossen ist, wenn alle gewünschten Eigenschaften +festgelegt wurden. + +Mit dem Builder-Pattern gibt es einen besseren Ansatz dafür. +Betrachten wir zunächst den `Hero`, den wir erzeugen wollen: + +```java +public final class Hero { + private final Profession profession; + private final String name; + private final HairType hairType; + private final HairColor hairColor; + private final Armor armor; + private final Weapon weapon; + + private Hero(Builder builder) { + this.profession = builder.profession; + this.name = builder.name; + this.hairColor = builder.hairColor; + this.hairType = builder.hairType; + this.weapon = builder.weapon; + this.armor = builder.armor; + } +} +``` + +Dazu gibt es den `Builder`: + +```java + public static class Builder { + private final Profession profession; + private final String name; + private HairType hairType; + private HairColor hairColor; + private Armor armor; + private Weapon weapon; + + public Builder(Profession profession, String name) { + if (profession == null || name == null) { + throw new IllegalArgumentException("profession and name can not be null"); + } + this.profession = profession; + this.name = name; + } + + public Builder withHairType(HairType hairType) { + this.hairType = hairType; + return this; + } + + public Builder withHairColor(HairColor hairColor) { + this.hairColor = hairColor; + return this; + } + + public Builder withArmor(Armor armor) { + this.armor = armor; + return this; + } + + public Builder withWeapon(Weapon weapon) { + this.weapon = weapon; + return this; + } + + public Hero build() { + return new Hero(this); + } +} +``` + +Verwendet wird das Ganze dann so: + +```java + public static void main(String[] args) { + + var mage = new Hero.Builder(Profession.MAGE, "Riobard") + .withHairColor(HairColor.BLACK) + .withWeapon(Weapon.DAGGER) + .build(); + LOGGER.info(mage.toString()); + + var warrior = new Hero.Builder(Profession.WARRIOR, "Amberjill") + .withHairColor(HairColor.BLOND) + .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD) + .build(); + LOGGER.info(warrior.toString()); + + var thief = new Hero.Builder(Profession.THIEF, "Desmond") + .withHairType(HairType.BALD) + .withWeapon(Weapon.BOW) + .build(); + LOGGER.info(thief.toString()); +} +``` + +Programmausgabe: + +``` +16:28:06.058 [main] INFO com.iluwatar.builder.App -- This is a mage named Riobard with black hair and wielding a dagger. +16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a warrior named Amberjill with blond long curly hair wearing chain mail and wielding a sword. +16:28:06.060 [main] INFO com.iluwatar.builder.App -- This is a thief named Desmond with bald head and wielding a bow. +``` + +## Verwendung + +* Das Builder-Pattern ist ideal für Anwendungen, die komplexe Konstruktoren benötigen. +* Der Algorithmus zur Erzeugung eines komplexen Objekts sollte unabhängig davon sein, aus + welchen Elementen es besteht und wie diese zusammengesetzt werden. +* Der Konstruktionsprozess muss verschiedene Ausprägungen des konstruierten Objekts erlauben. +* Besonders nützlich, wenn viele Schritte zur Erzeugung benötigt werden, die in einer bestimmten + Reihenfolge ausgeführt werden müssen. + +## Tutorials + +* [Builder Design Pattern in Java (DigitalOcean)](https://www.journaldev.com/1425/builder-design-pattern-in-java) +* [Builder (Refactoring Guru)](https://refactoring.guru/design-patterns/builder) +* [Exploring Joshua Bloch’s Builder design pattern in Java (Java Magazine)](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) + +## Reale Anwendungen in Java + +* StringBuilder und StringBuffer konstruieren veränderbare String-Objekte +* Java.nio.ByteBuffer und ähnliche Klassen wie FloatBuffer, IntBuffer usw. +* javax.swing.GroupLayout.Group#addComponent() +* Verschiedene GUI-Builder in IDEs, die GUI-Komponenten bauen. +* Alle Implementationen von [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html) +* [Apache Camel Builder](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder) +* [Apache Commons Option.Builder](https://commons.apache.org/proper/commons-cli/apidocs/org/apache/commons/cli/Option.Builder.html) + +## Vor- und Nachteile + +Vorteile: + +* Bessere Kontrolle des Konstruktionsprozesses als bei anderen Erzeugungsmustern. +* Ermöglicht schrittweise Konstruktion, Verschiebung von Schritten und rekursiven Ablauf der Schritte. +* Kann Objekte konstruieren, die eine komplexe Zusammenstellung von Teilobjekten erfordern. + Dabei wird das Gesamtobjekt von den Teilen und dem Prozess des Zusammenfügens getrennt. +* Prinzip der eindeutigen Verantwortlichkeit: Komplexer Konstruktionscode kann von der Geschäftslogik getrennt werden. + +Nachteile: + +* Der Code kann insgesamt komplexer werden, weil zusätzliche Klassen benötigt werden. +* Durch die Builder-Objekte kann sich der Speicherverbrauch erhöhen. + +## Verwandte Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Kann gemeinsam mit Builder verwendet werden, um Teile eines komplexen Objekts zu generieren. +* [Prototype](https://java-design-patterns.com/patterns/prototype/): Builder bauen oft Prototypen nach. +* [Step Builder](https://java-design-patterns.com/patterns/step-builder/): Eine Variante des Builder-Patterns mit Schritt-für-Schritt-Ansatz. + Gute Wahl für Objekte mit einer Vielzahl optionaler Parameter. + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) diff --git a/localization/de/chain-of-responsibility/README.md b/localization/de/chain-of-responsibility/README.md new file mode 100644 index 000000000000..7f4e0f839705 --- /dev/null +++ b/localization/de/chain-of-responsibility/README.md @@ -0,0 +1,221 @@ +--- +shortTitle: Chain of Responsibility +category: Behavioral +language: de +tag: + - Decoupling + - Event-driven + - Gang of Four + - Messaging +--- + +## Alternativbezeichnungen + +* Chain of Command +* Chain of Objects +* Responsibility Chain +* deutsch: Zuständigkeitskette + +## Zweck + +Chain of Responsibility ist ein Verhaltensmuster, +das den Sender einer Anfrage von deren Empfängern entkoppelt, indem mehrere Objekte die +Gelegenheit zum Bearbeiten der Anfrage erhalten. Die empfangenden Objekte sind miteinander +verkettet und die Anfrage wird so lange entlang der Kette weitergereicht, bis ein Objekt +sie bearbeitet. + +## Detaillierte Erklärung + +Vergleichsbeispiel + +> Die Chain of Responsibility gleicht der Arbeit in einem Call-Center für technischen +Kundendienst. Jedes Support-Level entspricht einem Handler in der Kette. +Wenn ein Kunde wegen eines Problems anruft, landet der Anruf bei einem Mitarbeiter des ersten +Levels. Einfache Probleme kann dieser direkt lösen. Wenn der Fall schwieriger ist, leitet +er den Anruf an einen Second-Level-Kollegen weiter. Dieser Prozess läuft über verschiedene +Stufen so lange weiter, bis ein Fachmann gefunden wurde, der das Problem löst. +Indem der Anruf entlang der Kette bis zur passenden Stelle weitergereicht wird, +erreicht man eine Entkopplung zwischen der Anfrage (Anruf) und ihrem Empfänger (jeweiliger +Mitarbeiter). + +In einfachen Worten + +> Das Pattern hilft beim Bau einer Kette von Objekten. Eine Anfrage kommt auf einer Seite herein +und wird von einem Objekt zum nächsten weitergereicht, bis der passende Handler für sie gefunden ist. + +Wikipedia sagt + +> Das Design-Pattern Chain of Responsibility besteht aus einer Quelle für Befehlsobjekt +und einer Reihe von Bearbeiterobjekten. Jedes Bearbeiterobjekt enthält eine Entscheidungslogik, welche +Art von Befehlsobjekten es selbst bearbeiten kann. Die übrigen leitet es an das nächste +Objekt in der Kette weiter. + +Ablaufdiagramm + +![Chain of Responsibility flowchart](/chain-of-responsibility/etc/chain-of-responsibility-flowchart.png) + +## Programmbeispiel + +In diesem Java-Beispiel gibt der König der Orcs lautstarke Befehle an seine Armee, die von +einer Kette Untergebener ausgeführt werden. Am nächsten zum König steht sein General, +dann ein Offizier und schließlich ein einfacher Soldat. + +Zuerst definieren wir für die Befehle die Klasse `Request`. + +```java +public class Request { + + private final RequestType requestType; + private final String requestDescription; + private boolean handled; + + public Request(final RequestType requestType, final String requestDescription) { + this.requestType = Objects.requireNonNull(requestType); + this.requestDescription = Objects.requireNonNull(requestDescription); + } + + public void markHandled() { + this.handled = true; + } + + @Override + public String toString() { + return getRequestDescription(); + } +} + +public enum RequestType { + DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX +} +``` + +Hier sehen wir die Hierarchie der `RequestHandler`. + +```java +public interface RequestHandler { + + boolean canHandleRequest(Request req); + + int getPriority(); + + void handle(Request req); + + String name(); +} + +public class OrcCommander implements RequestHandler { + @Override + public boolean canHandleRequest(Request req) { + return req.getRequestType() == RequestType.DEFEND_CASTLE; + } + + @Override + public int getPriority() { + return 2; + } + + @Override + public void handle(Request req) { + req.markHandled(); + LOGGER.info("{} handling request \"{}\"", name(), req); + } + + @Override + public String name() { + return "Orc commander"; + } +} + +// OrcOfficer und OrcSoldier sind ähnlich definiert + +``` + +Der `OrcKing` gibt den Befehl und baut die Kette (geordnet nach Priorität) auf: + +```java +public class OrcKing { + + private List handlers; + + public OrcKing() { + buildChain(); + } + + private void buildChain() { + handlers = Arrays.asList(new OrcCommander(), new OrcOfficer(), new OrcSoldier()); + } + + public void makeRequest(Request req) { + handlers + .stream() + .sorted(Comparator.comparing(RequestHandler::getPriority)) + .filter(handler -> handler.canHandleRequest(req)) + .findFirst() + .ifPresent(handler -> handler.handle(req)); + } +} +``` + +Hier erhält die Kette verschiedene Befehle: + +```java + public static void main(String[] args) { + + var king = new OrcKing(); + king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle")); + king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner")); + king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); +} +``` + +Ausgabe: + +``` +Orc commander handling request "defend castle" +Orc officer handling request "torture prisoner" +Orc soldier handling request "collect tax" +``` + +## Verwendung + +* Wenn mehrere Objekte eine Anfrage bearbeiten können und der zuständige Verarbeiter nicht +vorab bekannt ist. Der Verarbeiter sollte automatisch ermittelt werden. +* Wenn eine Anfrage an eines von mehreren Objekten gesendet wird, ohne den Empfänger explizit festzulegen. +* Bei dynamischer Zusammenstellung der Menge möglicher Bearbeiter. + +## Reale Anwendungen in Java + +* Event-Bubbling in GUI-Frameworks, wo ein Event in verschiedenen Stufen der Komponentenhierachie bearbeitet werden kann. +* Middleware-Frameworks, bei denen Anfragen eine Kette möglicher Verarbeiter durchlaufen. +* Logging-Frameworks, bei denen Nachrichten eine Reihe von Loggern durchlaufen, von denen sie verschieden behandelt werden können. +* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29) +* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html) +* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-) + +## Vor- und Nachteile + +Vorteile: + +* Weniger Kopplung. Der Sender einer Anfrage muss nicht wissen, von wem diese bearbeitet wird. +* Flexibilität bei der Zuweisung von Verantwortlichkeiten durch Umbildung der Kette. +* Für den Fall, dass kein Kettenglied die Anfrage bearbeiten kann, kann ein Default-Verarbeiter festgelegt werden. + +Nachteile: + +* Bei langen und komplexen Ketten kann der Ablauf schwer zu durchschauen und zu debuggen sein. +* Eine Anfrage kann unbearbeitet bleiben, wenn ein passender Bearbeiter fehlt. +* Der (möglicherweise auch vergebliche) Durchlauf durch mehrere Verarbeiter kann die Peformance beeinträchtigen. + +## Verwandte Patterns + +* [Command](https://java-design-patterns.com/patterns/command/): Kann verwendet werden zur Kapselung der Anfrage in ein Objekt, das durch die Kette läuft. +* [Composite](https://java-design-patterns.com/patterns/composite/): Wird oft gemeinsam mit Chain of Responsibility verwendet. +* [Decorator](https://java-design-patterns.com/patterns/decorator/): Decorators können ähnlich wie Verantwortlichkeiten verkettet werden. + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PAJUg5) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) +* [Pattern languages of program design 3](https://amzn.to/4a4NxTH) diff --git a/localization/de/dependency-injection/README.md b/localization/de/dependency-injection/README.md new file mode 100644 index 000000000000..3717b59fbbb9 --- /dev/null +++ b/localization/de/dependency-injection/README.md @@ -0,0 +1,169 @@ +--- +shortTitle: Dependency Injection +category: Creational +language: de +tag: + - Decoupling + - Dependency management + - Inversion of control +--- + +## Alternativbezeichnungen + +* Inversion of Control (IoC) +* Dependency Inversion + +## Zweck + +Die Erzeugung der in einem Objekt benötigten Abhängigkeiten soll von der Verwendung entkoppelt werden. So wird der Code flexibler und testbarer. + +## Detaillierte Erklärung + +Beispiel aus dem echten Leben + +> Stellen Sie sich edles Restaurant vor, in dem der Koch diverse Zutaten für das Essen braucht. +> Er geht nicht für jede Zutat einzeln zu deren Hersteller, sondern bedient sich eines zuverlässigen +> Lieferanten, der ihm jeden Tag die Produkte frisch vom jeweiligen Hersteller besorgt. +> So kann er sich aufs Kochen konzentrieren und muss sich nicht mehr um den Einkauf kümmern. +> +> Im Dependency-Injection-Pattern fungiert der Lieferant als "Injektor", der die nötigen +> Abhängigkeiten (Zutaten) dem "Objekt" Koch zur Verfügung stellt. Der Koch kann die Zutaten +> verwenden, ohne deren Ursprung kennen zu müssen. Die Beschaffung und Verwendung der Abhängigkeiten +> sind also klar getrennt. Mit diesem Ansatz werden Effizienz, Flexibilität und Wartungsfreundlichkeit in der Küche verbessert, +> ebenso wie in einem Softwaresystem. + +In einfachen Worten + +> Dependency Injection trennt die Beschaffung der Abhängigkeiten vom eigenen Verhalten des Verwenders. + +Wikipedia sagt + +> In der Softwareentwicklung ist Dependency Injection eine Technik, mit der ein Objekt andere +> Objekte zugewiesen bekommt, die es benötigt. Diese anderen Objekte nennt man Abhängigkeiten (Dependencies). + +Ablaufdiagramm + +![Dependency Injection sequence diagram](/dependency-injection/etc/dependency-injection-sequence-diagram.png) + +## Programmbeispiel + +Der alte Hexenmeister möchte hin und wieder seine Pfeife stopfen und Tabak rauchen. +Dabei will er aber nicht von einer einzigen Tabakmarke abhängig sein, sondern die Marke wechseln können. + +Definieren wir also zunächst die Schnittstelle `Tobacco` und konkrete Klassen für die Marken. + +```java + +public abstract class Tobacco { + + public void smoke(Wizard wizard) { + LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(), + this.getClass().getSimpleName()); + } +} + +public class SecondBreakfastTobacco extends Tobacco { +} + +public class RivendellTobacco extends Tobacco { +} + +public class OldTobyTobacco extends Tobacco { +} +``` + +Als nächstes die `Wizard`-Klassenhierarchie. + +```java +public interface Wizard { + + void smoke(); +} + +public class AdvancedWizard implements Wizard { + + private final Tobacco tobacco; + + public AdvancedWizard(Tobacco tobacco) { + this.tobacco = tobacco; + } + + @Override + public void smoke() { + tobacco.smoke(this); + } +} +``` + +Schließlich sehen wir, wie leicht es ist, dem Hexenmeister jede beliebige Tabakmarke zu geben. + +```java +public static void main(String[] args) { + var simpleWizard = new SimpleWizard(); + simpleWizard.smoke(); + + var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); + + var advancedSorceress = new AdvancedSorceress(); + advancedSorceress.setTobacco(new SecondBreakfastTobacco()); + advancedSorceress.smoke(); + + var injector = Guice.createInjector(new TobaccoModule()); + var guiceWizard = injector.getInstance(GuiceWizard.class); + guiceWizard.smoke(); +} +``` + +Prorammausgabe: + +``` +11:54:05.205 [main] INFO com.iluwatar.dependency.injection.Tobacco -- SimpleWizard smoking OldTobyTobacco +11:54:05.207 [main] INFO com.iluwatar.dependency.injection.Tobacco -- AdvancedWizard smoking SecondBreakfastTobacco +11:54:05.207 [main] INFO com.iluwatar.dependency.injection.Tobacco -- AdvancedSorceress smoking SecondBreakfastTobacco +11:54:05.308 [main] INFO com.iluwatar.dependency.injection.Tobacco -- GuiceWizard smoking RivendellTobacco +``` + +## Verwendung + +* Wenn die Kopplung zwischen den Klassen reduziert und die Modularität der Anwendung erhöht werden soll +* In Szenarien, wo die Objekterzeugung komplex ist oder sonst von der Verwendung der Klasse getrennt werden soll. +* In Anwendungen, die einfacheres Texten durch Mocks oder Stubs benötigen. +* In Frameworks oder Bibliotheken, die den Lebenszyklus von Objekten managen, wie Spring oder Jakarta EE (früher Java EE). + +## Reale Anwendungen in Java + +* Frameworks wie Spring, Jakarta EE und Google Guice verwenden Dependency Injection (DI) + ausgiebig, um Lebenszyklen und Abhängigkeiten zu verwalten. +* Desktop- und Webanwendungen, die eine flexible Architektur mit leicht austauschbaren Komponenten benötigen. + +## Vor- und Nachteile + +Vorteile: + +* Verbessert die Modularität und Trennung von Zuständigkeiten. +* Vereinfacht Unit-Tests durch leichtes Mocken von Abhängigkeiten. +* Verbessert Flexibilität und Wartbarkeit durch Förderung von loser Kopplung. + +Nachteile: + +* Kann Konfiguration verkomplizieren, vor allem in großen Projekten. +* Entwickler, die mit dem Konzept nicht vertraut sind, müssen es erst erlernen. +* Erfordert sorgfältiges Management von Lebenzyklen und Gültigkeitsbereich der Objekte. + +## Verwandte Patterns + +* [Factory-Methoden](https://java-design-patterns.com/patterns/factory-method/) und [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Werden zur Erzeugung von Instanzen genutzt, die per DI injiziert werden. +* [Service Locator](https://java-design-patterns.com/patterns/service-locator/): Eine Alternative zu DI, um Dienste oder Komponenten zu finden, entkoppelt den Prozess aber nicht so effektiv. +* [Singleton](https://java-design-patterns.com/patterns/singleton/): Häufig Ergänzung zu DI, um eine einzige Instanz zu liefern. eines Service für die gesamte Anwendung zu liefern. + +## Quellen + +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://amzn.to/3wRnjp5) +* [Dependency Injection: Design patterns using Spring and Guice](https://amzn.to/4aMyHkI) +* [Dependency Injection Principles, Practices, and Patterns](https://amzn.to/4aupmxe) +* [Google Guice: Agile Lightweight Dependency Injection Framework](https://amzn.to/4bTDbX0) +* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://amzn.to/4ayCtxp) +* [Java Design Pattern Essentials](https://amzn.to/3xtPPxa) +* [Pro Java EE Spring Patterns: Best Practices and Design Strategies Implementing Java EE Patterns with the Spring Framework](https://amzn.to/3J6Teoh) +* [Spring in Action](https://amzn.to/4asnpSG) diff --git a/localization/de/fluent-interface/README.md b/localization/de/fluent-interface/README.md new file mode 100644 index 000000000000..0fe0ceda1355 --- /dev/null +++ b/localization/de/fluent-interface/README.md @@ -0,0 +1,216 @@ +--- +shortTitle: Fluent Interface +category: Behavioral +language: de +tag: + - API design + - Code simplification + - Decoupling + - Object composition + - Reactive +--- + +## Alternativbezeichnungen + +* Fluent API +* Method Chaining + +## Zweck + +Primäres Ziel des Fluent-Interface-Pattern ist es, eine gut lesbare sprechende API zur +Verfügung zu stellen, indem Methodenaufrufe einfach verkettet werden können (Method Chaining). +Dieser Ansatz ist ideal, um komplexe Objekte schrittweise zu bauen und generell ein angenehmeres +Programmiererlebnis zu erreichen. + +## Detaillierte Erklärung + +Vergleichsbeispiel + +> Die Bestellung eines frei konfigurierbaren Kaffees in einer Kaffeebar funktioniert ähnlich +> wie das Fluent-Interface-Pattern. +> Dabei teilen Sie dem Barista nicht all ihre Wünsche auf einmal mit, sondern nennen schrittweise +> eine Auswahl nach der anderen, in einem natürlichen Fluss. Sie sagen beispielsweise "Ich möchte +> einen großen großen Kaffee, mit zwei Espresso-Shots, ohne Zucker, plus Mandelmilch". +> Diese Aneinanderhängung von Wünschen entspricht dem Verketten von Methodenaufrufen +> beim Fluent-Interface-Pattern, wodurch der Code zu Objektkonfiguration intuitiv lesbar wird. +> So wie eine Kaffeekomponente nach der anderen ausgewählt wird, wird im Code eine Methode nach der anderen +> ausgeführt. + +In einfachen Worten: + +> Fluent Interface bietet eine sprechende, leicht lesbare Schnittstelle zum Code. + +Wikipedia sagt: + +> In der Softwareentwicklung ist Fluent Interface eine objektorientierte API, deren Design auf +> ausgiebiger Verkettung von Methoden beruht. Ziel ist verbesserte Lesbarkeit des Codes +> durch eine domänenspezifische Sprache (DSL, domain specific language). + +Ablaufdiagramm + +![Fluent Interface sequence diagram](/fluent-interface/etc/fluent-interface-sequence-diagram.png) + +## Programmbeispiel + +Wir wollen Zahlen aus einer Liste nach verschiedenen Kriterien auswählen. Dabei können +wir die Lesbarkeit des Codes gut mit dem Fluent-Interface-Pattern verbessern. + +Der Beispielcode enthält zwei Implementationen eines `FluentIterable`-Interfaces. + +```java +public interface FluentIterable extends Iterable { + + FluentIterable filter(Predicate predicate); + + Optional first(); + + FluentIterable first(int count); + + Optional last(); + + FluentIterable last(int count); + + FluentIterable map(Function function); + + List asList(); + + static List copyToList(Iterable iterable) { + var copy = new ArrayList(); + iterable.forEach(copy::add); + return copy; + } +} +``` + +`SimpleFluentIterable` betreibt eifrige Auswertung und wäre für eine reale Anwendung zu rechenintensiv. + +```java +public class SimpleFluentIterable implements FluentIterable { + // ... +} +``` +`LazyFluentIterable` wertet erst bei Terminierung der Kette aus. + +```java +public class LazyFluentIterable implements FluentIterable { + // ... +} +``` + +Ihre Verwendung zeigen wir mit einer simplen Zahlenliste, die gefiltert, transformiert +und zu einer neuen Liste zusammengestellt wird. Das Ergebnis wird anschließend ausgegeben. + +```java +public static void main(String[] args) { + + var integerList = List.of(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68); + + prettyPrint("The initial list contains: ", integerList); + + var firstThreeNegatives = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(negatives()) + .first(3) + .asList(); + prettyPrint("The first three negative values are: ", firstThreeNegatives); + + + var lastTwoPositives = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(positives()) + .last(2) + .asList(); + prettyPrint("The last two positive values are: ", lastTwoPositives); + + SimpleFluentIterable + .fromCopyOf(integerList) + .filter(number -> number % 2 == 0) + .first() + .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber)); + + + var transformedList = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(negatives()) + .map(transformToString()) + .asList(); + prettyPrint("A string-mapped list of negative numbers contains: ", transformedList); + + + var lastTwoOfFirstFourStringMapped = LazyFluentIterable + .from(integerList) + .filter(positives()) + .first(4) + .last(2) + .map(number -> "String[" + number + "]") + .asList(); + prettyPrint("The lazy list contains the last two of the first four positive numbers " + + "mapped to Strings: ", lastTwoOfFirstFourStringMapped); + + LazyFluentIterable + .from(integerList) + .filter(negatives()) + .first(2) + .last() + .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number)); +} +``` + +Programmausgabe: + +``` +08:50:08.260 [main] INFO com.iluwatar.fluentinterface.app.App -- The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68. +08:50:08.265 [main] INFO com.iluwatar.fluentinterface.app.App -- The first three negative values are: -61, -22, -87. +08:50:08.265 [main] INFO com.iluwatar.fluentinterface.app.App -- The last two positive values are: 23, 2. +08:50:08.266 [main] INFO com.iluwatar.fluentinterface.app.App -- The first even number is: 14 +08:50:08.267 [main] INFO com.iluwatar.fluentinterface.app.App -- A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68]. +08:50:08.270 [main] INFO com.iluwatar.fluentinterface.app.App -- The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6]. +08:50:08.270 [main] INFO com.iluwatar.fluentinterface.app.App -- Last amongst first two negatives: -22 +``` + +## Verwendung + +* Zum Entwurf vielgenutzter APIs, bei denen die Lesbarkeit des sie verwendenden Codes besonders wichtig ist. +* Zur schrittweisen Konstruktion komplexer Objekte mit intuitivem und weniger fehleranfälligem Code. +* Zur Verbesserung der Übersichtlichkeit des Codes und Reduktion von Boilerplate-Code, + speziell bei Konfigurationen und Objektkonstruktion. + +## Tutorials + +* [An Approach to Internal Domain-Specific Languages in Java (InfoQ)](http://www.infoq.com/articles/internal-dsls-java) + +## Reale Anwendungen in Java + +* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html) +* [Google Guava FluentIterable](https://github.com/google/guava/wiki/FunctionalExplained) +* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/) +* [Mockito](http://mockito.org/) +* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial) +* Builder in Bibliotheken wie Apache Camel für den Integrations-Workflow. + +## Vor- und Nachteile + +Vorteile: + +* Signifikant erhöhte Lesbarkeit und Wartbarkeit des Codes +* Unterstützt die Konstruktion unveränderlicher Objekte, weil die Methoden typischerweise neue Instanzen zurückgeben. +* Weniger Variablen nötig, da der Kontext durch die Aufrufkette klar wird. + +Nachteile: + +* Für Neulinge ist der Code weniger intuitiv. +* Verkettung von Methoden erschwert das Debuggen. +* Übermäßige Verwendung kann zu komplexem schwer wartbarem Code führen. + +## Verwandte Patterns + +* [Builder](https://java-design-patterns.com/patterns/builder/): Verwendet oft Fluent Interface zur schrittweisen Konstruktion. Bei Builder geht es um die Konstruktion komplexer Objekte, bei Fluent Interface um die Methodenverkettung. +* [Chain of Responsibility](https://java-design-patterns.com/patterns/chain-of-responsibility/): Fluent Interfaces können als spezielle Verwendung von Chain of Responsibility betrachtet werden, wo jede Methode in der Kette eine Teilaufgabe behandelt und ihr Ergebnis an die nächste Methode weiterreicht. + +## Quellen + +* [Domain-Driven Design: Tackling Complexity in the Heart of Software](https://amzn.to/3UrXkh2) +* [Domain Specific Languages](https://amzn.to/3R1UYDA) +* [Effective Java](https://amzn.to/4d4azvL) +* [Java Design Pattern Essentials](https://amzn.to/44bs6hG) +* [Fluent Interface (Martin Fowler)](http://www.martinfowler.com/bliki/FluentInterface.html) diff --git a/localization/de/singleton/README.md b/localization/de/singleton/README.md new file mode 100644 index 000000000000..6d27a16ee29d --- /dev/null +++ b/localization/de/singleton/README.md @@ -0,0 +1,114 @@ +--- +shortTitle: Singleton +category: Creational +language: de +tag: + - Gang of Four + - Instantiation + - Lazy initialization + - Resource management +--- + +## Alternativbezeichnung + +* Single Instance + +## Zweck + +Sicherstellen, dass es nur eine Instanz einer Klasse gibt, und einen globalen Zugriffspunkt auf diese Instanz bereitstellen. + +## Detaillierte Erklärung + +Analogie aus der Realität + +> Das Singleton-Pattern entspricht der Ausgabe von Pässen durch die Regierung. +> Jeder Bürger darf zu jeder Zeit nur einen Pass besitzen. Die Meldebehörde stellt sicher, +> dass niemandem ein zweiter Pass ausgestellt wird. +> Wenn ein Bürger ins Ausland reist, benötigt er seinen Pass, der als einzigartiger weltweit anerkannter Nachweis +> seiner Identität dient. + +In einfachen Worten + +> Es darf nur ein einziges Objekt dieser Klasse erzeugt werden. +> +Wikipedia sagt + +> In der Softwareentwicklung ist das Singleton ein Entwurfsmuster, das die Instanziierung einer +> Klasse auf ein einziges Objekt beschränkt. +> Dies ist sinnvoll, wenn genau ein Objekt benötigt wird, das Aktionen über das gesamte System +> hinweg koordiniert. + +Ablaufdiagramm + +![Singleton Pattern sequence diagram](/singleton/etc/singleton-sequence-diagram.png) + +## Programmbeispiel + +vgl. Joshua Bloch, Effective Java 2nd Edition, Seite 18 + +> Die beste Art der Implementation eines Singletons ist ein Enum mit nur einem Element. + +```java +public enum EnumIvoryTower { + INSTANCE +} +``` + +So wird es verwendet: + +```java + var enumIvoryTower1 = EnumIvoryTower.INSTANCE; + var enumIvoryTower2 = EnumIvoryTower.INSTANCE; + LOGGER.info("enumIvoryTower1={}", enumIvoryTower1); + LOGGER.info("enumIvoryTower2={}", enumIvoryTower2); +``` + +Ausgabe in der Konsole: + +``` +enumIvoryTower1=com.iluwatar.singleton.EnumIvoryTower@1221555852 +enumIvoryTower2=com.iluwatar.singleton.EnumIvoryTower@1221555852 +``` + +## Verwendung + +Ein Singleton sollte verwendet werden, wenn +* genau eine Instanz der Klasse benötigt wird, die für Nutzer über einen wohldefinierten Zugriffspunkt erreichbar ist. +* es möglich sein soll, diese Klasse durch Vererbung zu erweitern, ohne dass bei Verwendung der erweiterten Instanz Codeänderungen nötig sind. + +## Reale Anwendungen in Java + +* Logging-Klassen +* Konfigurationsklassen in vielen Anwendungen +* Verbindungspools +* Dateimanager +* [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) +* [java.awt.Desktop#getDesktop()](http://docs.oracle.com/javase/8/docs/api/java/awt/Desktop.html#getDesktop--) +* [java.lang.System#getSecurityManager()](http://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getSecurityManager--) + +## Vor- und Nachteile +Vorteile: +* Kontrollierter Zugriff auf die einzige Instanz. +* Namensraum wird nicht unnötig belastet. +* Operationen und Darstellungen können durch Vererbung verfeinert werden. +* Bei Bedarf auch mehrere Instanzen möglich. +* Flexibler als Klassenoperationen + +Nachteile: +* Schwierig zu testen wegen globalem Status. +* Möglicherweise komplexeres Lebenszyklusmanagement. +* Bei Parallelität sind ohne sorgfältige Synchronisierung Engpässe möglich. + +## Verwandte Patterns + +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/): Oft verwendet, um sicherzustellen, dass nur eine Instanz existiert. +* [Factory Methoden](https://java-design-patterns.com/patterns/factory-method/): Das Singleton-Pattern kann implementiert werden, indem über eine Factory-Methode die Instanzerzeugung gekapselt wird. +* [Prototyp](https://java-design-patterns.com/patterns/prototype/): Hier müssen keine Instanzen erzeugt werden. Das Pattern kann zusammen mit dem Singleton verwendet werden, um einzige Instanzen zu verwalten. + +## Quellen + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) diff --git a/localization/de/step-builder/README.md b/localization/de/step-builder/README.md new file mode 100644 index 000000000000..cdcb0b6ee9ac --- /dev/null +++ b/localization/de/step-builder/README.md @@ -0,0 +1,218 @@ +--- +shortTitle: Step Builder +category: Creational +language: de +tag: + - Code simplification + - Domain + - Encapsulation + - Extensibility + - Instantiation + - Interface +--- + +## Alternativbezeichnung + +* Fluent Builder + +## Zweck + +Das Step-Builder-Pattern ist eine erweiterte Technik, um komplexe Objekte übersichtlich und flexibel +zu erzeugen. Es ist ideal für Szenarien, in denen die Objekterzeugung schrittweise und äußerst genau zu erfolgen hat. + +## Detaillierte Erklärung + +Vergleichsbeispiel: + +> Betrachten wir den Zusammenbau eines individuell konfigurierten Computers. +Dafür sind mehrere Schritte nötig: Die CPU muss ausgewählt werden, ein Motherboard, dazu kommen +Arbeitsspeicher, Grafikkarte und Festplatte, die nach und nach ins Gehäuse eingebaut werden müssen. +Jeder Schritt folgt auf den anderen, bis schließlich ein funktionsfähiger Rechner entsteht. +Dieser schrittweise Konstruktionsprozess entspricht dem Step-Builder-Pattern und sorgt dafür, +dass alle nötigen Komponenten richtig zusammengebaut werden und anforderungsgemäß funktionieren. + +In einfachen Worten + +> Das Step-Builder-Pattern konstruiert komplexe Objekte nach und nach durch eine Reihe +definierter Schritte. Das macht den Vorgang übersichtlich und flexibel. + +Wikipedia sagt + +> Step Builder ist eine Variante des Builder-Patterns mit dem Ziel, eine flexible Lösung +zur schrittweisen Konstruktion komplexer Objekte anzubieten. Sie ist besonders hilfreich, +wenn ein Objekt viele Initialisierungsschritte benötigt, die der Klarheit und Flexibilität wegen +einzeln abgearbeitet werden können. + +Ablaufdiagramm + +![Step Builder Ablaufdiagramm](/step-builder/etc/step-builder-sequence-diagram.png) + +## Programmbeispiel + +Als Erweiterung des Builder-Patterns führt Step Builder den Nutzer Schritt für Schritt durch +den Erzeugungsprozess eines Objekts. Es werden immer nur die nächsten verfügbaren Schritte +angezeigt, und die build-Methode ist erst dann verfügbar, wenn das Objekt tatsächlich bereit +zum Bau ist. + +Betrachten wir eine Klasse `Character` mit vielen Attributen wie `name`, `fighterClass`, +`wizardClass`, `weapon`, `spell`, und `abilities`. + +```java +public class Character { + + private String name; + private String fighterClass; + private String wizardClass; + private String weapon; + private String spell; + private List abilities; + + public Character(String name) { + this.name = name; + } + +} +``` + +Die Konstruktion ist wegen der vielen Attribute komplex. Darum verwenden wir Step Builder. + +Wir schreiben eine Klasse `CharacterStepBuilder`, um den Benutzer durch den Konstruktionsprozess zu führen. + +```java +public class CharacterStepBuilder { + + // neuer Builder startet mit dem Schritt Namensvergabe + public static NameStep newBuilder() { + return new CharacterSteps(); + } + +} +``` + +Die Klasse `CharacterStepBuilder` enthält eine Reihe von Interfaces, +die jeweils einen Schritt des Konstruktionsprozesses repräsentieren. Indem jedes Interface +eine Methode für den folgenden Schritt deklariert, wird der Benutzer durch den Prozess geführt. + +```java +// nach der Namensvergabe kommt die Auswahl der wizardClass oder fighterClass +public interface NameStep { + ClassStep name(String name); +} +``` + +```java +// nach der Klassenwahl wird entweder eine Waffe oder ein Zauberspruch zugewiesen +public interface ClassStep { + WeaponStep fighterClass(String fighterClass); + SpellStep wizardClass(String wizardClass); +} + +// Weitere Schritte weggelassen +``` + +Die Klasse `Steps` implementiert all diese Interfaces und baut schließlich das `Character`-Object. + +```java +private static class Steps implements NameStep, ClassStep, WeaponStep, SpellStep, BuildStep { + + private String name; + private String fighterClass; + private String wizardClass; + private String weapon; + private String spell; + private List abilities; + + // Die Implementationen der Methoden für die einzelnen Schritte sind hier weggelassen + + @Override + public Character build() { + return new Character(name, fighterClass, wizardClass, weapon, spell, abilities); + } +} +``` + +Jetzt ist die Erzeugung eines `Character`-Objekts ein geführter Prozess. + +```java +public static void main(String[] args) { + + var warrior = CharacterStepBuilder + .newBuilder() + .name("Amberjill") + .fighterClass("Paladin") + .withWeapon("Sword") + .noAbilities() + .build(); + + LOGGER.info(warrior.toString()); + + var mage = CharacterStepBuilder + .newBuilder() + .name("Riobard") + .wizardClass("Sorcerer") + .withSpell("Fireball") + .withAbility("Fire Aura") + .withAbility("Teleport") + .noMoreAbilities() + .build(); + + LOGGER.info(mage.toString()); + + var thief = CharacterStepBuilder + .newBuilder() + .name("Desmond") + .fighterClass("Rogue") + .noWeapon() + .build(); + + LOGGER.info(thief.toString()); +} +``` + +Konsolenausgabe: + +``` +12:58:13.887 [main] INFO com.iluwatar.stepbuilder.App -- This is a Paladin named Amberjill armed with a Sword. +12:58:13.889 [main] INFO com.iluwatar.stepbuilder.App -- This is a Sorcerer named Riobard armed with a Fireball and wielding [Fire Aura, Teleport] abilities. +12:58:13.889 [main] INFO com.iluwatar.stepbuilder.App -- This is a Rogue named Desmond armed with a with nothing. +``` + +## Verwendung + +* Wenn die Konstruktion eines Objekts viele Initialisierungsschritte benötigt. +* Wenn die Objektkonstruktion komplex ist und viele Parameter enthält. +* Um einen übersichtlichen, lesbaren und wartbaren Objekterzeugungsprozess bereitzustellen. + +## Tutorials + +* [Step Builder (Marco Castigliego)](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html) + +## Reale Anwendungen in Java +* Komplexe Konfigurationseinstellungen in Java-Anwendungen. +* Konstruktion von Objekten für Datenbankeinträge mit vielen Feldern. +* Konstruktion von GUI-Elementen, wo jeder Schritt einen anderen Teil der Schnittstelle festlegt. + +## Vor- und Nachteile + +Vorteile + +* Code wird lesbarer und wartbarer durch übersichtliche und prägnante Objektkonstruktion. +* Erhöhte Flexibilität bei der Objekterzeugung durch Varianten im Konstruktionsprozess. +* Unterstützt unveränderbare Objekte durch Abtrennung ihrer Erzeugung.ntation. + +Nachteile + +* Code kann durch zusätzliche Klassen und Interfaces komplexer werden. +* Langatmiger Code bei vielen Konstruktionsschritten. + +## Verwandte Patterns + +* [Builder](https://java-design-patterns.com/patterns/builder/): Beide Patterns dienen der Konstruktion komplexer Objekte. Step Builder ist eine Variante mit Betonung auf schrittweisem Vorgehen. +* [Fluent Interface](https://java-design-patterns.com/patterns/fluentinterface/): Wird oft zusammen mit Step Builder verwendet, um eine sprechende API mit Methodenverkettung zur Konstruktion bereitzustellen. +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Wird manchmal im Step-Builder-Pattern genutzt, um die Konstruktion des Builders selbst zu kapseln. + +## Quellen + +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://amzn.to/3wRnjp5) +* [Effective Java](https://amzn.to/4cGk2Jz) +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) From 394aff8ac6ff6bc415be68447f7f695bd4983798 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:21:02 +0300 Subject: [PATCH 056/108] docs: add sieberss as a contributor for translation (#3506) * 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 00b30de4eb62..0ceed882e35a 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3674,6 +3674,15 @@ "contributions": [ "doc" ] + }, + { + "login": "sieberss", + "name": "Stefan Siebers", + "avatar_url": "https://avatars.githubusercontent.com/u/178474619?v=4", + "profile": "https://github.com/sieberss", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index e96fba482b54..adb4c7591cb2 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-403-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-404-orange.svg?style=flat-square)](#contributors-)
@@ -598,6 +598,7 @@ This project is licensed under the terms of the MIT license.
Dhiraj Birajdar
Dhiraj Birajdar

📖 + Stefan Siebers
Stefan Siebers

🌍 From 2c0228971136c56e6a7763c3f131cb5a4fa52d66 Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Wed, 3 Jun 2026 23:02:57 +0530 Subject: [PATCH 057/108] fix: V-001 security vulnerability (#3461) Automated security fix generated by Orbis Security AI Co-authored-by: Ubuntu --- page-object/src/main/java/com/iluwatar/pageobject/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page-object/src/main/java/com/iluwatar/pageobject/App.java b/page-object/src/main/java/com/iluwatar/pageobject/App.java index a0eda082f726..214858cdcb53 100644 --- a/page-object/src/main/java/com/iluwatar/pageobject/App.java +++ b/page-object/src/main/java/com/iluwatar/pageobject/App.java @@ -77,7 +77,7 @@ public static void main(String[] args) { } else { // Java Desktop not supported - above unlikely to work for Windows so try the // following instead... - Runtime.getRuntime().exec("cmd.exe start " + applicationFile); + new ProcessBuilder("cmd.exe", "/c", "start", "", applicationFile.getAbsolutePath()).start(); } } catch (IOException ex) { From a0a10b300bdcec0bfd3cb4759c702346d0bfb6b6 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:33:35 +0300 Subject: [PATCH 058/108] docs: add orbisai0security as a contributor for security (#3507) * 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 0ceed882e35a..3ade6027312e 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3683,6 +3683,15 @@ "contributions": [ "translation" ] + }, + { + "login": "orbisai0security", + "name": "OrbisAI Security", + "avatar_url": "https://avatars.githubusercontent.com/u/242526317?v=4", + "profile": "https://orbisappsec.com/", + "contributions": [ + "security" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index adb4c7591cb2..6283ddf90255 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-404-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-405-orange.svg?style=flat-square)](#contributors-)
@@ -599,6 +599,7 @@ This project is licensed under the terms of the MIT license. Dhiraj Birajdar
Dhiraj Birajdar

📖 Stefan Siebers
Stefan Siebers

🌍 + OrbisAI Security
OrbisAI Security

🛡️ From f5bd0380d5b79eaab1aea7335c07ed698dad3d1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:40:39 +0300 Subject: [PATCH 059/108] build(deps-dev): bump org.apache.maven.plugins:maven-war-plugin (#3431) Bumps [org.apache.maven.plugins:maven-war-plugin](https://github.com/apache/maven-war-plugin) from 3.4.0 to 3.5.1. - [Release notes](https://github.com/apache/maven-war-plugin/releases) - [Commits](https://github.com/apache/maven-war-plugin/compare/maven-war-plugin-3.4.0...maven-war-plugin-3.5.1) --- updated-dependencies: - dependency-name: org.apache.maven.plugins:maven-war-plugin dependency-version: 3.5.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- model-view-viewmodel/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model-view-viewmodel/pom.xml b/model-view-viewmodel/pom.xml index 248eb9e7d507..e77d53ef7396 100644 --- a/model-view-viewmodel/pom.xml +++ b/model-view-viewmodel/pom.xml @@ -37,7 +37,7 @@ 10.0.0-jakarta 11.0.24 - 3.4.0 + 3.5.1 yyyy-MM-dd -${project.version}-FL-${maven.build.timestamp} From 4215c86de090e9bff31d1a9afe92ca9db6f7a1e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:42:07 +0300 Subject: [PATCH 060/108] build(deps-dev): bump org.assertj:assertj-core in /bloc (#3426) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.3 to 3.27.7. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.3...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- bloc/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bloc/pom.xml b/bloc/pom.xml index cc52a3b99dc2..021fbaafeb8d 100644 --- a/bloc/pom.xml +++ b/bloc/pom.xml @@ -50,7 +50,7 @@ org.assertj assertj-core - 3.27.3 + 3.27.7 test From 51b03f1137e8f5d6170246fbdd5cb4b4990c4eb3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:43:15 +0300 Subject: [PATCH 061/108] build(deps): bump ch.qos.logback:logback-core in /subclass-sandbox (#3380) Bumps [ch.qos.logback:logback-core](https://github.com/qos-ch/logback) from 1.5.18 to 1.5.19. - [Release notes](https://github.com/qos-ch/logback/releases) - [Commits](https://github.com/qos-ch/logback/compare/v_1.5.18...v_1.5.19) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-core dependency-version: 1.5.19 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 9d21c7400f09..a22acb7f716f 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -35,7 +35,7 @@ subclass-sandbox 2.0.17 - 1.5.18 + 1.5.19 From 5ff41687dfa081db15b7d59c2d3e3b75f1ce413f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:48:17 +0300 Subject: [PATCH 062/108] build(deps): bump org.apache.commons:commons-lang3 in /double-buffer (#3304) Bumps org.apache.commons:commons-lang3 from 3.17.0 to 3.18.0. --- updated-dependencies: - dependency-name: org.apache.commons:commons-lang3 dependency-version: 3.18.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- double-buffer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/double-buffer/pom.xml b/double-buffer/pom.xml index ad5bf6c3e314..af19d486f9ee 100644 --- a/double-buffer/pom.xml +++ b/double-buffer/pom.xml @@ -45,7 +45,7 @@ org.apache.commons commons-lang3 - 3.17.0 + 3.18.0 org.junit.jupiter From 8b0cf692cfd77cb2ac169db26750248809d13657 Mon Sep 17 00:00:00 2001 From: Raju Gupta <64011583+rranjangupta@users.noreply.github.com> Date: Wed, 3 Jun 2026 23:29:52 +0530 Subject: [PATCH 063/108] feat: Add test coverage for single-table-inheritance pattern (#3468) * Add STI tests * test: add delta for floating-point comparison in VehicleServiceTest * fix: guard teardown against nulls and use assertNotNull in VehicleServiceTest Add null checks in @AfterEach tearDown() to prevent NullPointerException if setUp() partially fails. Replace assertTrue(x != null) with assertNotNull(x). * style: format code in SingleTableInheritanceTest and VehicleServiceTest for consistency --- .../iluwatar/SingleTableInheritanceTest.java | 38 +++++ .../iluwatar/service/VehicleServiceTest.java | 161 ++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java create mode 100644 single-table-inheritance/src/test/java/com/iluwatar/service/VehicleServiceTest.java diff --git a/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java b/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java new file mode 100644 index 000000000000..8c4415cf4bfd --- /dev/null +++ b/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.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; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** Tests that SingleTableInheritance example application runs without errors. */ +class SingleTableInheritanceTest { + + @Test + void shouldExecuteWithoutException() { + assertDoesNotThrow(() -> SingleTableInheritance.main(new String[] {})); + } +} diff --git a/single-table-inheritance/src/test/java/com/iluwatar/service/VehicleServiceTest.java b/single-table-inheritance/src/test/java/com/iluwatar/service/VehicleServiceTest.java new file mode 100644 index 000000000000..2bff4b354627 --- /dev/null +++ b/single-table-inheritance/src/test/java/com/iluwatar/service/VehicleServiceTest.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.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import com.iluwatar.entity.Car; +import com.iluwatar.entity.Freighter; +import com.iluwatar.entity.Train; +import com.iluwatar.entity.Truck; +import com.iluwatar.entity.Vehicle; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +/** + * Tests for {@link VehicleService} exercising CRUD operations and verifying that all concrete + * Vehicle subtypes are persisted and retrieved correctly via the single-table inheritance strategy. + */ +@SpringBootTest +class VehicleServiceTest { + + private static final double DELTA = 0.001; + + @Autowired private VehicleService vehicleService; + + private Vehicle savedCar; + private Vehicle savedTruck; + private Vehicle savedTrain; + private Vehicle savedFreighter; + + @BeforeEach + void setUp() { + savedCar = vehicleService.saveVehicle(new Car("Tesla", "Model S", 4, 825)); + savedTruck = vehicleService.saveVehicle(new Truck("Ford", "F-150", 3325, 14000)); + savedTrain = vehicleService.saveVehicle(new Train("Siemens", "Velaro", 600, 8)); + savedFreighter = vehicleService.saveVehicle(new Freighter("Boeing", "747F", 100000, 8130)); + } + + @AfterEach + void tearDown() { + if (savedCar != null) vehicleService.deleteVehicle(savedCar); + if (savedTruck != null) vehicleService.deleteVehicle(savedTruck); + if (savedTrain != null) vehicleService.deleteVehicle(savedTrain); + if (savedFreighter != null) vehicleService.deleteVehicle(savedFreighter); + } + + @Test + void saveVehicle_shouldPersistCarWithCorrectType() { + assertTrue(savedCar.getVehicleId() > 0); + assertInstanceOf(Car.class, savedCar); + assertEquals("Tesla", savedCar.getManufacturer()); + assertEquals("Model S", savedCar.getModel()); + assertEquals(825, ((Car) savedCar).getEngineCapacity()); + } + + @Test + void saveVehicle_shouldPersistTruckWithCorrectType() { + assertTrue(savedTruck.getVehicleId() > 0); + assertInstanceOf(Truck.class, savedTruck); + assertEquals(14000, ((Truck) savedTruck).getTowingCapacity()); + } + + @Test + void saveVehicle_shouldPersistTrainWithCorrectType() { + assertTrue(savedTrain.getVehicleId() > 0); + assertInstanceOf(Train.class, savedTrain); + assertEquals(8, ((Train) savedTrain).getNoOfCarriages()); + } + + @Test + void saveVehicle_shouldPersistFreighterWithCorrectType() { + assertTrue(savedFreighter.getVehicleId() > 0); + assertInstanceOf(Freighter.class, savedFreighter); + assertEquals(8130.0, ((Freighter) savedFreighter).getFlightLength(), DELTA); + } + + @Test + void getVehicle_shouldReturnCorrectVehicleById() { + Vehicle fetched = vehicleService.getVehicle(savedCar.getVehicleId()); + + assertNotNull(fetched); + assertInstanceOf(Car.class, fetched); + assertEquals(savedCar.getVehicleId(), fetched.getVehicleId()); + } + + @Test + void getVehicle_shouldReturnNullForNonexistentId() { + Vehicle result = vehicleService.getVehicle(Integer.MAX_VALUE); + assertNull(result); + } + + @Test + void getAllVehicles_shouldReturnAllSavedVehicles() { + List all = vehicleService.getAllVehicles(); + assertNotNull(all); + // At minimum the 4 vehicles saved in @BeforeEach must be present + assertTrue_containsId(all, savedCar.getVehicleId()); + assertTrue_containsId(all, savedTruck.getVehicleId()); + assertTrue_containsId(all, savedTrain.getVehicleId()); + assertTrue_containsId(all, savedFreighter.getVehicleId()); + } + + @Test + void updateVehicle_shouldPersistChanges() { + Car car = (Car) savedCar; + car.setModel("Model X"); + vehicleService.updateVehicle(car); + + Vehicle updated = vehicleService.getVehicle(car.getVehicleId()); + assertEquals("Model X", updated.getModel()); + } + + @Test + void deleteVehicle_shouldRemoveFromRepository() { + // Save a temporary vehicle and delete it + Vehicle tmp = vehicleService.saveVehicle(new Car("BMW", "M3", 4, 3000)); + int tmpId = tmp.getVehicleId(); + + vehicleService.deleteVehicle(tmp); + + assertNull(vehicleService.getVehicle(tmpId)); + } + + // Helper: assert that a specific vehicle id exists in the list + private void assertTrue_containsId(List vehicles, int id) { + boolean found = vehicles.stream().anyMatch(v -> v.getVehicleId() == id); + if (!found) { + throw new AssertionError("Expected vehicle with id=" + id + " in list but was not found."); + } + } +} From 12887208937be8a6be88531f90959530947046e8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:00:32 +0300 Subject: [PATCH 064/108] docs: add rranjangupta as a contributor for code (#3508) * 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 3ade6027312e..865843b00c0c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3692,6 +3692,15 @@ "contributions": [ "security" ] + }, + { + "login": "rranjangupta", + "name": "Raju Gupta", + "avatar_url": "https://avatars.githubusercontent.com/u/64011583?v=4", + "profile": "https://www.rajugupta.com/portfolio/", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 6283ddf90255..18d804739aef 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-405-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-406-orange.svg?style=flat-square)](#contributors-)
@@ -600,6 +600,7 @@ This project is licensed under the terms of the MIT license. Dhiraj Birajdar
Dhiraj Birajdar

📖 Stefan Siebers
Stefan Siebers

🌍 OrbisAI Security
OrbisAI Security

🛡️ + Raju Gupta
Raju Gupta

💻 From d4a0ece9e39ca1da34900878f151fb7f98e5d3c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:03:39 +0300 Subject: [PATCH 065/108] build(deps-dev): bump org.assertj:assertj-core in /health-check (#3438) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.3 to 3.27.7. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.3...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- health-check/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-check/pom.xml b/health-check/pom.xml index 203503ad03b6..8019d9a15f2c 100644 --- a/health-check/pom.xml +++ b/health-check/pom.xml @@ -94,7 +94,7 @@ org.assertj assertj-core - 3.27.3 + 3.27.7 test From 7473378ca226540c921362be627ed73903eccb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=A0=95=EB=AA=A8?= <116088682+alex052525@users.noreply.github.com> Date: Sun, 7 Jun 2026 04:05:42 +0900 Subject: [PATCH 066/108] feat: implement Immutable pattern (Fixes #3448) (#3509) * feat: implement Immutable pattern #3448 Add immutable/ module with ImmutableUser (final class, defensive copy, withAge wither method), App demo, JUnit 5 tests, PlantUML diagram, and README following project conventions. Co-Authored-By: Claude Sonnet 4.6 * feat: add withName and withRoles wither methods to ImmutableUser #3448 Every field now has a corresponding wither for consistency. Co-Authored-By: Claude Sonnet 4.6 * fix: add junit-jupiter-api dependency to immutable module #3448 Required for @Test annotations and assert methods in test code. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- immutable/README.md | 133 ++++++++++++++++++ immutable/etc/immutable.urm.puml | 21 +++ immutable/pom.xml | 76 ++++++++++ .../main/java/com/iluwatar/immutable/App.java | 61 ++++++++ .../com/iluwatar/immutable/ImmutableUser.java | 116 +++++++++++++++ .../iluwatar/immutable/ImmutableUserTest.java | 123 ++++++++++++++++ pom.xml | 1 + 7 files changed, 531 insertions(+) create mode 100644 immutable/README.md create mode 100644 immutable/etc/immutable.urm.puml create mode 100644 immutable/pom.xml create mode 100644 immutable/src/main/java/com/iluwatar/immutable/App.java create mode 100644 immutable/src/main/java/com/iluwatar/immutable/ImmutableUser.java create mode 100644 immutable/src/test/java/com/iluwatar/immutable/ImmutableUserTest.java diff --git a/immutable/README.md b/immutable/README.md new file mode 100644 index 000000000000..3d780ccf3109 --- /dev/null +++ b/immutable/README.md @@ -0,0 +1,133 @@ +--- +title: "Immutable Pattern in Java: Building Thread-Safe Objects" +shortTitle: Immutable +description: "Learn the Immutable pattern in Java with real-world examples, class diagrams, and tutorials. Understand how to create objects that cannot be modified after construction." +category: Idiom +language: en +tag: + - Immutability + - Thread safety + - Concurrency + - Object composition +--- + +## Also known as + +Value Object (when applied strictly to small domain values) + +## Intent of Immutable Design Pattern + +Ensure that an object's state cannot be changed after it is constructed, making it inherently thread-safe and easier to reason about. + +## Detailed Explanation of Immutable Pattern with Real-World Examples + +Real-world example + +> A birth certificate is a perfect real-world analogy for the Immutable pattern. Once issued, a birth certificate records a person's name, date of birth, and place of birth permanently. You cannot alter the certificate itself; if a legal correction is needed, a new certificate is issued. The original document remains unchanged, guaranteeing that every copy handed to a bank, school, or government office reflects exactly the same facts. + +In plain words + +> An immutable object is one whose state is fixed at construction time and can never change. Instead of modifying an existing object, you create a new one with the desired state. + +Wikipedia says + +> In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created. + +Class diagram + +![Immutable class diagram](./etc/immutable.urm.puml) + +## Programmatic Example of Immutable Pattern in Java + +The core of the pattern is `ImmutableUser`. All fields are `final`, the mutable `roles` list is defensively copied via `List.copyOf`, and "mutation" is expressed by returning a new instance. + +```java +public final class ImmutableUser { + + private final String name; + private final int age; + private final List roles; + + public ImmutableUser(String name, int age, List roles) { + this.name = name; + this.age = age; + this.roles = List.copyOf(roles); + } + + public String getName() { return name; } + public int getAge() { return age; } + public List getRoles() { return roles; } + + public ImmutableUser withAge(int newAge) { + return new ImmutableUser(this.name, newAge, this.roles); + } +} +``` + +`App` demonstrates the pattern in action: + +```java +var alice = new ImmutableUser("Alice", 30, List.of("admin", "user")); +LOGGER.info("Original user: {}", alice); + +var olderAlice = alice.withAge(31); +LOGGER.info("Updated user (new object): {}", olderAlice); +LOGGER.info("Original is unchanged: {}", alice); + +var mutableRoles = new ArrayList<>(List.of("viewer")); +var bob = new ImmutableUser("Bob", 25, mutableRoles); +mutableRoles.add("editor"); +LOGGER.info("Bob's roles (unchanged despite external list mutation): {}", bob.getRoles()); +``` + +Running the example produces output similar to: + +``` +INFO com.iluwatar.immutable.App - Original user: ImmutableUser{name='Alice', age=30, roles=[admin, user]} +INFO com.iluwatar.immutable.App - Updated user (new object): ImmutableUser{name='Alice', age=31, roles=[admin, user]} +INFO com.iluwatar.immutable.App - Original is unchanged: ImmutableUser{name='Alice', age=30, roles=[admin, user]} +INFO com.iluwatar.immutable.App - Bob's roles (unchanged despite external list mutation): [viewer] +``` + +## When to Use the Immutable Pattern in Java + +* When objects are shared across threads and synchronization overhead is undesirable. +* When you need objects to be used safely as map keys or in sets (consistent `hashCode`). +* When you want to model value types such as money, dates, or coordinates. +* When defensive programming is critical and you must prevent accidental state corruption. + +## Real-World Applications of Immutable Pattern in Java + +* `java.lang.String` — the quintessential immutable class in the JDK. +* `java.time.LocalDate`, `LocalDateTime` — immutable date/time representations. +* `java.math.BigDecimal`, `BigInteger` — immutable numeric types. +* Record classes introduced in Java 16 — compiler-generated immutable data carriers. + +## Benefits and Trade-offs of Immutable Pattern + +Benefits: + +* **Thread safety**: No synchronization needed; immutable objects can be shared freely across threads. +* **Simplicity**: Absence of state changes eliminates a whole category of bugs. +* **Safe sharing**: Can be freely passed to untrusted code without defensive copying at call sites. +* **Cache-friendly**: Immutable objects can be cached, interned, or pre-computed without risk. + +Trade-offs: + +* **Object creation overhead**: Every logical "update" allocates a new object, which may pressure the garbage collector in hot paths. +* **Verbose construction**: Complex objects often require a Builder to avoid unwieldy constructors. +* **Not always applicable**: Objects that model inherently stateful entities (e.g., a network connection) cannot reasonably be immutable. + +## Related Java Design Patterns + +* [Value Object](https://java-design-patterns.com/patterns/value-object/): Overlapping concept; value objects are typically immutable and compared by value rather than identity. +* [Builder](https://java-design-patterns.com/patterns/builder/): Commonly paired with Immutable to construct complex objects step-by-step before freezing them. +* [Prototype](https://java-design-patterns.com/patterns/prototype/): Cloning a mutable object is an alternative to immutability when shared state must occasionally change. +* [Flyweight](https://java-design-patterns.com/patterns/flyweight/): Leverages immutability to safely share fine-grained objects across many contexts. + +## References and Credits + +* [Effective Java, 3rd Edition — Item 17: Minimize Mutability](https://amzn.to/3JIYJoL) +* [Java Concurrency in Practice](https://amzn.to/3vXyUEh) +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://amzn.to/3JIYJoL) +* [Wikipedia — Immutable object](https://en.wikipedia.org/wiki/Immutable_object) diff --git a/immutable/etc/immutable.urm.puml b/immutable/etc/immutable.urm.puml new file mode 100644 index 000000000000..a455b1eab93b --- /dev/null +++ b/immutable/etc/immutable.urm.puml @@ -0,0 +1,21 @@ +@startuml +package com.iluwatar.immutable { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class ImmutableUser { + - name : String {final} + - age : int {final} + - roles : List {final} + + ImmutableUser(name : String, age : int, roles : List) + + getName() : String + + getAge() : int + + getRoles() : List + + withAge(newAge : int) : ImmutableUser + + toString() : String + } +} +App ..> ImmutableUser : creates +@enduml diff --git a/immutable/pom.xml b/immutable/pom.xml new file mode 100644 index 000000000000..e250a2ed48e3 --- /dev/null +++ b/immutable/pom.xml @@ -0,0 +1,76 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + immutable + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.immutable.App + + + + + + + + + diff --git a/immutable/src/main/java/com/iluwatar/immutable/App.java b/immutable/src/main/java/com/iluwatar/immutable/App.java new file mode 100644 index 000000000000..c49cbe041e2d --- /dev/null +++ b/immutable/src/main/java/com/iluwatar/immutable/App.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.immutable; + +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Immutable pattern ensures that an object's state cannot be changed after construction. + * + *

In this example, {@link ImmutableUser} demonstrates the pattern: all fields are final, the + * mutable {@code roles} list is defensively copied, and any state change produces a brand-new + * instance via {@link ImmutableUser#withAge(int)}. + */ +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + var alice = new ImmutableUser("Alice", 30, List.of("admin", "user")); + LOGGER.info("Original user: {}", alice); + + var olderAlice = alice.withAge(31); + LOGGER.info("Updated user (new object): {}", olderAlice); + LOGGER.info("Original is unchanged: {}", alice); + + // Demonstrate defensive copy: mutating the source list does not affect alice + var mutableRoles = new java.util.ArrayList<>(List.of("viewer")); + var bob = new ImmutableUser("Bob", 25, mutableRoles); + mutableRoles.add("editor"); + LOGGER.info("Bob's roles (unchanged despite external list mutation): {}", bob.getRoles()); + } +} diff --git a/immutable/src/main/java/com/iluwatar/immutable/ImmutableUser.java b/immutable/src/main/java/com/iluwatar/immutable/ImmutableUser.java new file mode 100644 index 000000000000..4b4f38de4ac2 --- /dev/null +++ b/immutable/src/main/java/com/iluwatar/immutable/ImmutableUser.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.immutable; + +import java.util.List; + +/** + * An immutable representation of a user. + * + *

All fields are final and set only at construction time. The {@code roles} list is defensively + * copied to prevent external mutation. Any "modification" produces a new {@link ImmutableUser} + * instance, leaving the original unchanged. + */ +public final class ImmutableUser { + + private final String name; + private final int age; + private final List roles; + + /** + * Constructs an {@link ImmutableUser} with the given attributes. + * + * @param name the user's name + * @param age the user's age + * @param roles the user's roles; copied defensively so external changes have no effect + */ + public ImmutableUser(String name, int age, List roles) { + this.name = name; + this.age = age; + this.roles = List.copyOf(roles); + } + + /** + * Returns the user's name. + * + * @return name + */ + public String getName() { + return name; + } + + /** + * Returns the user's age. + * + * @return age + */ + public int getAge() { + return age; + } + + /** + * Returns an unmodifiable view of the user's roles. + * + * @return roles + */ + public List getRoles() { + return roles; + } + + /** + * Returns a new {@link ImmutableUser} identical to this one but with the given name. + * + * @param newName the new name value + * @return a new instance with the updated name + */ + public ImmutableUser withName(String newName) { + return new ImmutableUser(newName, this.age, this.roles); + } + + /** + * Returns a new {@link ImmutableUser} identical to this one but with the given age. + * + * @param newAge the new age value + * @return a new instance with the updated age + */ + public ImmutableUser withAge(int newAge) { + return new ImmutableUser(this.name, newAge, this.roles); + } + + /** + * Returns a new {@link ImmutableUser} identical to this one but with the given roles. + * + * @param newRoles the new roles; copied defensively + * @return a new instance with the updated roles + */ + public ImmutableUser withRoles(List newRoles) { + return new ImmutableUser(this.name, this.age, newRoles); + } + + @Override + public String toString() { + return "ImmutableUser{name='" + name + "', age=" + age + ", roles=" + roles + '}'; + } +} diff --git a/immutable/src/test/java/com/iluwatar/immutable/ImmutableUserTest.java b/immutable/src/test/java/com/iluwatar/immutable/ImmutableUserTest.java new file mode 100644 index 000000000000..0479aff68d89 --- /dev/null +++ b/immutable/src/test/java/com/iluwatar/immutable/ImmutableUserTest.java @@ -0,0 +1,123 @@ +/* + * 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.immutable; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +class ImmutableUserTest { + + @Test + void constructorSetsAllFields() { + var user = new ImmutableUser("Alice", 30, List.of("admin")); + assertEquals("Alice", user.getName()); + assertEquals(30, user.getAge()); + assertEquals(List.of("admin"), user.getRoles()); + } + + @Test + void withAgeReturnsNewObjectWithUpdatedAge() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + var updated = original.withAge(31); + + assertEquals(31, updated.getAge()); + assertEquals("Alice", updated.getName()); + assertEquals(original.getRoles(), updated.getRoles()); + } + + @Test + void withAgeDoesNotMutateOriginal() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + original.withAge(99); + + assertEquals(30, original.getAge()); + } + + @Test + void withAgeReturnsDistinctInstance() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + var updated = original.withAge(31); + + assertNotSame(original, updated); + } + + @Test + void defensiveCopyPreventsExternalListMutation() { + var mutableRoles = new ArrayList<>(List.of("viewer")); + var user = new ImmutableUser("Bob", 25, mutableRoles); + + mutableRoles.add("editor"); + + assertEquals(List.of("viewer"), user.getRoles()); + } + + @Test + void getRolesReturnsUnmodifiableList() { + var user = new ImmutableUser("Bob", 25, List.of("viewer")); + + assertThrows(UnsupportedOperationException.class, () -> user.getRoles().add("editor")); + } + + @Test + void withNameReturnsNewObjectWithUpdatedName() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + var updated = original.withName("Bob"); + + assertEquals("Bob", updated.getName()); + assertEquals(30, updated.getAge()); + assertEquals(original.getRoles(), updated.getRoles()); + } + + @Test + void withNameDoesNotMutateOriginal() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + original.withName("Bob"); + + assertEquals("Alice", original.getName()); + } + + @Test + void withRolesReturnsNewObjectWithUpdatedRoles() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + var updated = original.withRoles(List.of("viewer", "editor")); + + assertEquals(List.of("viewer", "editor"), updated.getRoles()); + assertEquals("Alice", updated.getName()); + assertEquals(30, updated.getAge()); + } + + @Test + void withRolesDoesNotMutateOriginal() { + var original = new ImmutableUser("Alice", 30, List.of("admin")); + original.withRoles(List.of("viewer")); + + assertEquals(List.of("admin"), original.getRoles()); + } +} diff --git a/pom.xml b/pom.xml index 3403c4607f37..c654c5c62dd0 100644 --- a/pom.xml +++ b/pom.xml @@ -147,6 +147,7 @@ health-check hexagonal-architecture identity-map + immutable intercepting-filter interpreter iterator From c70b63d069a34148bff84d60a785cb3928071095 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 6 Jun 2026 22:06:25 +0300 Subject: [PATCH 067/108] docs: add alex052525 as a contributor for code (#3511) * 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 865843b00c0c..d72fdc71741a 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3701,6 +3701,15 @@ "contributions": [ "code" ] + }, + { + "login": "alex052525", + "name": "김정모", + "avatar_url": "https://avatars.githubusercontent.com/u/116088682?v=4", + "profile": "https://github.com/alex052525", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 18d804739aef..2f69a6f0f7b2 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-406-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-407-orange.svg?style=flat-square)](#contributors-)
@@ -601,6 +601,7 @@ This project is licensed under the terms of the MIT license. Stefan Siebers
Stefan Siebers

🌍 OrbisAI Security
OrbisAI Security

🛡️ Raju Gupta
Raju Gupta

💻 + 김정모
김정모

💻 From 13cde46f2e43742c2cd7643780d389fb414b00ad Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Sun, 7 Jun 2026 12:41:45 +0530 Subject: [PATCH 068/108] fix: CVE-2025-22235 security vulnerability (#3510) Automated dependency upgrade by OrbisAI Security --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c654c5c62dd0..87aa35d6aa1e 100644 --- a/pom.xml +++ b/pom.xml @@ -39,7 +39,7 @@ UTF-8 - 3.4.4 + 3.4.5 5.11.4 5.14.2 1.5.18 From 177dc527043d4edacaf44364434479d7879c56fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 7 Jun 2026 12:10:39 +0300 Subject: [PATCH 069/108] fix: Fix test stability issues --- .../java/com/iluwatar/health/check/App.java | 7 +- health-check/src/test/java/AppTest.java | 2 +- .../com/iluwatar/order/microservice/Main.java | 7 +- .../iluwatar/order/microservice/MainTest.java | 2 +- .../iluwatar/payment/microservice/Main.java | 7 +- .../payment/microservice/MainTest.java | 2 +- .../microservice/microservice/Main.java | 7 +- .../product/microservice/MainTest.java | 2 +- .../com/iluwatar/idempotentconsumer/App.java | 7 +- .../iluwatar/idempotentconsumer/AppTest.java | 2 +- .../com/iluwatar/page/controller/App.java | 7 +- .../com/iluwatar/page/controller/AppTest.java | 2 +- .../main/java/com/iluwatar/polling/App.java | 7 +- .../iluwatar/polling/DataSourceService.java | 20 ++++- .../java/com/iluwatar/polling/AppTest.java | 6 +- .../polling/DataSourceServiceTest.java | 8 +- .../java/com/iluwatar/subscriber/App.java | 7 +- .../java/com/iluwatar/subscriber/AppTest.java | 6 +- .../limiting/pattern/AdaptiveRateLimiter.java | 37 +++++++- .../pattern/TokenBucketRateLimiter.java | 37 ++++++-- .../pattern/AdaptiveRateLimiterTest.java | 75 +++++++++------- .../limiting/pattern/ConcurrencyTests.java | 88 ++++++++++--------- .../com/iluwatar/SingleTableInheritance.java | 7 +- .../iluwatar/SingleTableInheritanceTest.java | 2 +- 24 files changed, 248 insertions(+), 106 deletions(-) diff --git a/health-check/src/main/java/com/iluwatar/health/check/App.java b/health-check/src/main/java/com/iluwatar/health/check/App.java index 8f8faed9f821..6c0a446c97ee 100644 --- a/health-check/src/main/java/com/iluwatar/health/check/App.java +++ b/health-check/src/main/java/com/iluwatar/health/check/App.java @@ -43,6 +43,11 @@ public class App { /** Program entry point. */ public static void main(String[] args) { - SpringApplication.run(App.class, args); + var context = SpringApplication.run(App.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/health-check/src/test/java/AppTest.java b/health-check/src/test/java/AppTest.java index c9cd78366461..0c1be55a16ef 100644 --- a/health-check/src/test/java/AppTest.java +++ b/health-check/src/test/java/AppTest.java @@ -33,6 +33,6 @@ class AppTest { /** Entry point */ @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> App.main(new String[] {})); + assertDoesNotThrow(() -> App.main(new String[] {"test"})); } } diff --git a/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java index b6b6da79faae..2e822606ec3b 100644 --- a/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java +++ b/microservices-distributed-tracing/order-microservice/src/main/java/com/iluwatar/order/microservice/Main.java @@ -73,6 +73,11 @@ public class Main { * @param args command line args */ public static void main(String[] args) { - SpringApplication.run(Main.class, args); + var context = SpringApplication.run(Main.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java index 97f9295ff0c1..70e1e3809181 100644 --- a/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java +++ b/microservices-distributed-tracing/order-microservice/src/test/java/com/iluwatar/order/microservice/MainTest.java @@ -32,6 +32,6 @@ class MainTest { @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> Main.main(new String[] {})); + assertDoesNotThrow(() -> Main.main(new String[] {"test"})); } } diff --git a/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java index 506096f4e909..b3be47acc2cd 100644 --- a/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java +++ b/microservices-distributed-tracing/payment-microservice/src/main/java/com/iluwatar/payment/microservice/Main.java @@ -72,6 +72,11 @@ public class Main { * @param args command line args */ public static void main(String[] args) { - SpringApplication.run(Main.class, args); + var context = SpringApplication.run(Main.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java index 2b500440ebc0..87d019da4c3a 100644 --- a/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java +++ b/microservices-distributed-tracing/payment-microservice/src/test/java/com/iluwatar/payment/microservice/MainTest.java @@ -32,6 +32,6 @@ class MainTest { @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> Main.main(new String[] {})); + assertDoesNotThrow(() -> Main.main(new String[] {"test"})); } } diff --git a/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java index 91e41631c190..60ef23d6def2 100644 --- a/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java +++ b/microservices-distributed-tracing/product-microservice/src/main/java/com/iluwatar/product/microservice/microservice/Main.java @@ -72,6 +72,11 @@ public class Main { * @param args command line args */ public static void main(String[] args) { - SpringApplication.run(Main.class, args); + var context = SpringApplication.run(Main.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java index 1534943abd02..8dee84dcbdf1 100644 --- a/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java +++ b/microservices-distributed-tracing/product-microservice/src/test/java/com/iluwatar/product/microservice/MainTest.java @@ -33,6 +33,6 @@ class MainTest { @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> Main.main(new String[] {})); + assertDoesNotThrow(() -> Main.main(new String[] {"test"})); } } diff --git a/microservices-idempotent-consumer/src/main/java/com/iluwatar/idempotentconsumer/App.java b/microservices-idempotent-consumer/src/main/java/com/iluwatar/idempotentconsumer/App.java index fe099eab415f..414e7166c11f 100644 --- a/microservices-idempotent-consumer/src/main/java/com/iluwatar/idempotentconsumer/App.java +++ b/microservices-idempotent-consumer/src/main/java/com/iluwatar/idempotentconsumer/App.java @@ -45,7 +45,12 @@ @Slf4j public class App { public static void main(String[] args) { - SpringApplication.run(App.class, args); + var context = SpringApplication.run(App.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } /** diff --git a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java index f6cd88e0f505..e00b1aad7ade 100644 --- a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java +++ b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java @@ -40,7 +40,7 @@ class AppTest { @Test void testMain() { - assertDoesNotThrow(() -> App.main(new String[] {})); + assertDoesNotThrow(() -> App.main(new String[] {"test"})); } @Test diff --git a/page-controller/src/main/java/com/iluwatar/page/controller/App.java b/page-controller/src/main/java/com/iluwatar/page/controller/App.java index 076ebf081c24..57f8a9a16c25 100644 --- a/page-controller/src/main/java/com/iluwatar/page/controller/App.java +++ b/page-controller/src/main/java/com/iluwatar/page/controller/App.java @@ -44,6 +44,11 @@ public class App { * @param args command line args */ public static void main(final String[] args) { - SpringApplication.run(App.class, args); + var context = SpringApplication.run(App.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java b/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java index b3d374210dfe..eb49969ee3b4 100644 --- a/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java +++ b/page-controller/src/test/java/com/iluwatar/page/controller/AppTest.java @@ -32,6 +32,6 @@ public class AppTest { @Test void shouldExecuteApplicationWithoutException() { - assertDoesNotThrow(() -> App.main(new String[] {})); + assertDoesNotThrow(() -> App.main(new String[] {"test"})); } } diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java index 0b5f9f4d00fa..bd437846b9ed 100644 --- a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/App.java @@ -40,6 +40,11 @@ public class App { * @param args command line args. */ public static void main(String[] args) { - SpringApplication.run(App.class, args); + var context = SpringApplication.run(App.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java index 45dd317fce74..70c091b90ce6 100644 --- a/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java +++ b/polling-publisher/polling-service/src/main/java/com/iluwatar/polling/DataSourceService.java @@ -44,9 +44,22 @@ public class DataSourceService { private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); /** Constructor & Scheduler to push random data. */ + @org.springframework.beans.factory.annotation.Autowired public DataSourceService(DataRepository repository) { + this(repository, true); + } + + /** + * Constructor with option to start the scheduler. + * + * @param repository the data repository + * @param startScheduler true to start the data generation scheduler + */ + public DataSourceService(DataRepository repository, boolean startScheduler) { this.repository = repository; - scheduleDataGeneration(); + if (startScheduler) { + scheduleDataGeneration(); + } } private void scheduleDataGeneration() { @@ -78,4 +91,9 @@ public void removeData(int id) { public Map getAllData() { return repository.findAll(); } + + @javax.annotation.PreDestroy + public void shutdown() { + scheduler.shutdown(); + } } diff --git a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java index d54972662be7..458a29fba88e 100644 --- a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java +++ b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/AppTest.java @@ -28,12 +28,16 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.test.context.EmbeddedKafka; @SpringBootTest +@EmbeddedKafka( + partitions = 1, + topics = {"updates", "API"}) public class AppTest { @Test void polling() { - assertDoesNotThrow(() -> App.main(new String[] {})); + assertDoesNotThrow(() -> App.main(new String[] {"test"})); } } diff --git a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java index 1f861e45beb3..bbcd881c7d59 100644 --- a/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java +++ b/polling-publisher/polling-service/src/test/java/com/iluwatar/polling/DataSourceServiceTest.java @@ -38,7 +38,7 @@ public class DataSourceServiceTest { @BeforeEach void setUp() { repository = new DataRepository(); - service = new DataSourceService(repository); + service = new DataSourceService(repository, false); } @Test @@ -77,8 +77,8 @@ void testGetAllData() { Map result1 = service.getAllData(); - assertEquals(size + 2, result.size(), "Should return all stored data."); - assertEquals("First", result.get(1), "Value for key 1 should be 'First'."); - assertEquals("Second", result.get(2), "Value for key 2 should be 'Second'."); + assertEquals(size + 2, result1.size(), "Should return all stored data."); + assertEquals("First", result1.get(1), "Value for key 1 should be 'First'."); + assertEquals("Second", result1.get(2), "Value for key 2 should be 'Second'."); } } diff --git a/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java index b8dd8a23f4ec..140210899cab 100644 --- a/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java +++ b/polling-publisher/subscriber-service/src/main/java/com/iluwatar/subscriber/App.java @@ -32,6 +32,11 @@ @SpringBootApplication public class App { public static void main(String[] args) { - SpringApplication.run(App.class, args); + var context = SpringApplication.run(App.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } } diff --git a/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java b/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java index b03222d435e0..c479eb5b832b 100644 --- a/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java +++ b/polling-publisher/subscriber-service/src/test/java/com/iluwatar/subscriber/AppTest.java @@ -29,12 +29,16 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.kafka.test.context.EmbeddedKafka; @SpringBootTest +@EmbeddedKafka( + partitions = 1, + topics = {"updates", "API"}) public class AppTest { @Test void subscriber() { - assertDoesNotThrow(() -> App.main(new String[] {})); + assertDoesNotThrow(() -> App.main(new String[] {"test"})); } } diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java index 1b18a8c941b9..4501bb0e9acc 100644 --- a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiter.java @@ -10,13 +10,28 @@ public class AdaptiveRateLimiter implements RateLimiter { private final AtomicInteger currentLimit; private final ConcurrentHashMap limiters = new ConcurrentHashMap<>(); private final ScheduledExecutorService healthChecker = Executors.newScheduledThreadPool(1); + private final long checkInterval; + private final TimeUnit timeUnit; public AdaptiveRateLimiter(int initialLimit, int maxLimit) { + this(initialLimit, maxLimit, 10, TimeUnit.SECONDS); + } + + /** + * Constructor with option to set custom interval. + * + * @param initialLimit initial rate limit + * @param maxLimit maximum rate limit + * @param interval check interval + * @param timeUnit check interval time unit + */ + public AdaptiveRateLimiter(int initialLimit, int maxLimit, long interval, TimeUnit timeUnit) { this.initialLimit = initialLimit; this.maxLimit = maxLimit; this.currentLimit = new AtomicInteger(initialLimit); - // Periodically increase limit to recover if system appears healthy - healthChecker.scheduleAtFixedRate(this::adjustLimits, 10, 10, TimeUnit.SECONDS); + this.checkInterval = interval; + this.timeUnit = timeUnit; + healthChecker.scheduleAtFixedRate(this::adjustLimits, interval, interval, timeUnit); } @Override @@ -24,9 +39,10 @@ public void check(String serviceName, String operationName) throws RateLimitExce String key = serviceName + ":" + operationName; int current = currentLimit.get(); - // Reuse or create TokenBucket for this key using currentLimit + // Reuse or create TokenBucket for this key using currentLimit and checkInterval RateLimiter limiter = - limiters.computeIfAbsent(key, k -> new TokenBucketRateLimiter(current, current)); + limiters.computeIfAbsent( + key, k -> new TokenBucketRateLimiter(current, current, checkInterval, timeUnit)); try { limiter.check(serviceName, operationName); @@ -47,4 +63,17 @@ private void adjustLimits() { int updated = currentLimit.updateAndGet(curr -> Math.min(maxLimit, curr + (initialLimit / 2))); System.out.printf("[Adaptive] Health check passed - Increasing limit to %d%n", updated); } + + /** Gracefully shut down the health checker executor and child limiters. */ + public void shutdown() { + healthChecker.shutdown(); + limiters + .values() + .forEach( + limiter -> { + if (limiter instanceof TokenBucketRateLimiter) { + ((TokenBucketRateLimiter) limiter).shutdown(); + } + }); + } } diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java index 3001c880aad3..e13b966a2ac4 100644 --- a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java @@ -4,8 +4,10 @@ import java.util.concurrent.atomic.AtomicInteger; /** - * Token Bucket rate limiter implementation. Allows requests to proceed as long as there are tokens - * available in the bucket. Tokens are added at a fixed interval up to a defined capacity. + * Token Bucket rate limiter implementation. Allows requests to proceed as long + * as there are tokens + * available in the bucket. Tokens are added at a fixed interval up to a defined + * capacity. */ public class TokenBucketRateLimiter implements RateLimiter { private final int capacity; @@ -14,10 +16,22 @@ public class TokenBucketRateLimiter implements RateLimiter { private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); public TokenBucketRateLimiter(int capacity, int refillRate) { + this(capacity, refillRate, 1, TimeUnit.SECONDS); + } + + /** + * Constructor with custom refill interval. + * + * @param capacity token bucket capacity + * @param refillRate token refill rate + * @param refillInterval refill interval value + * @param timeUnit refill interval time unit + */ + public TokenBucketRateLimiter( + int capacity, int refillRate, long refillInterval, TimeUnit timeUnit) { this.capacity = capacity; this.refillRate = refillRate; - // Refill tokens in all buckets every second - scheduler.scheduleAtFixedRate(this::refillBuckets, 1, 1, TimeUnit.SECONDS); + scheduler.scheduleAtFixedRate(this::refillBuckets, refillInterval, refillInterval, timeUnit); } @Override @@ -39,7 +53,10 @@ private void refillBuckets() { buckets.forEach((k, b) -> b.refill(refillRate)); } - /** Inner class that represents the bucket holding tokens for each service-operation. */ + /** + * Inner class that represents the bucket holding tokens for each + * service-operation. + */ private static class TokenBucket { private final int capacity; private final AtomicInteger tokens; @@ -52,8 +69,10 @@ private static class TokenBucket { boolean tryConsume() { while (true) { int current = tokens.get(); - if (current <= 0) return false; - if (tokens.compareAndSet(current, current - 1)) return true; + if (current <= 0) + return false; + if (tokens.compareAndSet(current, current - 1)) + return true; } } @@ -61,4 +80,8 @@ void refill(int amount) { tokens.getAndUpdate(current -> Math.min(current + amount, capacity)); } } + + public void shutdown() { + scheduler.shutdown(); + } } diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java index 042d606490d0..330975353f7c 100644 --- a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/AdaptiveRateLimiterTest.java @@ -8,49 +8,60 @@ class AdaptiveRateLimiterTest { @Test void shouldDecreaseLimitWhenThrottled() throws Exception { AdaptiveRateLimiter limiter = new AdaptiveRateLimiter(10, 20); - - // Exceed initial limit - for (int i = 0; i < 11; i++) { - try { - limiter.check("test", "op"); - } catch (RateLimitException e) { - // Expected after 10 requests + try { + // Exceed initial limit + for (int i = 0; i < 11; i++) { + try { + limiter.check("test", "op"); + } catch (RateLimitException e) { + // Expected after 10 requests + } } - } - // Verify limit was reduced - assertThrows( - RateLimitException.class, - () -> { - for (int i = 0; i < 6; i++) { // New limit should be 5 (10/2) - limiter.check("test", "op"); - } - }); + // Verify limit was reduced + assertThrows( + RateLimitException.class, + () -> { + for (int i = 0; i < 6; i++) { // New limit should be 5 (10/2) + limiter.check("test", "op"); + } + }); + } finally { + limiter.shutdown(); + } } @Test void shouldGraduallyIncreaseLimitWhenHealthy() throws Exception { AdaptiveRateLimiter limiter = - new AdaptiveRateLimiter(4, 10); // Start from 4 → expect 2 → expect increase to 4 + new AdaptiveRateLimiter( + 4, + 10, + 100, + java.util.concurrent.TimeUnit + .MILLISECONDS); // Start from 4 → expect 2 → expect increase to 4 + try { + // Force throttling to reduce limit + for (int i = 0; i < 5; i++) { + try { + limiter.check("test", "op"); + } catch (RateLimitException e) { + // Expected to throttle and reduce limit + } + } - // Force throttling to reduce limit - for (int i = 0; i < 5; i++) { - try { + // Wait for health check to increase limit + Thread.sleep(150); // Wait slightly more than 100 milliseconds + + // Allow up to 4 requests again (limit should've increased to 4) + for (int i = 0; i < 4; i++) { limiter.check("test", "op"); - } catch (RateLimitException e) { - // Expected to throttle and reduce limit } - } - // Wait for health check to increase limit - Thread.sleep(11000); // Wait slightly more than 10 seconds - - // Allow up to 4 requests again (limit should've increased to 4) - for (int i = 0; i < 4; i++) { - limiter.check("test", "op"); + // 5th should throw exception again + assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); + } finally { + limiter.shutdown(); } - - // 5th should throw exception again - assertThrows(RateLimitException.class, () -> limiter.check("test", "op")); } } diff --git a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java index 35a1294a8ad3..cba26d9ab7d0 100644 --- a/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java +++ b/rate-limiting-pattern/src/test/java/com/iluwatar/rate/limiting/pattern/ConcurrencyTests.java @@ -13,57 +13,65 @@ void tokenBucketShouldHandleConcurrentRequests() throws Exception { int requestLimit = 5; RateLimiter limiter = new TokenBucketRateLimiter(requestLimit, requestLimit); ExecutorService executor = Executors.newFixedThreadPool(threadCount); - CountDownLatch latch = new CountDownLatch(threadCount); + try { + CountDownLatch latch = new CountDownLatch(threadCount); - AtomicInteger successCount = new AtomicInteger(); - AtomicInteger failureCount = new AtomicInteger(); + AtomicInteger successCount = new AtomicInteger(); + AtomicInteger failureCount = new AtomicInteger(); - for (int i = 0; i < threadCount; i++) { - executor.submit( - () -> { - try { - limiter.check("test", "op"); - successCount.incrementAndGet(); - } catch (RateLimitException e) { - failureCount.incrementAndGet(); - } - latch.countDown(); - }); - } + for (int i = 0; i < threadCount; i++) { + executor.submit( + () -> { + try { + limiter.check("test", "op"); + successCount.incrementAndGet(); + } catch (RateLimitException e) { + failureCount.incrementAndGet(); + } + latch.countDown(); + }); + } - latch.await(); - assertEquals(requestLimit, successCount.get()); - assertEquals(threadCount - requestLimit, failureCount.get()); + latch.await(); + assertEquals(requestLimit, successCount.get()); + assertEquals(threadCount - requestLimit, failureCount.get()); + } finally { + executor.shutdown(); + } } @Test void adaptiveLimiterShouldAdjustUnderLoad() throws Exception { - AdaptiveRateLimiter limiter = new AdaptiveRateLimiter(10, 20); + AdaptiveRateLimiter limiter = new AdaptiveRateLimiter(10, 20, 100, TimeUnit.MILLISECONDS); ExecutorService executor = Executors.newFixedThreadPool(20); + try { + // Flood with requests to trigger throttling + for (int i = 0; i < 30; i++) { + executor.submit( + () -> { + try { + limiter.check("test", "op"); + } catch (RateLimitException ignored) { + } + }); + } - // Flood with requests to trigger throttling - for (int i = 0; i < 30; i++) { - executor.submit( - () -> { - try { - limiter.check("test", "op"); - } catch (RateLimitException ignored) { - } - }); - } - - Thread.sleep(15000); // Wait for adjustment + Thread.sleep(150); // Wait for adjustment - // Verify new limit is in effect - int allowed = 0; - for (int i = 0; i < 20; i++) { - try { - limiter.check("test", "op"); - allowed++; - } catch (RateLimitException ignored) { + // Verify new limit is in effect + int allowed = 0; + for (int i = 0; i < 20; i++) { + try { + limiter.check("test", "op"); + allowed++; + } catch (RateLimitException ignored) { + } } - } - assertTrue(allowed > 5 && allowed < 15); // Should be between initial and max + assertTrue(allowed > 5 && allowed < 15); // Should be between initial and max + } finally { + executor.shutdown(); + limiter.shutdown(); + } } } diff --git a/single-table-inheritance/src/main/java/com/iluwatar/SingleTableInheritance.java b/single-table-inheritance/src/main/java/com/iluwatar/SingleTableInheritance.java index f27b71213a09..cb647dcb1ec4 100644 --- a/single-table-inheritance/src/main/java/com/iluwatar/SingleTableInheritance.java +++ b/single-table-inheritance/src/main/java/com/iluwatar/SingleTableInheritance.java @@ -67,7 +67,12 @@ public class SingleTableInheritance implements CommandLineRunner { * @param args program runtime arguments */ public static void main(String[] args) { - SpringApplication.run(SingleTableInheritance.class, args); + var context = SpringApplication.run(SingleTableInheritance.class, args); + if (args.length > 0 && "test".equals(args[0])) { + // Close the context immediately during tests to prevent Tomcat/background threads from + // hanging the JVM + context.close(); + } } /** diff --git a/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java b/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java index 8c4415cf4bfd..8ba4f275a0dd 100644 --- a/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java +++ b/single-table-inheritance/src/test/java/com/iluwatar/SingleTableInheritanceTest.java @@ -33,6 +33,6 @@ class SingleTableInheritanceTest { @Test void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> SingleTableInheritance.main(new String[] {})); + assertDoesNotThrow(() -> SingleTableInheritance.main(new String[] {"test"})); } } From c317ce012a5d04fa136673e9f8da0ea69a064cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 7 Jun 2026 12:35:18 +0300 Subject: [PATCH 070/108] feat: Enable codecov reports --- .github/workflows/maven-ci.yml | 7 ++++++- .github/workflows/maven-pr-builder.yml | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml index 5d2812e72fb7..00ad59c7dab2 100644 --- a/.github/workflows/maven-ci.yml +++ b/.github/workflows/maven-ci.yml @@ -50,4 +50,9 @@ jobs: env: # These two env variables are needed for sonar analysis GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/maven-pr-builder.yml b/.github/workflows/maven-pr-builder.yml index 2bae03814fcf..149733343781 100644 --- a/.github/workflows/maven-pr-builder.yml +++ b/.github/workflows/maven-pr-builder.yml @@ -38,4 +38,9 @@ jobs: run: sudo apt-get install -y xvfb - name: Build with Maven - run: xvfb-run ./mvnw clean verify \ No newline at end of file + run: xvfb-run ./mvnw clean verify + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} \ No newline at end of file From 2dfb27c8591a0363ab0fdac76e71f303b8a2df17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 7 Jun 2026 12:40:02 +0300 Subject: [PATCH 071/108] fix: spotless formatting fixes --- .../contextservice/pom.xml | 20 ++++++++++++++++ .../ContextserviceApplication.java | 7 +++--- .../contextservice/MyCustomHealthCheck.java | 5 ++-- .../controller/ContextController.java | 5 ++-- .../contextservice/ContextControllerTest.java | 23 ++++++++++--------- .../ContextserviceApplicationTests.java | 13 ++++++----- .../myCustomHealthCheckTest.java | 11 +++++---- .../eurekaserver/pom.xml | 20 ++++++++++++++++ .../eurekaserver/EurekaserverApplication.java | 7 +++--- .../EurekaserverApplicationTests.java | 13 ++++++----- .../greetingservice/pom.xml | 20 ++++++++++++++++ .../GreetingserviceApplication.java | 7 +++--- .../greetingservice/MyCustomHealthCheck.java | 4 +++- .../GreetingserviceApplicationTests.java | 13 ++++++----- .../MyCustomHealthCheckTest.java | 11 +++++---- .../controller/GreetingControllerTest.java | 18 ++++++++------- .../pattern/TokenBucketRateLimiter.java | 23 +++++++------------ 17 files changed, 141 insertions(+), 79 deletions(-) diff --git a/microservices-self-registration/contextservice/pom.xml b/microservices-self-registration/contextservice/pom.xml index ea6d105bd06f..71f61fcf6a30 100644 --- a/microservices-self-registration/contextservice/pom.xml +++ b/microservices-self-registration/contextservice/pom.xml @@ -67,6 +67,26 @@ org.apache.maven.plugins maven-compiler-plugin + + com.diffplug.spotless + spotless-maven-plugin + 2.44.4 + + + + check + apply + + + + + + + 1.17.0 + + + + diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java index eb22d094ffce..01335dcc28c1 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/ContextserviceApplication.java @@ -10,8 +10,7 @@ @EnableFeignClients public class ContextserviceApplication { - public static void main(String[] args) { - SpringApplication.run(ContextserviceApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(ContextserviceApplication.class, args); + } } diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java index 0226fc50e803..554ab2e83aef 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/MyCustomHealthCheck.java @@ -7,7 +7,6 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; - @Component("myCustomHealthCheck") public class MyCustomHealthCheck implements HealthIndicator { @@ -33,7 +32,9 @@ boolean performHealthCheck() { public Health health() { if (isHealthy) { log.info("Health check successful, service is UP"); - return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + return Health.up() + .withDetail("message", "Service is running and scheduled checks are OK") + .build(); } else { log.warn("Health check failed, service is DOWN"); return Health.down().withDetail("error", "Scheduled health checks failed").build(); diff --git a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java index 5ad8969e0871..3b5febb80028 100644 --- a/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java +++ b/microservices-self-registration/contextservice/src/main/java/com/learning/contextservice/controller/ContextController.java @@ -13,7 +13,8 @@ public class ContextController { private final String userRegion; @Autowired - public ContextController(GreetingServiceClient greetingServiceClient, @Value("${user.region}") String userRegion) { + public ContextController( + GreetingServiceClient greetingServiceClient, @Value("${user.region}") String userRegion) { this.greetingServiceClient = greetingServiceClient; this.userRegion = userRegion; } @@ -21,6 +22,6 @@ public ContextController(GreetingServiceClient greetingServiceClient, @Value("${ @GetMapping("/context") public String getContext() { String greeting = greetingServiceClient.getGreeting(); - return "The Greeting Service says: "+greeting+" from "+userRegion; + return "The Greeting Service says: " + greeting + " from " + userRegion; } } diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java index f11da867cda0..8fba01f0c3b5 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextControllerTest.java @@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; - import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; @@ -21,29 +20,31 @@ @Import(TestConfig.class) class ContextControllerTest { - @Autowired - private MockMvc mockMvc; + @Autowired private MockMvc mockMvc; - @MockitoBean - private GreetingServiceClient greetingServiceClient; + @MockitoBean private GreetingServiceClient greetingServiceClient; @Value("${user.region}") private String userRegion; @Test - void shouldReturnContextGreeting() throws Exception{ + void shouldReturnContextGreeting() throws Exception { Mockito.when(greetingServiceClient.getGreeting()).thenReturn("Mocked Hello"); - mockMvc.perform(MockMvcRequestBuilders.get("/context") - .accept(MediaType.TEXT_PLAIN)) + mockMvc + .perform(MockMvcRequestBuilders.get("/context").accept(MediaType.TEXT_PLAIN)) .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); + .andExpect( + MockMvcResultMatchers.content() + .string("The Greeting Service says: Mocked Hello from Chennai, Tamil Nadu, India")); } @Test void shouldReturnContextServiceHealthStatusUp() throws Exception { - mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + mockMvc + .perform(MockMvcRequestBuilders.get("/actuator/health")) .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("\"status\":\"UP\""))); + .andExpect( + MockMvcResultMatchers.content().string(Matchers.containsString("\"status\":\"UP\""))); } } diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java index a5d5c869c664..aa789ad92cbd 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/ContextserviceApplicationTests.java @@ -6,12 +6,13 @@ @SpringBootTest class ContextserviceApplicationTests { - @Test - void contextLoads() { - // This is a basic integration test that checks if the Spring Application Context loads successfully. + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads + // successfully. // If the context loads without any exceptions, the test is considered passing. // It is often left empty as the act of loading the context is the primary verification. - // You can add specific assertions here if you want to verify the presence or state of certain beans. - } - + // You can add specific assertions here if you want to verify the presence or state of certain + // beans. + } } diff --git a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java index 129209469827..d771a1eed9ae 100644 --- a/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java +++ b/microservices-self-registration/contextservice/src/test/java/com/learning/contextservice/myCustomHealthCheckTest.java @@ -1,10 +1,11 @@ package com.learning.contextservice; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.health.Health; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.boot.actuate.health.Status; -import static org.junit.jupiter.api.Assertions.*; +import org.springframework.test.util.ReflectionTestUtils; class MyCustomHealthCheckTest { @@ -16,7 +17,8 @@ void testHealthUp() { Health health = healthCheck.health(); assertEquals(Status.UP, health.getStatus()); assertTrue(health.getDetails().containsKey("message")); - assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + assertEquals( + "Service is running and scheduled checks are OK", health.getDetails().get("message")); } @Test @@ -29,5 +31,4 @@ void testHealthDown() { assertTrue(health.getDetails().containsKey("error")); assertEquals("Scheduled health checks failed", health.getDetails().get("error")); } - -} \ No newline at end of file +} diff --git a/microservices-self-registration/eurekaserver/pom.xml b/microservices-self-registration/eurekaserver/pom.xml index b1a4b26cf4f4..fac49a1e4938 100644 --- a/microservices-self-registration/eurekaserver/pom.xml +++ b/microservices-self-registration/eurekaserver/pom.xml @@ -49,6 +49,26 @@ org.apache.maven.plugins maven-compiler-plugin + + com.diffplug.spotless + spotless-maven-plugin + 2.44.4 + + + + check + apply + + + + + + + 1.17.0 + + + + diff --git a/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java index 80b3d904ff4c..80b888f5910c 100644 --- a/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java +++ b/microservices-self-registration/eurekaserver/src/main/java/com/learning/eurekaserver/EurekaserverApplication.java @@ -8,8 +8,7 @@ @EnableEurekaServer public class EurekaserverApplication { - public static void main(String[] args) { - SpringApplication.run(EurekaserverApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(EurekaserverApplication.class, args); + } } diff --git a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java index b5150fefa940..4f846888281d 100644 --- a/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java +++ b/microservices-self-registration/eurekaserver/src/test/java/com/learning/eurekaserver/EurekaserverApplicationTests.java @@ -6,12 +6,13 @@ @SpringBootTest class EurekaserverApplicationTests { - @Test - void contextLoads() { - // This is a basic integration test that checks if the Spring Application Context loads successfully. + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads + // successfully. // If the context loads without any exceptions, the test is considered passing. // It is often left empty as the act of loading the context is the primary verification. - // You can add specific assertions here if you want to verify the presence or state of certain beans. - } - + // You can add specific assertions here if you want to verify the presence or state of certain + // beans. + } } diff --git a/microservices-self-registration/greetingservice/pom.xml b/microservices-self-registration/greetingservice/pom.xml index 45988a145866..36221db34add 100644 --- a/microservices-self-registration/greetingservice/pom.xml +++ b/microservices-self-registration/greetingservice/pom.xml @@ -63,6 +63,26 @@ org.apache.maven.plugins maven-compiler-plugin + + com.diffplug.spotless + spotless-maven-plugin + 2.44.4 + + + + check + apply + + + + + + + 1.17.0 + + + + diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java index 7a549a084284..93b3d3041996 100644 --- a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/GreetingserviceApplication.java @@ -10,8 +10,7 @@ @ComponentScan("com.learning.greetingservice.controller") public class GreetingserviceApplication { - public static void main(String[] args) { - SpringApplication.run(GreetingserviceApplication.class, args); - } - + public static void main(String[] args) { + SpringApplication.run(GreetingserviceApplication.class, args); + } } diff --git a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java index 218a4ad002d4..639a402fc70a 100644 --- a/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java +++ b/microservices-self-registration/greetingservice/src/main/java/com/learning/greetingservice/MyCustomHealthCheck.java @@ -32,7 +32,9 @@ boolean performHealthCheck() { public Health health() { if (isHealthy) { log.info("Health check successful, service is UP"); - return Health.up().withDetail("message", "Service is running and scheduled checks are OK").build(); + return Health.up() + .withDetail("message", "Service is running and scheduled checks are OK") + .build(); } else { log.warn("Health check failed, service is DOWN"); return Health.down().withDetail("error", "Scheduled health checks failed").build(); diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java index 945898278aa9..0f00c8ab435c 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/GreetingserviceApplicationTests.java @@ -6,12 +6,13 @@ @SpringBootTest class GreetingserviceApplicationTests { - @Test - void contextLoads() { - // This is a basic integration test that checks if the Spring Application Context loads successfully. + @Test + void contextLoads() { + // This is a basic integration test that checks if the Spring Application Context loads + // successfully. // If the context loads without any exceptions, the test is considered passing. // It is often left empty as the act of loading the context is the primary verification. - // You can add specific assertions here if you want to verify the presence or state of certain beans. - } - + // You can add specific assertions here if you want to verify the presence or state of certain + // beans. + } } diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java index 8ba8b2a30f93..6e67f875c154 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/MyCustomHealthCheckTest.java @@ -1,10 +1,11 @@ package com.learning.greetingservice; +import static org.junit.jupiter.api.Assertions.*; + import org.junit.jupiter.api.Test; import org.springframework.boot.actuate.health.Health; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.boot.actuate.health.Status; -import static org.junit.jupiter.api.Assertions.*; +import org.springframework.test.util.ReflectionTestUtils; class MyCustomHealthCheckTest { @@ -16,7 +17,7 @@ void testHealthUp() { Health health = healthCheck.health(); assertEquals(Status.UP, health.getStatus()); assertTrue(health.getDetails().containsKey("message")); - assertEquals("Service is running and scheduled checks are OK", health.getDetails().get("message")); + assertEquals( + "Service is running and scheduled checks are OK", health.getDetails().get("message")); } - -} \ No newline at end of file +} diff --git a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java index 5ae98c8b6aeb..22fa8ecf3568 100644 --- a/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java +++ b/microservices-self-registration/greetingservice/src/test/java/com/learning/greetingservice/controller/GreetingControllerTest.java @@ -16,21 +16,23 @@ @ActiveProfiles("test") class GreetingControllerTest { - @Autowired - private MockMvc mockMvc; + @Autowired private MockMvc mockMvc; @Test - void shouldReturnGreeting() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/greeting") - .accept(MediaType.TEXT_PLAIN)) + void shouldReturnGreeting() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/greeting").accept(MediaType.TEXT_PLAIN)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("Hello")); } @Test - void shouldReturnHealthStatusUp() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/actuator/health")) + void shouldReturnHealthStatusUp() throws Exception { + mockMvc + .perform(MockMvcRequestBuilders.get("/actuator/health")) .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().string(org.hamcrest.Matchers.containsString("\"status\":\"UP\""))); + .andExpect( + MockMvcResultMatchers.content() + .string(org.hamcrest.Matchers.containsString("\"status\":\"UP\""))); } } diff --git a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java index e13b966a2ac4..ded1396f1fff 100644 --- a/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java +++ b/rate-limiting-pattern/src/main/java/com/iluwatar/rate/limiting/pattern/TokenBucketRateLimiter.java @@ -4,10 +4,8 @@ import java.util.concurrent.atomic.AtomicInteger; /** - * Token Bucket rate limiter implementation. Allows requests to proceed as long - * as there are tokens - * available in the bucket. Tokens are added at a fixed interval up to a defined - * capacity. + * Token Bucket rate limiter implementation. Allows requests to proceed as long as there are tokens + * available in the bucket. Tokens are added at a fixed interval up to a defined capacity. */ public class TokenBucketRateLimiter implements RateLimiter { private final int capacity; @@ -22,10 +20,10 @@ public TokenBucketRateLimiter(int capacity, int refillRate) { /** * Constructor with custom refill interval. * - * @param capacity token bucket capacity - * @param refillRate token refill rate + * @param capacity token bucket capacity + * @param refillRate token refill rate * @param refillInterval refill interval value - * @param timeUnit refill interval time unit + * @param timeUnit refill interval time unit */ public TokenBucketRateLimiter( int capacity, int refillRate, long refillInterval, TimeUnit timeUnit) { @@ -53,10 +51,7 @@ private void refillBuckets() { buckets.forEach((k, b) -> b.refill(refillRate)); } - /** - * Inner class that represents the bucket holding tokens for each - * service-operation. - */ + /** Inner class that represents the bucket holding tokens for each service-operation. */ private static class TokenBucket { private final int capacity; private final AtomicInteger tokens; @@ -69,10 +64,8 @@ private static class TokenBucket { boolean tryConsume() { while (true) { int current = tokens.get(); - if (current <= 0) - return false; - if (tokens.compareAndSet(current, current - 1)) - return true; + if (current <= 0) return false; + if (tokens.compareAndSet(current, current - 1)) return true; } } From 4cc30055fcaaf17deb0bc323647f5dd80bfacb8e Mon Sep 17 00:00:00 2001 From: Ved Asole <77259804+ved-asole@users.noreply.github.com> Date: Sun, 7 Jun 2026 15:39:39 +0530 Subject: [PATCH 072/108] docs: Update ved-asole link in .all-contributorsrc (#3294) * Update ved-asole link in .all-contributorsrc Updated my profile link in .all-contributorsrc * Update README.md with url for ved-asole profile Update README.md with url for ved-asole profile --- .all-contributorsrc | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index d72fdc71741a..e90d733e4efb 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -2891,7 +2891,7 @@ "login": "ved-asole", "name": "Ved Asole", "avatar_url": "https://avatars.githubusercontent.com/u/77259804?v=4", - "profile": "http://vedasole.cloud", + "profile": "https://github.com/ved-asole", "contributions": [ "code" ] diff --git a/README.md b/README.md index 2f69a6f0f7b2..353be6b99ff2 100644 --- a/README.md +++ b/README.md @@ -481,7 +481,7 @@ This project is licensed under the terms of the MIT license. Jakub Klimek
Jakub Klimek

💻 believe
believe

🌍 egg0102030405
egg0102030405

🌍 📖 - Ved Asole
Ved Asole

💻 + Ved Asole
Ved Asole

💻 NewMorning
NewMorning

🌍 From 5a2beb880812b5014af12f8137c47ec284345579 Mon Sep 17 00:00:00 2001 From: Anakin Yen <122139183+AnakinYen0329@users.noreply.github.com> Date: Sun, 7 Jun 2026 18:16:48 +0800 Subject: [PATCH 073/108] feat: translage to traditional Chinese (zh-tw) (#3324) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修改完成 * Add Singleton pattern example --- README.md | 3 +- localization/zh-TW/README.md | 42 ++++ .../{zh => zh-TW}/abstract-document/README.md | 46 ++-- .../etc/abstract-document.png | Bin localization/zh-TW/abstract-factory/README.md | 229 ++++++++++++++++++ .../etc/abstract-factory.urm.png | Bin 0 -> 82368 bytes .../etc/abstract-factory.urm.puml | 101 ++++++++ localization/zh-TW/active-object/README.md | 123 ++++++++++ .../active-object/etc/active-object.urm.png | Bin 0 -> 19466 bytes localization/zh-TW/actor-model/README.md | 193 +++++++++++++++ .../etc/Actor_Model_UML_Class_Diagram.png | Bin 0 -> 47298 bytes .../actor-model/etc/actor-model.urm.puml | 35 +++ 12 files changed, 749 insertions(+), 23 deletions(-) create mode 100644 localization/zh-TW/README.md rename localization/{zh => zh-TW}/abstract-document/README.md (68%) rename localization/{zh => zh-TW}/abstract-document/etc/abstract-document.png (100%) create mode 100644 localization/zh-TW/abstract-factory/README.md create mode 100644 localization/zh-TW/abstract-factory/etc/abstract-factory.urm.png create mode 100644 localization/zh-TW/abstract-factory/etc/abstract-factory.urm.puml create mode 100644 localization/zh-TW/active-object/README.md create mode 100644 localization/zh-TW/active-object/etc/active-object.urm.png create mode 100644 localization/zh-TW/actor-model/README.md create mode 100644 localization/zh-TW/actor-model/etc/Actor_Model_UML_Class_Diagram.png create mode 100644 localization/zh-TW/actor-model/etc/actor-model.urm.puml diff --git a/README.md b/README.md index 353be6b99ff2..247f5f17e87a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@
-Read in different language : [**zh**](localization/zh/README.md), [**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md), [**vi**](localization/vi/README.md), [**bn**](localization/bn/README.md), [**np**](localization/ne/README.md), [**it**](localization/it/README.md), [**da**](localization/da/README.md) +Read in different language : [**zh**](localization/zh/README.md), [**zh-TW**](localization/zh-TW/README.md) +,[**ko**](localization/ko/README.md), [**fr**](localization/fr/README.md), [**tr**](localization/tr/README.md), [**ar**](localization/ar/README.md), [**es**](localization/es/README.md), [**pt**](localization/pt/README.md), [**id**](localization/id/README.md), [**ru**](localization/ru/README.md), [**de**](localization/de/README.md), [**ja**](localization/ja/README.md), [**vi**](localization/vi/README.md), [**bn**](localization/bn/README.md), [**np**](localization/ne/README.md), [**it**](localization/it/README.md), [**da**](localization/da/README.md)
# Introduction diff --git a/localization/zh-TW/README.md b/localization/zh-TW/README.md new file mode 100644 index 000000000000..f7748a7c6208 --- /dev/null +++ b/localization/zh-TW/README.md @@ -0,0 +1,42 @@ + + +# 設計模式Java版 + +![Java CI with Maven](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI/badge.svg) [](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) [](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg) [](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)![Sonarcloud Status](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=alert_status) + +# 介紹 + +設計模式是程式設計師在設計應用程式或系統時,可以用來解決常見問題的最佳且具形式化的實踐方法。 + +設計模式能透過提供經過測試與驗證的開發範式,加快開發流程。 + +重複使用設計模式有助於避免那些可能導致重大問題的細微錯誤,同時也能提升程式碼的可讀性,讓熟悉這些模式的開發人員與架構師更容易理解。 + +# 入門 + +這個網站展示了 Java 設計模式。這些解決方案由開放原始碼社群中有經驗的程式設計師與架構師所開發。使用者可以透過高層次的描述來瀏覽這些模式,或是直接查看其原始碼。程式碼範例都有詳細的註解,可以視為實作特定設計模式的教學範本。我們使用的是最受歡迎且經過實戰驗證的開放原始碼 Java 技術。 + +在深入學習這些內容之前,你應該先熟悉各種[軟體設計原則](https://java-design-patterns.com/principles/). + +所有設計都應盡可能簡單。建議先從 KISS(Keep It Simple, Stupid)、YAGNI(You Aren’t Gonna Need It)以及 Do The Simplest Thing That Could Possibly Work 這些原則開始。只有在實際需要擴充性時,才應該引入複雜性與設計模式。 + +熟悉了這些概念,就可以透過以下任一種方式深入研究可用的設計模式: + +- 依名稱搜尋特定模式。找不到的話?請[在這裡](https://github.com/iluwatar/java-design-patterns/issues)回報新模式。 +- 使用難度標籤: `Performance(效能)` , `Gang of Four(四人幫)`和`Data access(資料存取)` 。 +- 使用模式分類`Creational(建立型)` ,`Behavioral(行為型)`和其他类别。 + + +希望你能在這個網站上找到對你的架構有幫助的物件導向解決方案,並且在學習的過程中和我們開發這些方案時一樣感到愉快。 + +# 如何做出貢獻 + +如果你願意為這個專案做出貢獻,你可以在我們的[開發者 Wiki](https://github.com/iluwatar/java-design-patterns/wiki)找到相關資訊。我們也會在[Gitter聊天室](https://gitter.im/iluwatar/java-design-patterns)中協助你並回答你的問題。 + +# 許可證 + +該項目使用麻省理工學院許可證。 + + diff --git a/localization/zh/abstract-document/README.md b/localization/zh-TW/abstract-document/README.md similarity index 68% rename from localization/zh/abstract-document/README.md rename to localization/zh-TW/abstract-document/README.md index cf19dfcf84cb..f71ff845a97f 100644 --- a/localization/zh/abstract-document/README.md +++ b/localization/zh-TW/abstract-document/README.md @@ -2,34 +2,34 @@ title: Abstract Document shortTitle: Abstract Document category: Structural -language: zh +language: zh-TW tag: - Extensibility --- ## 目的 -使用动态属性,并在保持类型安全的同时实现非类型化语言的灵活性。 +使用動態屬性,並在保持型別安全的同時實現非型別化語言的靈活性。 -## 解释 +## 解釋 -抽象文档模式使您能够处理其他非静态属性。 此模式使用特征的概念来实现类型安全,并将不同类的属性分离为一组接口。 +抽象文件模式 (Abstract Document Pattern) 使您能夠處理其他非靜態屬性。此模式使用特性 (trait) 的概念來實現型別安全,並將不同類別的屬性分離為一組介面。 -真实世界例子 +真實世界範例 -> 考虑由多个部分组成的汽车。 但是,我们不知道特定汽车是否真的拥有所有零件,或者仅仅是零件中的一部分。 我们的汽车是动态而且非常灵活的。 +> 考慮由多個部分組成的汽車。但是,我們不知道特定汽車是否真的擁有所有零件,或者僅僅是零件中的一部分。我們的汽車是動態而且非常靈活的。 -通俗的说 +簡單的說 -> 抽象文档模式允许在对象不知道的情况下将属性附加到对象。 +> 抽象文件模式允許在物件不知道的情況下將屬性附加到物件上。 -维基百科说 +維基百科說 -> 面向对象的结构设计模式,用于组织松散类型的键值存储中的对象并使用类型化的视图公开数据。 该模式的目的是在强类型语言中实现组件之间的高度灵活性,在这种语言中,可以在不丢失类型安全支持的情况下,将新属性动态地添加到对象树中。 该模式利用特征将类的不同属性分成不同的接口。 +> 物件導向的結構設計模式,用於組織鬆散型別的鍵值儲存中的物件,並使用型別化的視圖公開資料。該模式的目的是在強型別語言中實現元件之間的高度靈活性,在這種語言中,可以在不遺失型別安全支援的情況下,將新屬性動態地新增到物件樹中。該模式利用特性 (trait) 將類別的不同屬性分成不同的介面。 -**程序示例** +**程式碼範例** -让我们首先定义基类`Document`和`AbstractDocument`。 它们基本上使对象拥有属性映射和任意数量的子对象。 +讓我們先定義基礎類別`Document`和`AbstractDocument`。 它們基本上使物件擁有屬性對映 (map) 和任意數量的子物件。 ```java public interface Document { @@ -74,7 +74,7 @@ public abstract class AbstractDocument implements Document { ... } ``` -接下来,我们定义一个枚举“属性”和一组类型,价格,模型和零件的接口。 这使我们能够为Car类创建静态外观的界面。 +接下來,我們定義一個列舉 `Property` 和一組關於型別、價格、模型和零件的介面。這使我們能夠為 `Car` 類別創建靜態外觀的介面。 ```java public enum Property { @@ -110,7 +110,7 @@ public interface HasParts extends Document { } ``` -现在我们准备介绍`Car`。 +現在我們準備介紹`Car`。 ```java public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts { @@ -121,7 +121,7 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart } ``` -最后是完整示例中的`Car`构造和使用方式。 +最後是完整範例中 `Car`的建構和使用方式。。 ```java LOGGER.info("Constructing parts and car"); @@ -162,19 +162,21 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart // door/Lambo/300 ``` -## 类图 +## 類別圖 ![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain") -## 适用性 +## 適用性 -使用抽象文档模式当 +在以下情況使用抽象文件模式: -* 需要即时添加新属性 -* 你想要一种灵活的方式来以树状结构组织域 -* 你想要更宽松的耦合系统 +* 需要即時新增新屬性時 -## 鸣谢 +* 想要一種靈活的方式以樹狀結構組織領域 (domain) 時 + +* 想要一個更鬆散耦合的系統時 + +## 參考資料和來源 * [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern) * [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf) diff --git a/localization/zh/abstract-document/etc/abstract-document.png b/localization/zh-TW/abstract-document/etc/abstract-document.png similarity index 100% rename from localization/zh/abstract-document/etc/abstract-document.png rename to localization/zh-TW/abstract-document/etc/abstract-document.png diff --git a/localization/zh-TW/abstract-factory/README.md b/localization/zh-TW/abstract-factory/README.md new file mode 100644 index 000000000000..414c1a8f0100 --- /dev/null +++ b/localization/zh-TW/abstract-factory/README.md @@ -0,0 +1,229 @@ +--- +title: Abstract Factory +shortTitle: Abstract Factory +category: Structural +language: zh-TW +tag: + - Extensibility +--- + +## 別稱 + +* Kit (套件) + +## 抽象工廠設計模式的意圖 + +Java 中的抽象工廠模式 (Abstract Factory pattern) 提供一個介面,用於創建一系列相關或相依的物件家族,而無需指定其具體類別,從而增強了軟體設計的模組化與靈活性。 + +## 抽象工廠模式的詳細解釋與真實世界範例 + +真實世界範例 + +> 想像一家傢俱公司,它使用 Java 中的抽象工廠模式來生產多種風格的傢俱:現代風、維多利亞風和鄉村風。每種風格都包含椅子、桌子和沙發等產品。為了確保每種風格內部的一致性,該公司使用了抽象工廠模式。 +> +> 在這個情境中,抽象工廠是一個用於創建相關傢俱物件家族(椅子、桌子、沙發)的介面。每個具體工廠(ModernFurnitureFactory、VictorianFurnitureFactory、RusticFurnitureFactory)都實作了這個抽象工廠介面,並創建一組符合特定風格的產品。如此一來,客戶端就可以創建一整套現代或維多利亞風格的傢俱,而無需擔心其實例化的細節。這不僅保持了風格的一致性,也讓更換不同風格的傢俱變得輕而易舉。 + +簡單來說 + +> 工廠中的工廠;一個將個別但相關/相依的工廠群組在一起,而無需指定其具體類別的工廠。 + +維基百科說 + +> 抽象工廠模式提供了一種方法,可以封裝一組具有共通主題的獨立工廠,而無需指定它們的具體類別。 + +類別圖 + +![Abstract Factory class diagram](./etc/abstract-factory.urm.png "Abstract Factory class diagram") + +## Java 中的抽象工廠程式碼範例 + +為了使用抽象工廠模式來創建一個王國,我們需要具有共通主題的物件。精靈王國需要精靈國王、精靈城堡和精靈軍隊;而獸人王國則需要獸人國王、獸人城堡和獸人軍隊。王國中的這些物件之間存在著相依性。 + +將上述的王國範例轉換為程式碼。首先,我們為王國中的物件定義一些介面和實作。 + +```java +public interface Castle { + String getDescription(); +} + +public interface King { + String getDescription(); +} + +public interface Army { + String getDescription(); +} + +// Elven implementations -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the elven castle!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfKing implements King { + static final String DESCRIPTION = "This is the elven king!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the elven Army!"; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// Orcish implementations similarly -> ... +``` + +接著,我們為王國工廠定義抽象和實作。 + +```java +public interface KingdomFactory { + Castle createCastle(); + + King createKing(); + + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + + @Override + public Castle createCastle() { + return new ElfCastle(); + } + + @Override + public King createKing() { + return new ElfKing(); + } + + @Override + public Army createArmy() { + return new ElfArmy(); + } +} + +// 獸人 (Orcish) 的實作也類似 -> ... +``` +現在,我們可以為我們不同的王國工廠設計一個工廠。在這個範例中,我們創建了 `FactoryMaker`,它負責返回 `ElfKingdomFactory` 或 O`OrcKingdomFactory` 的實例。客戶端可以使用 `FactoryMaker` 來創建所需的具體工廠,而該工廠又會生產出不同的具體物件(繼承自 `Army`, `King`, `Castle`)。在這個範例中,我們還使用了一個 enum 來參數化客戶端將請求哪種類型的王國工廠。 + +```java +public static class FactoryMaker { + + public enum KingdomType { + ELF, ORC + } + + public static KingdomFactory makeFactory(KingdomType type) { + return switch (type) { + case ELF -> new ElfKingdomFactory(); + case ORC -> new OrcKingdomFactory(); + }; + } +} +``` + +這是我們範例應用程式的主函式: + +```java +LOGGER.info("elf kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ELF); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); + +LOGGER.info("orc kingdom"); +createKingdom(Kingdom.FactoryMaker.KingdomType.ORC); +LOGGER.info(kingdom.getArmy().getDescription()); +LOGGER.info(kingdom.getCastle().getDescription()); +LOGGER.info(kingdom.getKing().getDescription()); +``` + +程式輸出: + +``` +07:35:46.340 [main] INFO com.iluwatar.abstractfactory.App -- elf kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the elven king! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- orc kingdom +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc army! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc castle! +07:35:46.343 [main] INFO com.iluwatar.abstractfactory.App -- This is the orc king! +``` + +## 在 Java 中何時使用抽象工廠模式 +在 Java 中,當您遇到以下情況時,請使用抽象工廠模式:: + +* 系統應與其產品的創建、組合和表示方式無關。 + +* 您需要用多個產品家族中的其中一個來配置系統。 + +* 必須同時使用一系列相關的產品物件,以強制保持一致性。 + +* 您希望提供一個產品的類別庫,只暴露它們的介面,而不是它們的實作。 + +* 相依物件的生命週期比消費者的生命週期短。 + +* 相依物件需要使用執行時期的值或參數來建構。 + +* 您需要在執行時期從一個家族中選擇要使用的產品。 + +* 新增新產品或家族時,不應要求修改現有程式碼。 + +## Java 抽象工廠模式教學 + +* [Abstract Factory Design Pattern in Java (DigitalOcean)](https://www.digitalocean.com/community/tutorials/abstract-factory-design-pattern-in-java) +* [Abstract Factory(Refactoring Guru)](https://refactoring.guru/design-patterns/abstract-factory) + +## 抽象工廠模式的優點與權衡 + +優點: + +* 靈活性:無需修改程式碼即可輕鬆切換產品家族。 + +* 解耦:客戶端程式碼只與抽象介面互動,提升了可移植性和可維護性。 + +* 可重用性:抽象工廠和產品有助於跨專案的元件重用。 + +* 可維護性:對個別產品家族的變更是局部的,簡化了更新過程。 + +權衡: + +* 複雜性:定義抽象介面和具體工廠會增加初期的開發開銷。 + +* 間接性:客戶端程式碼透過工廠間接與產品互動,可能會降低透明度。 + +## Java 中抽象工廠模式的實際應用 + +* Java Swing 的 `LookAndFeel` 類別,用於提供不同的外觀與感覺選項。 + +* Java Abstract Window Toolkit (AWT) 中的各種實作,用於創建不同的 GUI 元件。 + +* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) + +## 相關的 Java 設計模式 + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): 抽象工廠使用工廠方法來創建產品。 +* [Singleton](https://java-design-patterns.com/patterns/singleton/): 抽象工廠類別通常被實作為單例 +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/): 與抽象工廠類似,但更專注於以靈活的方式配置和管理一組相關物件。 + +## 參考資料與致謝 + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Design Patterns in Java](https://amzn.to/3Syw0vC) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3HWNf4U) diff --git a/localization/zh-TW/abstract-factory/etc/abstract-factory.urm.png b/localization/zh-TW/abstract-factory/etc/abstract-factory.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..836858a2c652f55723cff879d1058248e1d2799c GIT binary patch literal 82368 zcmbrmby$>L_Xf&qfgqqDU82$gDkZIeq%;W9NDti&(jp9qq_lMR&>`L3Ln%mi4Gm`x zzOVY#?>g5x^A7{eJkQ>1uf5iN-)rs1Uq(s<6P*|x1qB6DOjJk?1?Bo83d)svv@75* z^${He;0K+}OJy4!a|=fkJ$)M#5j`_KD{UJ+-Ft5x?-|L)JQ?u=AXZ#`~@!K5DR-PX%2sWyGC`EKk(W32NP|9>>)o|x{nz*z0pLO zWU)w!?=c{Vb4N>PG3#pP_DA8*;mTQe-=1{$IJ0mUQxJsQQ)}{=85n7DrD8xgBUFy3 zxOiw-*e3DtnPoGMJLOD+s>D?bSDcp?6&mRYDAa+}qoa*<&mN;IF?4*#bo5!QU9@ZP zVpL(?4iRMX_m;l1))`6awm*hmuj-Q0Czg~#a^%-ZcZc-}bHnrAIdQVv72+Om4?lbm zQsAIpsk*{1EzS-<7xGX zGF)EW*Ke4tuWf!>#ep*PRVHioJj42JF_mCnRwEDJb2&^sRIl$j{AZT@7f&kWCyj{= zG%B~1=3OfweHTno%*8i8m3`VN_FU#Np-nF}f)=w5+vi{9mNVljYR@>)(Cf{x{lIk< zIgf~KwR>96Vg=uFu$~>eU6UoWp2Wf@&lBCGl7hGQ znYH{0NZbj_A#E)wgvT$@JAFjiI2?DTQ9c+^SqIJd9*dl)yQ;GCXDB zp^r+wptSIr{k{p_T--=KiPs2rNPu}i``|f>I=Yy4f}K$Y3d%baF`*X<4jOAyH(hQm zlAvy(-N(6e&HvuU2|6?*+1>sQ2cwG8%`9lKz?2C1dsR@S|701<{rlG_2Lx9kMz9w` zcSL;Jj`?>+Y`WHhB#S=tE*zZkB)I6$#Kpx;x$Z7FCUkX0*C2QE<*QML+T@@2C|BQQ zVgCKgJ4%7!8-Kt5dix9H>fi6R-pjy{n-}?dER+HN`3?nz@VLu*c1Up9@vo_IwX-YT!utD~SADZE zqiVl?eZEpNJw3g>y-i0)$6+?v*4B1A@7mALXlVszLIx9GT!s66Z}iKqF?t&~Kdh&x z2PNYknVznd`65u#m@b`wpQnvN&hMs{qx^(}qYPZ&@bEBzfH^Ha9Yg8wC3yTe18%sw z+smJxo-Lmqv=!tTQl_Mo$en37H&JGuE^KYROTuBcHDUd7J;HXi5u5*!YH3bFf~Kyn z?%TKb*G={H(=4d|9=PD!SBfMa)x&H%uY5bMXijUWdu*h@p}q0EF~p{(rbp0N z^DVwNlvEq^#)G9yNqHFi@cK`)-C){OB(ZZ5@I6qUbvg_B4g8N}pNUe8A zvq?xw@;Yp3h1`E>Sn9I3B#WSZ4g1of(;AeTl2Y)dGCX{^!g>*lg0IW0rKQEHw;^3} zSbyh7`xBOeVr3}Pgw2i~y0?9A zc7J>$q&tR#-x=}h@Lic0&tz{eGb7{r*}+WuJXnkYb(_Jbt*H``>j!$wo1N5s)vfZ#&Ac3cGdUs^c|ZOp?QF^$IJW?%0F%iB^?Ln`HqGqlPZC zqAbaYQqytC==GQyI^hfjdiHJv0-=9^ZYU4?{8SIUsy!e6F-tLfpc^>S#qnx>iA<5M z*zxCx2zJ+F8x_N$j615(U=5ufi6`97h&2Yx@auf_$0i4A>gqnLMu~{;lF_W%2RBer zi=Fc|YMf@9ZWhNrc+=3(P@Zf~2;)BL;r-4JOOr-~`$8oYOf}|pIycuuA({$}zL=So z4c<3PPN(c=KF{C1mcZlKu%TY##0Gn$UU`>B>}Sk-C)=ho+|t_{90T1|ny9j8HkOu> z(r27&fhNb`aHt*~lqZq6C^5qNI3$UW1*^zt|7;pjk@pes!z1(`dp%Yj~U>FhtB~zQCd3(Eu zFlGqwz#-*QlQ&KrlarH%j(v$QCTrZ!k7(9$YEpmg{XhZoZ1%~N=(O6?;c3oseMJ(< zRD8P}s8kmF*~tONoT91S#-tcWXE*}~WGDk{?5RrI0O~Dra`K3X2z}1f+bWA7G`tMJ zXY1r7^-4Rl39Z4mEB7lex>r-Hb3^IUvN z$|`1d)4xgH_*hrdXskRDlAO(0SNyX8e*^CTZnj!4ii+Q=7ag@z@nvKAXkM9AK)boZo&}e2(;QFVJ?6ubp6j;6(7FJSq zGXVRDR^Op#*g}~%+h%!S?e@c-q?Z9pbBOKj`d{1U5NsdHWRYO@PP*r@T(&FqUZ~vm z8@I5r-S_q3YqPUft0RojganK#3NCE3o*D4Hwei761`7%C@wMhNwWBO<8pFQ8C~<63 zG3-#YATsWVsULY{g4PZQS2@*ElM2@pyWNHEarB(PBHeZzmD0jOF$sx5eOH*?^>c=S zh41>DdKep!CfDOV$8h=n!=>cl*}1u8(>m)#sk7t#(t07VgGPD;4Ka=?l{XQ*<|6H8+y%&l!CtB9@6~`43AwL^WnM%24F*0iiJ`GX9)@l zijR+vu01+A+@70EM$d!nPMFvATZhxiCRxpQXu2Kg1(Wl3P3OTuATMs`Ihnq{K}x!j z#ia{^2Z%n&yyjyC-$9rdL(iGD*qp90o2o4AB*aCSj^H5I2Th}&o1&+7JbGG#fg$^^ zt2ZX=+%FV+DB1ULD(%))YF!*5`Ko0b1E~_3+u^=(3RN^X(z(l_idB}|wx%{Pz2%@3 z#LFj8Vz##vvL|}FY{nxgrnCPt9TdVePV0rJd6zl|Byy-#%1@Jwd0lSt-F9{4`>#)0 zWWe8vIc|OP2nfK~A8rmHz}V~ziH&`AP+3(q_b;DX)|z>#XJEi#G?0>$^XU7O`7X%}uuAgs@;(fIL%5}wQpK2z3|bZz7ER5WXDD-{APs???Ycj#1e|4e zdwaab`5@$hi1$C=_%Y#yitYUpKi5bVw!Od4_75(6H~GG^)lmZe+B7LSdHM6}Toqf= zuZLv3PGMXu`w;D$cYpfAa}mQ?I{9I0tkGX6vX3}Bb#0=InT?H&mzVd!g9j`u^5vf% z{)Uq_!NYPRxvG($K3VOr3=a(r1qR;wF8&GN&^g3xeR4^;t~XtCfM2i=MRDGji71V> zK2wxEv}F7S@2gjzp+vF2mUvU`U}<7vA}2R6oUJrCIOxM52GDIF$ywn6hxN-Sxk=vm zN2gJ?m{To#0={Nf6GaGNx2Z`9zy9^Lq)??}ZM+y*?yZiFyqugI(s)0=ETPMMk|!Fl zD?;e3hIm6Mjqo+o5vNow`>XFkpbA>(ty|wv60hY%JOz1+pT7g^ z$Pv*tK;ag?a;0HxuIGunV-bf9i9GsvCFVPF?ID3ET`d$;6sm7o?8p#s>sBBXTH~~z zWkDqdJjzn=zOi_HQJEm0Dp<~4mqI4f#EB@mwvoT5{SY~A+P}c^+lcB)(kUbGpSkM+ zxERkol8X6X?(%&2M%c!bzlq(BX5mSY`xCYj%ev=&Qu(1*Po(Oh$K<4E!_xiS#YH_B zqasVp%7{{D-$(#Jk(Yzo+mkRAh2~R?lW>o)q*!XYU2s0t?+EvDUefq}j5aPk|QjebKBNY zjVoU&t%MD^Zkfm9UZ@?~9>X2?LL)ML;MfYwR@SY=+gI;U;{s23eiQgx>R?!#z5!JN z5eHjert!yMj_wk+>r<6!nv`&tGOvG_ugB)SrlV90&8)#=7F z+y1l*QnE9=T;^#sf%wZo^mB_a&Y=^t^g^TW%GRFsCi6*aa!bqi)!dnf$E|bh=;?oQ zcz}kBcIil9-3Kxyb?L}>Moe}4P`w0kyqZ`{wIANNUV6k@awc=vY>&K1&m2;Pyd#$D zA<;hi`iZncx;E|P5`*q4JBrgoUI>v=pP^&*Twl};UNhzds=OgI&k_I3nX@Q~y0yh; z$>Z04dkzG5+uBcN$1t?-*Hq|PH{Cr^5%EZ|C`zwT1q$g^;or=~le&JyZF@v%ll?69@mSPTy`@o2 zcWN_^>5q)gxWN6)$i{J(hS;#rXuf84QlQ!gaAdG&DP(>OEAhj3J7Mf-PIdd>NKa$y}RSRUK49hu{ z<_~Yem^JmgqTCKPn*9f{B>NLzK-H`83+Dy>Mke49XgA+v&Pu{}ak<1OjIfW)CCm=8 z-Zt-4xV{%^i>SE?mU6s31bXrzUoTnj;->MC$X2eLXIYu^0k$&t=wH;*;{`Vgb4| zsV1kV5j+kSvx^CWm3F4XB}P*Qy*=+)uwnJ7!66~pboPNCR2VgAdP92mLay`IcMC4r zku#|x(u~dp&uGfc@_7ytzH;$yR@X>Mnlp2_FOB9mE_7R8V@NLhL4WD3DMmw2^AevR zp6{D^e!^6OWxkn~av|VPVz8@r)k=3LK7D-Z5#|#Yw;u9f=EFod{-5)q)9en6=Mj7y zdG68^xi<5LWu)gjF%5GJeY`EI<15~$`sk6bcwC(-73g9%YhzkrJdU51zG;<*8JIE>Pv4$jh9nst>> z=>As^3akA@3in$k)73B9KaEUP!pONwxFe}GstMOt;4+hL`w*dYDMrHwwyUrA4>Vhd zjpnQugEE!!qXFlva!#OdLrZDJXVwTLKiSg0;*MQGrn5cmyuY+g|GLX_gx`HSnC*k6 z*2Ov5IElna&XLMnj&hC<8YT&R>lHM|JDq>w(zta@g)ur0vR-g<7zuxDEjisw2%XcY z!&b|1byhUzdLGHdSi$j;&vFmHltcxA&-B~MqMvzoT@tistpXzyW2|{^B#^97PCw$m z<$h1EJ|AvKylQByp)qH40(c`SOPZ$s!kf~D^@%4G?voX-h*W84{K6S7Bvb;QJbrie z9Zn+TsyL0PZg9B^X{mjv7Sq%h>GaWJ@y@sPo0YXDTk+5@&||CiCV$+CB@ZGZb3K(X zPS-tI8bv9t;Uc{`5)Q=RPG{tzy4p%G>3ED)rlvbInss@mf+{sQ?1Suv!|9>@DRgVF z6|o+3vEBM2dR`8vLa$Q|($&GGS*$m7?CfA0o6k@j zSH}#ydDjA8Iw4-8&h5tfO;gQ5j2{%dl!YXdB({q^vK@Mx)4al+VGQyEjvJF28$^1Y z)2!X@Sga@SkDt38OQ%@7pWk4ssZm2+nyMnZP$t>KUw6hJD6%C%;T>QF0h!cnI`oNR9qJBrUtXK1GvSFu`!z-+!|!64`nf^ zEIwNQ%u>}6&d{A_E6`uOc%d9Ex~|t5F$=GzI<(jus(kYPPEFb?BKk3h z&FOW+-tnT~;Kh%WW+oMXZHiNsbP*rP=BhMHL<+FgJU{1AL%Okecri_FZG6eM&APy+ z`sX9MmlhNtaJj3SL1y`lbe=>=@fvd@xi!6Nk+r~R5Xxrox=<(%Sn?F zmFz>b%209=jkMf+B66GA*wxh@OYL%Zyip`vI>RvK1eSRN21EF@z>Bi>2R@Aa(p$Q9BhN#uK z2?yX~(hbiIa1T!`&js_JSB03@9_{S*YEoprX#ZSnO=dQ4Id`LoRkm*fglL$b&k?JM za;S0o`Yqz2mj&A%SNV0*Q)NuX9v8b`xCdZBg5wii^AtPV8( zu{RW2JLJ@9F~tS2s0AHg-wq0QINmGCHN6RlQtg>t#LD`QSA+G}O(L8x++2$FZBO=B zw`Q9;N0{RH;`ws76WmViOwX4OdiG>_uAx*UwBm({E+5yOZ`2vw(DJN&?qyy+v2}$Oynu8V7DXxUnVEEb%4C!9& zFw}qxUfN3^uwLS28-=wiUX0JMYL3EQnD^KIgKQ)Lw!MA^t>qh(R}1Pdg6tkwvhO?l z{~cD|*9nUAjP#F0vt>JnAPYbhRSC?uo+>+ZvQD-Ww_co?x4>|WCTeQq&~K#xv=dXj$XL-V+X|1An?nWq{zm4YS%nB@i%$No*A{@H6}6M&QU!j zdw!SO&PDKZg3n7?@pNJ6iiH0?V}e)A7pJ>2b#7!GVTJRW#2@)PQ?F%f)Ib`2_Y=b; zxLg(HW6Py>H4v$IS8v$Fvly@%U&uB_s`Zt8maD;`$^k-GrF}ku@esA^-QGq;PE9k2 zv1*clPmxZmn-D`mm)ttWEi4V$!na2PKInzeI%^K)(^G3SS5m+)Z}a4vjK`!M1;aP* z4c1Rv6oQZp}UxWcG*NvA{yGxXG6=&bql^8Ad@ zi%z$s5K;7hr$@>>`1@8aIDEEw&hR8vd|c+Zp6si`iCx#XdNZJ3ezCCMY-G|gN%=F( z#MtqCdp=jI%`bd2ZIHE_N%#DC&s<72AgO`w06XM`t<&_A>ezDY#RCpgr!)0AYFq-Q zwc?^8AR4D6s+X=w4xaiQOY3^^%?5n|pfGzTru3d$jg_yJ)1O(T56!W_joFe@c-_{t z4PaUzR%*fmcyw|!Zpdvb)8xI4(fGZlQEmD(6lNp*+MUGPflmEFsZ6HorsCtucZ)NI zGY~oZyVn@59XW`wZDct)dSYR!izVeeEbPXQ#CH2dDH7XD@UFUP@73aJl>l^YmcBpCsI*1s4cSG6?Fs2 zPKT(A2&kok&n$#emU!r(AvkxA>*^OTW|ciOIPdt+md){@WTBg@}6Q@-GwG;$bQ*3ve=Bl5QI9IMgL zb&tZ;=NBJCXK!h-C5$dbkXS;6Zn3TxmY)itVeBqzdf3{SX-2_OW*Q(3?tg8O#C4Q${m#MkN z8en%V9TOYdGUHu?bYs4yg#mAWS;b1NK(_C{Cueit`J`>SQIemlFGaIqkF&M0jO_g` z_5~e1&&a0Mw}nP|ePQ+$=e7!Wk9eBkHbuaR!~ow@1|hFpbFyUo38m^m>yh8-Z6ds~ zO^Yr2LV1Ii92*h`Nf%4JKhfWe#2sH(SInmv}Lc%NiI*@|E{64{Z{IN3GdpoxQ&E5q5lz2ht zav3CO36KG|MOhE^mw54tJw#C#j2FmJ|5KL%rtC9)MRz$;Z&?iOPrswY!=kji;4Vw- z;0F>ZHe~obZvSOCG6~)M!@NZPQ#766PCkYo?f>&S5pDOu4cd_ZXVzT;8UXS>4aobv zB0^e%O8v$t^cnv;k*Ir)qfSSkQ*4wKZnl8 zWSpcD3Vt9Jg2xcbS5JQt20x*ZFoDuFpud41|LAW-zw$Iv@1j)wLtl#vQ~|21K2O~# zP6x63=@XejNR4wDt~shlpW-iX-k8ZB-coS-c0p}E$3LarWj#yLlk_1u&y@DT zh_QywW?_~^C(Ph%+ucS}zYfagiPw-ykJ!T^v}BAw?I{+h!pI){;b_0E2!l~Rz=18i z@(L6#Y>9D2_W5te@fX6^w)q!R`O9X9DQyOJ4Ngj`q~UKv=rQLBEq~7YmqWz~-4A$N z2|~7D*^|_tk+~_uN5}Mb3(2oF2o=?ZvX&cT5*mR5#?EZ>Hv;CKit?d4duFL>Po!Ld zCsRiEx@#6l41EG`XL}&S^aD|j2OCeeAxGF$_BfV5^Xc26jtP*G3Uy+dp$D6-$q=uP zjKAD~CZr8Q)Egi7naj33S%(uNAPGu5d<#vPT0=zMB6B^I#-GA%Y+$OU7cj(%Oy}wQ z3Ak2n=TlYo+}r5Up7D|T{j&(Q=Iyze{iW@{R5hyXj=Mf@%-TK#uElsUCH%M-=;JbY z`H;bUO~3UC0t@4$(5(jvaYCg3gyfP_EV^qAeZLX#fPW7Ab~}ywjC)=G!3?Ud?!#+0 zoFeJFqo`C)HX7?0jBjg7!x zT~cOJ+VnRWS3R$S!Vf-YH8Q$)~|8Xx@L__!UPU;*94+ zE=I;GYYZE_8*U)qAHnjku2!n<8P2|gkN?tqnx_qRcTLTGR%A?77;p;dL5%Sk&QvIC>T2RBv8X58YG87CP=v?LHR9Ltnkm!MGiD4VN z)I>@<|N1~Qo93X6(_G7V$t#9iWbn8NDyCt?u4=w1;Igy`bHxa36}3bBI$b- zWBfz9tzsP6?-9>0jgFwvr=aE59l?!QDYzInu*5dBhaARgRA+e#l=H^1H@;bo`^>ZVGfO2zQA9!_0B{d$f>eQfHouuEh_6BA{J?O8SDs9?bRj;D0jy-=(A&9{MgM9$Cm61fpTkx!~x z@7jIyKUbA~XJ;C{lb@J?)B4RRPJ(~^x1gX2vo~@Ky8`2j*8EX;UKkV zbwo1ZiB8Hl$^np7BQDGu&zZY9?M#YS)D=naxWuG>6#wC=P+3;Ff3o}#D@07wHG%(8 z7?b+W-m-cYhhOpzh3E4n_CM2IR>}E6^6B=Lc0@DIbo)?e`}0Js`oi!)k*_vf+JJ!1^%T z?YaxTJOm}0x7lxWi{qc8EeurTWhH;B*&s4?_cJ!}YERjw{ndW3Y2&zHZCyMJwH&=* zvijeqZp1xQ`lnd(6GdFqu0kV*HJ}n|o_7>X$3nb@aPF4G<|3`GV0!yH@t<(vjxfQW z7#6Ur5}py^DSv3yau?IQa}qhg zh<&Dq9%fgy4nd)cF~5b%a^KZ$c%dWQqSEmMvC3TC*~PbtwH*S&wp^|dYKN~ z4+(xT2>=Ecu1^$Zye6RZ+xwS=*pEMG?n*w8aN7R_{2@;uX1Ods-vEgFWTb00ZvG=+ z6Bgwgq=`xd*xEdbjEj4uAt`@%GRTPH(!gqo6DWk&mt`?L9uNF!Lz11&yq(VDipzwk z^|~u5i*H4GUs`l*VFlhdFyQI*ET(qAv+N+{172ru{MoT*5RJ5%`E<2Mc(~r#@$kW> zW+%Cxxw%MoIIZ^l!pK5TT=LLB%?YZ$IS&djyteLJWLqX)ceBbh@@3{$AR%q1| zu;S(^wDYmsh5EIk7_ZJ^5)YLF-ETv^NVnl|+iUFVa;A|qa<%k8;Q*kc3e%CF0ANxQ zza-Rn#D&pNSJr|%&GnK!A!kP5FDnuAt>yD6t~sekoAobzFLgg8xA=H4gfc!Li1F=q zcOlhm{&2bTK~!8EV|Qf&-`S?IytP}V@Xtg)6<|DB{@SVtlrP4M4eSSn!uV5DYz;NI z9Cx(rLb(kE29tXd4nPMcJ>#|OjGH65Ft~v($71(Mtl5CV_`twhWFqI$X=(c+Se0$n zBlhLy;|cBPZ6}beeZckvjep0B2`rQB+%|^fcM3mL(UE~=ulPxcY)DY%?mvN0{u`do z#kWhqEq)i{=1it3*O6VO6<6?>B03G7I5XQo_hG?2NIu17g{y2maojEag|QVCoG_bp z_=nss$vQS(2q*x6s*ED%sQn|QJk|r-Ed6RQ;Blej7U&ruM>$U@wNj0a`vFU5;kT@55oD(I$hhVkQJa?)!}Isjer- z^K#3l1u~k8o0S@dpjHK31fIrln3Lxy7xJh|y_y_PdMQ{M3#zpG)qYsHn}g}R2ekE> zOss$5C#)o~qdT>hU|$lT4O!%_@qnr*xhTo_iQIcd&2*B3^mA%#q;T)Qe6Z3q41iw& zMp$3(2L?WT%|!3Gl_DS$URYc`j}3iIt6Dk~!DxMCP!6isCVh#*Dk^If?xZGzEuUlD z2Ghn;xrX>UX55MFEj;KKtDGStIb9Lf+?}Zwwx&yKYBcP2xT8;99D1j!E^2Zft-nJ= zhBGda4f1WYv7HH*eOCe9CV^K-fZZ-zKD6M-K7r6EH+h$slG>3K=^TQ6!)mv3hmG#p zCVx{VrhUdoAELLJ7&{;^P|uz=<4nP@TZh z=Zp-;qmJCv z%xpSSKA@|sc-DEJ@Mz}A8Ae3RZe`SgPAojl-XOQEf3}H+Cla<~P zX7m>Ojd1VAwBa-8*I!(DU|A3l4qAMAnp4kfoSn**{lx>~?s{M94QbEI{(AiCX|PJg z8CzITQ&SvhA4_4~0s3|p$6TNTTj;GbtaLR{17R{__5K|_yZm!(WL^s$eJ+m+0Lf~h zi%1=om7JRTGL#xNZjWt5ak?&%K6DxBpY(x9Z_r~yke^JaJ0WIy8Mrb)qYa7|)ow=k zgr=Zkk6v@S6xqg-a!*5&VX`pW)hiK}_WP@&+5i!oeCF>V6aYO&+msAMruZJl$%H*w}E@sO3rUTbvh(2NlB<{rjd9wKN(mf50h_ zP-X|>sY!e%9&OB5wyO^+JzIVJaEAvUV6loyb{=c}(Ye-iS{f3r66d_yB9W8N>mW!} z7+I^RJWA~c5Pf!d$k&9M4iGZXl>|d($^wuni8H4so_Pv09%qKiGL+T%-c4{B*grcU zaRt;$SXe+S(LPg-y}q7dOr7@&V79_9dyJ`v+2GkF?L@p zh|O+Wx9G?MP5rTkQ*g(fAN6p4nfp6xu1Ep=E4E9J#Kyz=Vrlwxsw}=q`oy>SYn8ou{)Hv?m02T%OFMTqI_k$IIO0LjN z297dz`wi06h>a=!Z|9i%OZ{To$$4rw%L-_nK;3DZ?|oUsXGg@Kbk+Envb=LRJzmqq zq8wx!SN0hvr&<+$yJ_8P#`FX?bQ~T!Q;Y8C{OeGwjg)7XYF?9ciU4poEx=l!vUm~h zO~6=Uoe+^+K%S#mm*q=i+6k>rCh5!~t0NOm3e;cQ`Z^Akk(vb+v-)5TdaDXaT$8XvK&lT-y9Qa1*)cHcM60z}5_ z;2|H`pNWG_$@S^eChPvfmyh&YTn69nu7(9r*l&_2@4eTb0tNL2Vq|tMut7}Ml(#^Q zsc2666?WIgr^3n#tG%!13K~uRX!jbI+^DmLP|Snc@D5%*)|OWttgUT0OqSQd!n4lv z(BT?PIxO54dEVmGJ=AWgkLUi|@I#_z$_c3tWjUXo07dH#{~eIoC_@Qh(QYS1?n6m> zkURN^lTB1Zrf#?X*ZJ}6Z-to8YdkH*k|44`{=Jp_dJj?a|_FfEi zJF6l-fBrKN{I(H_PxXO_JWGSz2f8@P5#34gr?LSNnJ=rO>C^3=*S#s}%Xu?(c$k|b zdn%FjDF>c$Hq~W4?5oP8Q9ZW1C>D+IQ{4p+W|E2OQdjU7Z)CD`-svfKcyd^^xv;-6 zl?N=4bBi(qZlP1PvcBT4wFr80_Ev@?V3Sn@t)O9rKQ_xMi(SyqE?>P$9I|pJ?@3v& z1eDkLT)K}Cr>F>&*4{keEimlAzm{q_p>TpIx}8AD1`<4w1a%E)2J=83>n1jmpG=Lc zvNa~VQz(8sSpTacBXnPN%KrAnOt3sw7cK?s9pcI&9TBA$4{UACJ})e;!z<8UKXbHl zj^k3yR}VQR;&rQV|zE6`}{J z^Ky`x?u0Fc&J~2;9G{3c!@}#EX%4rQVGw$5LGk8nc!rRHsO74vDnYuzPznEJ^dBIs zJqTa6O2Y9yXfEwfQ!oz}J&jYSQRn?mJl=zPosmFES{Z51X|+-P?ODsc*A_l8lYIH` zEKD{?7Q8?h2Hencn3~Q=8X!$9GL@NhY3IEDKqc5R9HuDLM87PJ`m1vegz%9cP&w^t<<^$2yA1hq%i`M@R(L;R5a8M7}s9_*|T@Ho4I*AH?u*##QGJm(+C62Qg^IBcT zXg9G6;ujTGsYY?2Am0=9zNtWPZj2Pzqd^k4V0O|_Wb(X+>W3Q(nw*@bRA9d zO`SWnOKc#mm#;=v~bI46`Qr#6Z2glbrYJRp0uk3-EB3?(#kq5J06p&P% zDA1$qP4iF>px z%dql6GkL$!a40E3mROh(9{`!I?(R1*h1Bnn3eDMf4v!cuEefn{9xcwzwP&%@W7fr# zoQKf~E+15ay$X0_BC3^iM?QS3mFT>{C{F%eAJUhjJJ2Ea{uGebJdiY}wu z6ma$i$Zfr@ooR(XRg6ob=r}Z+=Ni-dIOB=mh2kXI)tkRke|v13II5m^Sj>lsif^@q zv+bcx*!(8T8`F#Pox6^rLBSLkK_^&2Fyr*z*kvYA+F627px?h729l)&bR|bfxm97B zcC~}F5Fh65i9J}l?mWw8jkku8CHi(&s;L1qNCrFC#1$d&f}CA)Y5QWetxfNTm- z>)N9jw-w!?4g*(jpD$2O$2_>j7sN#VE-7dzD1kB7n-lSjVJeb<$!a-W5T zRe0-9V5-xQrl`UB+>|NiV?p;Y?8{GNs`=}etFqx0Q)(-IYboYz1B+?eDPXPl~X z|9WmDOp7OfLMtv9Og{BvP0awHjS8}FpLCqQb%e{)E6_@0ni?*N+nGQAT12l%|LoaV zKa(X<`rl<0e8{lX@pAgT4QdQ{0-JFyK5Ldu8TR!%mx2*8p(F!AqMuL?L_iYQ5)ETE z84Ul?;oE@}>2WJ3C$-N{OM@vA)sGXR+c_IT&$7Fgo?us8 zSePc+&&;RVeY++0+c&(~mW+(y{T0RJ$jMsQ-E5@?$`4FKr|+v2%Tb*Gq(e@AH77TK z!%${!AXUZ;^_pS~mBc0XVH{KyvFCOC)W#08Sr&pTfYz|d4gVQd1ycp&RwMe`&c=sW z#6+_dOJn!(<53r3W2a7B-N9A%!Lkt1;*E4^X=^BFox%fUF6T`RwYe79r_eK6Dqd$h zj_&q1QZ1e%U+9j1;>pCDlEF!fNm1PPx7;ZXjh13Llj)!VK^pQEMZB<-G;%t{4&Q-R zKWtoDHeDiv*CWVQqU{R|_|IC*sj0ZP6ynRf%W}1_51>X04~269*V+|fyezQRUATR% zuMdKLS%1p8lErKde8d1L`Y~nxrjO4iC}?l z`!&!OHkn2(c^p>i4tihU9wjB9WJe6*CvrpH`n#C?8l$S$|IJsbB8*^0rukvj0x9Jv z?D-H+;gyvzlfu81CYE)&a2uOP24-ebjOtaTZyBry&4H;%!*=RGkx0g^otKOsa~@|B zoEPSGkH1S=ourgsn&V@|Cpl=|5l*MGU?%SOAEsf9dC7Z}jDK0OR+O6ZZXr@J9LX_r zIek5nVW;*f1D-*a395*&va;PR!rO#P-5uS&j~8VATg{22vchz_yfDFe_~y+C6&R!; z0x%LN{o0iDDq$GHgEEDo9#W(}So@*cgUQ`WFwg(QOXFZBJ| zi(!vGU~`Y&t%Un|qFvHvJP;;jfu0s^cKGUFQQMMz1!xTfu&unwt%~I-j(B*HHe*Rw z7JIaC){Hy6%Yb1NK)H|gU+R`iBPH+3~ zV|NIdPkoRTOZ&3+akIRfF-%@6_K=QapNy}1abxO2V>Tq70Xxz`Vcz*)0((=&OC1HD z`Ll{ucwdpj(AyU}7?@94@4D=EM_wA^%r25aDSE_lZ|Mgpr2-f`DB3)GFoWG!vnQ{I zqJw4cdzbA)@5dwpHsc8Hi(7Q1AG5PC|EN{r7jqbhl5y@Z0@V8-3;*cl7_)P<387hW zxzeuWMs(2_E=?(DU;wlq(o&W4$lYf!-CmXnAT_b|FfzGL&|=_s%QAVs(l#4tymJF; z%=z1EG2C=`xcuVH5`uL2OnZrb^2f9xz5@+_AH~Izl9H}1^irs%b=9?+w6>bh*Gkz= zRW66Uvc~=)FpCq+HU5uhT*|?`kbcqOwTV0I0nP)`lF9fO_6K~R1e24MG{D1TSvTe8 zCb3jD24vshU>bnnhoI&p>|H7IAQmZR$k>53D2=8JKyYQ`4|0`Sx__r`B zr7KBI&i5*ct#hh77jqO8u{#3@yujJ6s`4Re>5Bu=wJVt0d`mpP({V_U3N`1#*4%h8 z%LCy(c(o%|ovcjLDCm93Kvr3vA{+hS$cOSVEOQYj zJ@j_?ug5O4y*(wr)uE$Tx_55i{aI}Kw}z>Izs&CwcF5+WAgUtJAJj+T=3R*D8uWiO zK}qP|NxS>>vPp{IDOknJzO2iJwluKaWGV@;DQ0-%yJkQ3MtnVDu*qC4(~5%h z{M8#g8)S=OM5fKqu#g7>`-RB3)-nmW!3HN>uH99_?=`_VwTytt+pJduJ zrvPu~MGvym>zEjJw|S;ZaqQaln;=d{JqG7K&qJf5#p_VOQ#btm{R=-zh%_c$>9pag zHY(e~a!r)}$R~2ly3EoI9>?J}z?B+lwtHN3cb=bz*!DS?y;m&KntM+nbkLu($3f0s z8##Nw^RD#t^ud`Ea12w;XOjCuy)Rfq3Qcw2gYU&L>GEJoFDp2EdMLIUrcv45tdlNx zn(UMNk^kqkJ2O&Q|83gHBdv)N1dHZ(*ui<)A2UFPdO0~F z(igWlsZFlu@>Ud*Cm|)``6k-Y!nom>;LvVnRnWbN7DL;fJfR4 zmjzml;wUfrZ{f5_YA=TgHMIL&VwK33-l&njoNULBj?{}ig!L*t0+*c z*Wh!dM*d^&^2s_&=tu*CSLOfLU!8Uj#seCt!J~cL4j0T(Q2OwYH@v7#s1)|lbc!Q( zeCr+;T&$^kbMx{(C~Y3VRhDMF!Wh0|O+6i?K-+w*{w6qHm}_4=KmvdI=PC288(>&k zx8jvx#-itrW{4W7=e`&%GQU#({G(QM?B~O0z9RcD3B7Y#FNC=EE1mEA%pC5F z?*?GhV$cn5&kq`$+UdNglH`_V_Rv79JKIc2ctBrnM8EWNB;YAJDDS=;viumUzu{HB zT0ME|12hZHZTT%nut#u%RMN>=eeU@`->xAY$>?x$%xM3{e~MLC!*qFxcejzld@f~^ z;L`4V(3s%HJ8~W%D0yRs_x!ksnZIXRlu~V&(85`Y*;@mvhStgGfLTq7lvSdf{^!@x zF2DYi={$mUHpb#4ug;Am$?0=9@g}Jx7hHdDf`J$nZn{BB>BPC0w3JHa>@YV;i-I!f zYkm%%vvj$WZg~pH&Vh;6Q^AR+QcZ_8*lSpwJUolQ+4(3!cNQgWT;Ox@NY^}W<@XSE z(8M}_!O$Wwdz-SJP7Cbdx4$>#-tsa<*>!?d#ZJQihq3! z)n{8VsLoFsrmOM zcn-<4AHLU{ZBvapEP1gESp?(Rla}PIG5oA-`=wL@RI|%GOzG7oTMU^}SRfg6N%)5u zPB6k}(W`LxfZK{bNjPmW9wqszR0C+)tE*V?8}x7EksQWb+K@#uoBjEysJ z^=zZCC+G57Gt=Ks;+;26TSDt@AKJcMtO3I?I!IAz`(QGn!}yzOpUS!rbFi>vsjyK^F~vy^Y*q@X%=)!TEM z(nf@^X*`s=#_UM%=P!F_zNmmu(B!q4${1*qAto5f2hT=VT|0=%5%0FDPYH#tq6fJ! z)AzMPLK9QDQ&#U>s?aQ^GE9>kEqW)BxASUZ-R|^v_rgAwmNGy`ucCbMF)6Z6>)l8I zeEXYqzF=7K6t^_A342FCvt-OOTv-d!Q&qb`L-&x#!k-^~$Vf0{h z*!AJqP4nfYjHSQMV7%M=W}*i&{DPk6tyURz>(?yb1;-YaUyhu;h=H+fzvy!ke^!4%o))D`(q+vYL2fOkjZAcIa$ z+GWBfCtegIr#|t(q%ls9A74mWd{BkRhufZLjY2<>iMO+g>4U7^^Tmg@I`5&yW*r^p@vN&#qSbDlQD>hQWo%epu_TE#q&DpWME324_oC0K*4* zvS57i-B@+&;In;DUzdnxMr7*{mIPX<#EqGIJ|icfM-^$D_Se zDZ4|PP`Og1M%n#%DMqcPX+R5OVv2Pnvb~@Vb#J3zany9)ex9VdE0;faT2|0GTB86H z*HAK}&Io+O^Vivgs@QG5VSCk*Wf~e>eE6G~#?xz-qRTa zO5r(cMly_=i(q|P1nVuH^ew;hnIXm$W>%R~unX^e80R^ByEKS2VdfnN@_X7xH_t(t zLSrE%sOpx1Y?e}3zv0zDF2@tguE>o;&Ifw#&hL;jn*+qDK$~~RW)8FOcy>XkL2^_+IL)< zVWyH7*9LfQv5fewDGE)60TxS&&FUl@l$Jz0Uc%Shm|p%SuYT#CYGDkB2okfpjzM(I z%@I7g(6j-_^Sc`~G)mbu`@732gY`PrvBJ>V%=E;GdTJUPsFqXMh1~gl`CK~5?=xfG z98mxHflCC6^0_$A^zk9k5mC_YPV8zq=8SLZ{A6F-zHx4AtwFR#blzTMo5wFZObLzp!a1- z7`KmDH(Q z2S`Y2e>1*lCUS=d!eZmZkX$&=|;^w=~Cz z%^F&26#}_rOWL^)RWHNaS&v+4_w3=#(se4c&=f0wMsDLa+Mt6!cahrx#R7#1=qYNxeDr zV!9r;fWsc=z0bKl+0z)oM-D}sE$tl5;foF@_oEI9P;o6-fOWcGwDoqXHKaN)W+(aB^4LHoZ?HIrRDvZ-GsFtItp@q zu&Va>`LyU;;2l$qk?(fh=t@*R4n9n5?Bpc*w5>f0zvm&JPj26N7ujlP{KRFfAz%A3 z@x{wRu2*inW_lvb|2#wjt4QLi!G-rV%0JTXAKTLJp3F`U+PT!zE6M3iXJnr~I1>Rh zzZk(0K=@%C+}z=NMF40Pn9}&&5Dv^PHK+gd5RmL`;C{aT)@KH8y3?VA1fog1aP^=E=oTuLU zh9Do82%t;Xiqi6LA9@5J8WEk>b+2X**203$}wDiD1C=C zvvN+-Sgn6QF%a#W)e`;op-i_671ji-_H3vGa_{IMn~RGZOwY)ew4>{Ua;A>}w=TTt z%hpGgrd{~048=ITwYwo}*VOALsTLCflAOc3B;65}@I0*B`%R1To{i&&*DYVp*l~=O zlgCE?YFE?uW$>;{!j=8lF(ts|d3VW{bLx{52eh!#YGsc3+clKr~XN4d=K)vnRhMv`IE^UNHY<^9bQ zdHR(e&=Dm3BjG2bttBVeIgsE<*w1RVl-#8&bCBYQ?asCpcC&-@Ui?%#ptjr=euA)L zILXM+5PnCEeqkXqG^J_WNLS3VqkCIk30brrGu8cr-S;obEr9@du(h0sF8z?EB-f1= zoA1rqYKdG=3Z<)xviWg&sx=#buF}vqz+?ytNc24Q_;(-Ko(Jbhpo+aG$U$^Pt}O2h zK^Eh;wEXqia{PHJHuL$Fp`hz~b{h+Sak?4mjj=xTId$&JZIbL3lIxPZzEN!-hn~b< zcr4?#M&^(t#V38@ge3d>>wZ@r3BSI2j^@M!hcn`RG(k+_l}GnTW;gvt8Wgn{Lc~nX zGPAZ1QM;pk#T<+ry__5ztLYq!Z#ERXd5PR=`M)Qb?Pwb$SY}Kn$|kQAnlN^Z$yIr& zhP-wl`DgG-hEfacnS)L3UbNUVgGxb61%sE znWd@e34gq+RAAWK(?dD9N5rKhq(f@G^K%z5UbL8-t3R0V_C@ophkGmrwkszjq?N3m z6yI|>yRxxy;rz|c939N<_mH!DX!z1V`yp^he=aUkmN@Q@5&y-#^ZL_3j*ywnII6KV zdbWbYt7D+d^5H_Ke7}oX#L9#XE;U}V+KKH*p}6lw_c6j+b54Azts8TjJzI`Q-jvDH zU@zT^E5@WsRv>vquPB-mjyOM4+4sqthiEv@z-m1oX|y_dB4abc@v!FAKaw!*T)bKE zq96*lJyS<#xk>8F^Y=9#O%l|To{7nGxm14o-2!z$j8-i)Mg-iSkdnGe%p(rX=kS;k z>N}H>JbUSS9SM}FH`<4JbjT=@6|+XSmjBWpWMAu)7vba@^!E!lR&pPF@st;&F520=zogxyf$R*L8Lj-Wf25ry^Q z5DsE=YfBbE{_vp?XUoz^+WtoWw=AvbBsm&78@Uea(}G?9ilcALts_RYd1LPlulbEa z=KiXub4lHd#eZlhB88E5yLGNr~8PU*v1ALXpWG zO;_4Mc0+@NC|v0>i!bI{%QRET`t5g%n63E8td$aRb%<71`&{~G&fk}#CL2=p^W$~D zzAO{k*RZyUYFr+hgT?D^zBXx8Z!pF_6f50%m638zJ ztA=zY^GvtL+vv_wwoP1b-*@_$&E1C3YQU32g?e}3UuCng%u+b9Z67NJ(|5*h0;Gq+r;VBcYU~Jl*a*EBuXq=KyQz;95 zE*30B4<+fkIDgu9LBQfFn;d9nR8MDOw6S=|NueoO$VIq{5;I==-j@?$D zutOD>9aoz-e6V-eHPW#zR-$02~j7;KasxpgTsp=gwy^dKj8aYu; z>n)v0ksF(Co0mz<76wLh*G?-}UhtuIFq6e#kJkC?k#w9FmAGeU`l@4Iu0e6iLQ_nH zXOI~aA?c(Pom&sfochTo3Tb6|(mQd+`0HAF49k}iOCo*cth)qSbJ)yilU}!eul7pa zU2Ud}NLk+8?9b8)?$Xk$3s}vV%wnF5zhnyyH1MGFF7jY++xEaBp6RZMUWF&LYq?Ih zaEHsM1HBnz&|Na4G#lL*wJrzUAeC!tPK(+3U>};-v$2G_@JP#8594)R2lB}q;kHPx z$3^M{#Tt#9b!R-;lgs*h_h{%#K8cjvMGT`Q9U`iy>iUuEeOi^SQsi{y#o#^Eny>$l zJJJ*1T8*k=+jDx;t(8mSwLW*d73%nZ!kd|&H#x9g3*&I+;}vi{+n1%K_~wnDwOR%9Bx(nulCIi6m*nFe=(kXZqoj8ApZbVosp-#cp!(~ z`)EGnm1+f<@ozd;Rwq4~W5XVoA;;LGpKca_b%nk!Wm^d7Tq1E0!e4TdJZnT1=Uvlu zA4bc^Uf5S3W2DI_E97SK56c_tm^~FY#4-DoGNM2E1$uHHnbzRJ!mHAK>lenV#H7{` zT||A;3qNT$9+cP!TQ5~Mcs?zE+DJ63*dsldg@J-t9lD7Kd=|iD8f(W8(#qp2RdNR{o99`@x_2^e##w)Hrv>I(WQkN71RU<Nub+T)Ii45^A9rPq~0^EUxc%=VC0<5UFo=0{f7p2&g=zDD=+k$ZiUsgweDn75OxQFFu$;GDEd@k$%^<{=J zvp7{Hdy~0ilIT5g9y^0($7b;TEY4Lcr{BBW-&h6tqSZRXp4TH}6>};Jb_z}*b1r|O z+DL94Vd=r1e*$BYc%xm`e)~3kK%Y?wFJe;#Z64Iod(Y2{%H?Qo7A-j$Ty5(Y$}Hn{ zzim=3dMo9OeVt5T%uwERUhq)3$wF(c9Hw6sK0o3xl}SQ-1s1|sp!>|bxcG>iZS!!} z?Auk1j!#y5%1(t|P{rSMn8op%I|rfAktMoTjf2A8pgW;e-W70V?4P0k|NR(e=N!F$ zJ_Fe=C+>>!)EU2}ivP9tts^(D2NBxDJE2YdoTYMn@+3${fV+4?_KQ=(5*>#fOU3ZkW4Y>9L;TchuEc!V zKdbh2BebxN6b`7{TM-%X=Fz888=x9|`q5T*Xs;LAZ#S8c4#NKxN-R5LZKVwjt)WS{v{bll)5LVE z$-#l`%1K6#F}a4iBkPE%EYIuW@BEKZa~!(>Y9{Ks`)Hxhf#9>Uu^etCQSKrD4$8u}Qp-W||>4}gk zks`#2Fle4Ynpv_zZVSWcwOAV8>1jv6eth)PRM^&2^9m(GHgeZmiF`$ZOrZrxJ?71a zNt+d}_T$7fXi2~NThhrQ0=hdL_Fdxv^5KV5JY>XN?Dulr$_^|aah)L9IX(rq&+faQ z?YcB=_fA55)rHzmfP%EcgH8Dr!I$IKtBhqS>O9c`mkw8_qNSz%$G`n-AO1O5G?=RF ze3@8HH3JbWtZGYsh}yhj07{&j_ajY`(bmdI!Glv#J#Sn)x7OM>JEetdmAWT?e4}GG z)ukO&D>mnSyX2qu7jGulKdz3NK)xb;Siw@Qc_ibTQCWD&QcaYbyPAANw*Ud&MS`9J z2q;H$;MDO7O4HiR9AjL#4$OvrDi&|GYj|6%3WT)XV#?8xUtYS4-fX7xpPihY1>N7Y z$00#;&R&{{3fHOjs?2#K8|Y0es!e%jp*1>S2fH!kHbQd6B){^n`Mw;P!m!VuWl|Kd zR~Ko6+e#zuguRQiJM1>XeMs#hG+O*O5C{=qXgXX<(4XsP(;b>}Hjk zYRF_`gr}F<-Tkcrqla+v)!IaPn&T?u={p(k?m$Jm?VZMub%&So|C$YMRF5r5cI%XV ziKYqmVUjZQna2IyYR$%5kq5+sbY-F3CNn?A;t9BawypoEOMe&c&sn!yUn7O%! z5Kohzk$6M$0gz+?aYgymLq1^yt8J z!;4CV!PPa=Vs-LoPsTR%29X{P@ytM0{@xZ3<)<0<_wl77BeN!!fki9|>bN$|J-Pvb zapg;x%hs58^vbCfEj{S^*i@g~;zj80?>|N1_XYMAErX`Ql^9p~}ABIvPL>`&4C~Ks$2sqJIy(-;t;3pBrdsls)51K|${ie5s0?$K~Xx^K?h*o#g;0pOY~b zW(d_~`9SL00h9cB9345S3%fx_E;VQJf(?aiHwCS}MXFLjn)>i&y97tb!(_@Fkr)F( zy#dzxy=zp6aqt@cy(}@H)STK%CSiG% z^7M@t)jlX>T)pFlQel(bL3|{rn`AYm?$( zYIl{g-)115Kx^&gG4KA4_Scox+g6(>pF>RcLAXn*02*M7RyktQH*+iValLn(&h;}q zt`~`g%z&u5dHTi2Tft#*tZF@|{|?ZEFI>F%)~G&$YF@Vj@va;+$Q05x^b=DM4efMUHjBBXUI1iic1ma@I&zw2q(imrXl6MVjG3oE<8M7Kkxd}z} zFt5lsz+VW-xQ82eSoZCYI1mw`>;W~H&zFAaL*CKUjBaUZ#1%jj)|Y~2#Kenm9foM| zN+47B=ZD0T!qS;9GoZDMi!byOZgY76sK!hI5f{56_`d+E_@wT~B}~5iyF7Lf@3tNC z&?z$uWmqF!NGBO$ZE~NKSbqEVc(G*Dsdx`?%!cOT+fO*3Z7$H@*ju7vEPk(`^aN~4 zD2Ub`ENrzuTiv;N)sOLbu=HeI!ZIYnVx)XOt5Zu&P)rP>q>*(_S> zUBsO4%hk(7j-`NYg9e%M@!|mnrRNzV_IDRGFmYCVYzf#hH{tZ(blZPHMLEw_1r;g* zJ0C%q9VnNZ((HN-zac&-h)$}^wh@BZ_}xdNLl6_fj|9|o|BmU_$&#X{gg-kUp=mvZ zS9wD@k9*gkTY#2f?vP~YgvLY>Y6*_fW zFa0nt#QGRY5J9J|R^V^AHqCBl$Fpu9hd(GMmGKs>H5xBwh0h^Z{y}gu->OI=M|375 zax4sX$syL!1lv8`qBco}OQ%n#KGbdf|1MO+yx|cbp%gsQ#&5g7{PKpP^`u87;xc>yxNT{$~bfsEEI(gIx~B;b>X?GWZh?5x*ZEufBrgP4M3(0Eb4 z(Aaghd$V>^$xELq@!a1w)#P=`TpxOoiHB#~Chn}CQo?o~b!(Q_BmrEKge8AI^U*As zdhqN}i9?XOE%)7o*|BQZ(--oC)!DhSY7MP;ITQBeeH6K=$^zih7Kqvohh8&yNORFh zW#;i){KixixlszH2<=XZp{3B)jD@xnGl8D>=6Tl6T%J?Oe*I#(FNiyW0b23}GdkB_ zgL~RaSH+u0DOHMcz7Nb*T+h3C$c!RpiX{8tAC>ZRQLGsdF9Lp45q% zDt%e^wOxi4dZ?#l03pbY!jZ1(stt#lMClM~>x0dk68%OH2J@8pbsd_DZ)LwUa9#Ng zMrK;8_-d>IFbM4>uHIl~xtox@qegl0w}V@`V1tO5fqk^TzD}#$r8QiN1C5qf){N62 zJ5*pK*>-A_Rb5m%!RIMd`J+_(shVF2>zu%X9_9Q4tk&ixXc=%`ICDy-FGC}PDR{?+ zbuhNFI_*tQx+#cZ6lF52X*}Jc@`e}_!kZyD`h9*#<))~V{d#H8OnCz5-1(cbaiWRP z>JHiq4Y^>aiHsqFM@be2MXu!42WHfWVTTCR`d$jH|LS2Jp{w7Kc-rgU4(XMye& zQO39gkBvGPt?hD&m3&9CyiH$r-o)c=zB{8CH>mNH3ysf%NLDmlH$Pm!5q8J9QWiAe z>f#ZaM$}=+OMOTvmW1-`S`AE$j{^L2g>7;iZ(6%{=<398nDc)|Ep1*jl_YC}MNcbU zp#kV&QsDiu^!W@uWWRQm+2Kf?C`J>qxtw=bbmBAejX;7V}>v6RR-^w#6m^W^BJn@8wy!K!=_Od z%g6MuN6u&LnK3~iL}A5=0~K{Hp8FNn!8b-7Bt)146I|iwUWkSj{o&}2`11QuuY+pQ z66VPLsJ{ou0K+R`p}cEXyM&2vqW8l3%)zi7G1cW~m62A-a+f9wpq*t)hQ{jdW(2`i z_wv3VwF@$IDoDZ5g|?`u8#V3${@{>)`X~@Y=@4EGk+2)BID;f8)#+}7#)vicD=aY$ zxCsxDv{`bFta8JJ>l&%*b)N;xwi<%VD;KHE?l$yaTlp9szJPc@iU<#wcfAtAK?Z>nS?TuSR6`gr9aFfE9!x8#pQ_YoT}93{{Zha?<=aEwQ~I1S1TDga!U(1 z=YUo~??&tWoze)~zTOl?u2mEmQt9)MyeTxJ8-YFycZ9FQJ&sAE9QtqR(=QUf7LSDKwAGs5D%(zU6b z#qJLqbBYu;G=j51nG`E@+!|Hsko>JQc#+u??o)cf_{Ue_jFV(fH{`5w1TQ9)U5HtC zh}kv!7`4#%N!RLrh53yp0bRqm_&Zi2ACDt1`*3&MS&@MID2OkYe&7No6r@kgmKi4% z%K#-)G7_3%aw(q%AS;R-`|kKjD3*Cw;*4j$k_z7_ zAsbQAjJL!wx+lJVpH8kWNL?IyP`GW^z>P)s)VKSs-~SX3rJBE93C&BYxg}6_W^sh6A zf6L-K$YT6ILUSdyjDXY&)v-^#f3;()+?2G@-xdRe#>5^_d26a9O z@E(4^qptaOztGH9BC4guB1G580F%~g77)6Yt=EsPNzmF^Lt2mu{f!TY#$3lGiTvTSz*w3W{f9~Ru3x4hXH!eceU z>!A>AIALA7zfnt>+@GxtMT*9|8~#}s$?2o76<`3@<`4I$ew5 zT+ZckimvBqoBfLIC-*TSl5d@um74=xD?|P|aarBR z4X)@U+4`yG2ni2>C_Yl?cO-1U!6JKd2e1{mOPG)$#tP!DM&b;9*Qh*w!mBK9I8^8a zpYNI2S+j-Sths`zH#PAZYiq{1(iD`{?h}F$ALwJlu)huuOQ?OG=+PnU5Xq(g8+i!0 zGCF?zSRK_C)!oRW!?=;GJ=5IR01*hl8x2os)duu!AKsz=2A&tk$kDM;Zy>*^H%k(r z7%VI--%>2Pf5F)E=XLh?_lbDK=K$E+`!YImU!Imqe{XAyxnS2nlwfgwf4sp3!B+0X z6}Hk4{PrjH_aNH&rS<(`A>yZ=Ghqw&@Y_90y1p$OWn*sSq8zSJ{&6x@r=ZykUtR0V zHh6LvJ@7$oX00PA_X5+Ms-S#7sdVz7^X~F@WRw+B(d|rh3c`&EN z68N==^KhgXwuskS9#w0@4Fejep0G|!2THZFJo*PX3jmC75fPEnB*75T+QF0{QfPFE zXkZ?4C&KRg3q`4r*ByquzIi^_T0w6Pjj9JfhYF0I3KK^ZSZ&tS)A6XMe^G|OX2?7` z)!NZT!1Ikr{NT^wvN5fQ)Ac%3l*}9c03OaDIZ*aCMxLlkKVHV5QxW<9q@i9G=#1Se zFry=Z2yUY8)r9nAxKnctAT|fb#!DAwlER0uCDZI}_|QowZ~fsCj$ zva9esW996}d_lEa2?Qjxft|BxLWAYVc)rl)AUgnK%@+k9tH~D3_=k{Zo9!5H(jxd;7bC90s9|fD!hqEGi zi|=b_Xq1oKuaJ{xI~7ExmNgncrB*g7YrQ%tHlc%$G3S8JMH=g=kU_px3uJ(^Y{_Y} zW6aC@ojdirncDbdN<(Y|aHHcIjWDO(YIEARe*T+=pQQ?2n#AYxR4VD81G8pUGTp-Z6lP^KVyPd zO28{IHqfKRz(}V=|H2BM2>;1oo8%YZDAIfh-CF$p0oj( z|N1wWc(A7-Hp~RAbx<#QfgAMZEz^;1KazW^21*+J_k%v@2%f+o_$3=3oO@=614@Pa zFk_st8I2a(w0mxW;6FJvB7qxbyOW_<+%L+96C z$y}IAdDu^7!gyHWY0)j<;civQv;viDU2w{R2lR|jEtM#XMA8z4YhT93<4Q;Nw$yS&N6Vl3cdcA1Y3?4nFa&{mZZS80!&) zcf>?&I4#&|smKg2jFhHE5RC6;d!@ANZ7ORt+2kB7kMU2eRj~RNGS5;rUAT0~)646| zSsrMbS!y`pw({x>hPeH&`LyI9U)%N-a2J|(r{4-IclPui$fq`JcA^=sazj&#uF91d zy=P}I-cI(zHeEbj}pSMt%Fj0RIBlOJC@{&dBjD3lTBPYDc z&Yfc2@8U?JT#l^wL(H-ujO#~p*i$~k=oiA{FtkC==#mM&*JQl5hn>nPL0kq2C8p(~&wFQ!y0t=5a+kD$E+ZRa3S8 zltICJ`rA0|oWaR*xEZG=7~1RI>AL8YvX>wa+F^!0i1xH2M;iU$Y9aGRF9MZ;6HuTMuD_^|5H&YbJ0Mw-e^asxM05|Ddg!T~qDJz3N=)D~wc?{_d$YVi^y<8wExZ@MsvUaSnW^nx}#9{s*eZm43nO672 zVa{iB`8$EDvU%DcRYOW5vAI(_+#fba@+A)pVh$7-DGXe`cu^t!c?uI8*9dR2sTUIB zaKz(Ni z56j8mH*I<_Mt@2c;XH}3J{bUa>&GfK(4he9k)ic)KzZ6+lP>h!$zl%Pa_Sgr5p)NN z7o0DixS0!U)%u2U?~gafuLs{s{huS~y|(qHAr8k)t-+^uQFuP!KiQc?GnI9{`AE51 zzsiQ@y904zWAqw3pW6xotx`|wJLO+{ zEbh~7#ETj)%fZU4AM3Mel?HGA&oL|%6l!VcPF&8YChhdZ7h$`aQCSxDNxtL}Rdi=q z>n+M$^qwyN+vI{N^aXn9oc5~b8cR}_hn%>9r$vTAn^ho?3qv3Lp?za6XuC9ncYSju zq~Gi5J$$Aaa{h|k=}i;o+w?(}k`=*!&gZf)kaK~#m@B)mv_2KVA0}z?<{)G~qRBh4 zLrqkuzRKm#E$KWt6Yg0QF~8l(IEYosV`0~kM0l3@X_)I^A&;?EMO{AfTmOu4|GF-g za?>k5=!bmVzKku!P^j|YnOcf2g`X)w)R&Tm>mB*DaFub6WO)zLCN%T#UwcMEUjOIY zc{Bescz=GuwIin>{dFnp0lCA=`%}10@nB4TMXY%6ClZI3Z0OOTd5d7}EOrz_yr)!u z`8X8?ChucDE)?y_rfyBawqg3cZ7z{0{%M!5_)Yw=um0l;b8R`x8yoCK6a&`d2m2ah z)mTfbR6i#J%K)5s@xo}Lh=`k$Uazk|;C=wM8Sn~7SXrl=!pd(B-60|k3Wkj2__tz< zRUnG#mpcVdQu(~-m=zV&Jid5mP4wX4rZ-k)Qo2n+&Bn&f$r%GA9ADqn*dm~W07YaT zlCA)WY{O9y2wv)NE_O0YB<3Z8%Mo81uko_v?LoPLyy$b1pR_(cqUh-Vx5|M_uYS`d z{gf+MsPhE+_xk$VcEAGX%zWLN4<^tZAD6b`?t-7j2(AANNr!!<8xA_fV_9{X@UtD1 zd(0r$Pv+_E#=xQ4@qz`AS|06PXnU^EGXS}V-5pCXR&^mP-j3hkOb#9H>dT{_KYA2P z$Zo*s`%@-k-^8bxB^=h-&d`qk4aBS;-YYb!acbZL348#;~?Xx(deh$gGE70Xms(? z?D}L#7-KO^&+VK3pb~&Z;fRx%tvgN~K**;QyTEYh)bai=s!9WTDCL0@!M!s;AXJay zZ-tz{u)2pIUw2i`aaFc5(Hl27bH42GU>&GO_#Curi4PCdfBykxL{J<&H6rQm;@piR#`_K&@Td)&Q=tiT?tvCQ!3;LE@QEheP%KG{N z#3OOpXTX{4ch+|cBM`44n=~rGUr`La!Md@+RE*k;_r8am7)DWPD-n^ETAe-#emfs`G z7$JJFJQZOUcu!imFw7@C7pzMgnq#DKdh3jvjFiB%(S=UuM^&+zGm`agb6)^+(1DYPj824`o z)PlK-6Sb%x9!`7yI8Q4)5lRd%t~1?03~k^H$=CDk`L2C3|zH$1cO-~Lgfx@!=M zG#i4KAZtBPZ1IRISZ=O}ft(Tzs{Qtbfkn(Wy#yg2^qac55WIFC7q%3#=wE852U=&$ z7EK*7t=yK;33gxbgi||dKohC=^!raYmrN|)u=O*3k?IVciVM=H{&2OKqqCjE_?4je z@gPHYu@BAU@9)yK%q&E^~v>WWnk4jI-XzO zfs8Cz>@Nzsg`h0@j~?Aw&nMuLcN+IOCeMnEqhhr{8vMIwAW09DA_ll_2;rQn*H3Z8 z<%7@~%32+rooh<4OrpstG=2Aiacdzqo;fS4)gH$NoW%YA@=TeI4|1uuK6?`YjRuZ) zi)G$65Oe^)b9>0{a5oukv}V?L0W*%pnuO$veCyr6iHb8%Yag_+!~i)f7Oy!FR+0Sp zDwgPw+3>wVXH~LS!_39HeO!a9Qn26dcZ$7%j zx?0JjLO(k$l9oUv9-57UMA(1YgjGM-=YXQW+eLCt;||A#V%RM}xc-v#PYNL9J2&S0 zhuYgqfYps0+Y#~fYv#thu?ZB^BB;<})V%1g8TwGi0pbf4JDw9u|2h~CcgF-`+Cgwi zZB6u$Q<5nyPE(M9wdzLg3tnWm{EuaadW>@)(4jQio6QfBS_Dk#2#x zfW))sk=w`T^;i{u`iPd?!vOVi(&$^+6gm6v4;pOqI39)km-EOMM zgn>zS)nkBJAm;?-??Yh9!ESc6Ux`vawzdCuHOD!~D^uzfszCdqQ7v=;>H`#)wyiVp!hW%F1dU>Iv0KX4>OQXt4UWU_5_VH2H3jb@_bX z!!ULe7be7zP%tn#kc%7h5rI@wWCAFaUg_-DBR0EoXrB#v%HWw8;8wZTc#~E>_I@Jh zblhi@z$Ndq-FtIc&n+s7{YfK?s|HKHf;A!iI~-eqaEzf7ZfMwmT0*{@H#qQgGA#D# zjB~X|Cob^~Gd-fgLNZfsLGhaCelr|9o1*AYL-D(mi0WtJ6<)28p{V{u9Y))|cV2`c z!)1rr+Av^W%2i0t*+VRrIUwZQq{C=5xdci5i7HQfB6pvQ(OTV3GN2d9d2F@nQN z>~EjHGBn()@hxHO6!J|YdH9PuUayNNnvE3Hq<-*lL_X1*yK+*~6(S7TvW znD?f0$(cAekuqIl&6?V;9U`wD7F5XuCHvFlP$&)KBJEV)T05PQkr7pc#wKUxCL2TC z5b1;yAFuI(*qsbXO)pOHyR1UAmSNDda*aa({kxc;ju9` zt@LGI{GcZbz3CJE3UIP6d9}q8rDHOvm{tv6>SVl%={sXE=ny=5N$TTsU0q#BQ^Dn! z*DIfMXi-tJbp#OlU#k75qa^nqqQJzF_6cq9xaqFuLG{BhQwnBT<B1HMeZ`xpJJQ$f=R;#c$Dhf2xnKtQZ?(Ihyz=V#t8XrCS5FIk>$!?ci=MfD zYeDEa5=F1eY3*g1CiQfVgp!0&tARZDM=#3%^&%lWW^TY<(Ln61D3o~W+awMHb^<`` z%7f(_%s;2{!ysJVMJ?vO5mD132$oJD5@Qxz& zq&b(FYlHXi|B_wH(Ud4DONW%=l?&BtLvom7zKL9NzfObhbC6_`B&NhJM*n!NdexMx z-`-zC3-6aGGs{B9U#hD@SLK}wSITN7o`Zav2M=z8B_|IPu6gobjOqB<{ zR||x*xZp2_nQ18Fo-1q;IJL-SQ0O~R{ph8&Nz@$ndM)m*j}s6!K~A|lBka6?LCXa# z1U8fTuV5p?Is#ZIURsB9S{Me`E(WS|^>!(#MyPa(<|sVrN{f)p)9*ZadO$efKKDz( zO?5l2FW~}IP)wwTuI{nwM#TbkAF4Z^8`crZrT$v0p!o^%r_O~}9bc4&LaZh-X86K` zXi%#sT@4C_+bRUoNZDu=#YdZI4yI>>(=(s*XQ*Z&xb%9jxbpKi{3?Jv0equyF69Ug z+*o)W9H$u4n5OP=22oS8v3JPEG4oU4rjoLOPCMia7+ZxM1fGeFne$g0n#CzqI7IPkj^t3^o{TP&iSo%{=xTk zvE2K)pSfqQx#pS~Xpx)Hb{=^r)!XyH@x+2!H?6}`_%&kg>$Z_w_EtGq?w~|VIE3Z? zQx*Cge!S(|DMpp>;C^9pFz|rg!Z(UBQ9adn7UU4sFnj}$m)g6#H+c5hpdrC(c+&ju z2hUd(w1z9*-Tu4VfXB&}8LZ?onwjSu$(Uw_o57;Ef)B9_;TD|$C`>d#hX5%aV1vG` zn-o0SQW0BaMyD%cG&moVB&J^}$Cwoy)**L{Q6= zT2B{G%&Ep|W{-hzM3=*P^KN)F`9Qw1h)7c==pF#dzuz2gU7G=|%1@Z^?x!&Y>F4I+ zz>kBi@rc5uR>5IVyjC^s&rpVCDB_g~p z(2bl~3AF|=LDOIO=yW+K|EMUv#XL|@CrYKJVqnB_3+vY=1gZQlAmr^nA97iWsJ0Ho zC`<-BYwrO?DKL(IwQ9Bwo1Cj+HZbJ3U7Na~1m@*UmjP+9PB|MWLq%K^L58DxbyCn?pBiv=}hAY$WtMC zO3;m?4ypoRPkRAc8$ftYwdo{CFC@&^7R_kMe#_GI*dwEEdE-|*gO(>Lloq~{uXl{h zUupi2w=>^iajR(S9W2z4p-(nMyctynz5Zo@DtWV8cOMHX1?kb{!=&d;~_7j`gXJaW&d$Qis5TetTnqGKt8{- z6DiTYfPVSnSNf`2#8L6MINN2b^`IwJakh(FbgAh_S`=t?7X{GHSIemSO*sJ%0L zI^FUH+DIF)VVKon2EzOr;Xd>-;`&VMx{mp=ptrZezJ{GU>cwG>gl5*lu z{=A`br95OPOLB)^jF>!A@ zE&7b4F&k=FP3p(g)Gji?hkYb>ua~J+6hhj!aor(?#Bv3+bF4Rri0+tU1QV+%73(wY z(7AzTFeI>X5D!uln0Rz9sNHxflXI65L913VybcQUc$!C9zLIp2wPs=obQQ44UWMd1OaC~-&?1mtAXO+9)t%XX;=u!@bk$y5V8mvqk#eS z(MB5~VSqh(Zyt602Q{_o5YJ+i3e%LfaeO6xygou7Gwgd-d{YE!_oFR0>;+-c`mEz% z^hz`PYG8_kfca>_y|j(z|0vXj@X{Fb6s)Jzc+h^6uICpi$7diK0HLg-%hzP9i7zLl zbn~y{APcx5C}puFBIe*y_+^DqA{0^!cWwR2krTl9IqC-pTw_{w>2^mf6J09AQCT&$ z+{U%~??A*5!k$9dodUh}O_N~k-Bk4gJo``Qz&+ecGnarRgA7ur;V?tbYVs7^0G4XJ zi#|Dw@VqDZna4qE-j$L}?!4X(3pN~X_W>gtO>%yHQf!=>>wLR{lbkxpL80Y7Uo_lE z0Cwj@Yj;2Rh8Ij>*bJ0>2$zF}RkcCug$19dPr!#wJ*di;h#A7Fdg3g(^cLCOty-_;_!ZBEPw@qA02OiN&fZ>3BHKKqsS~wNKY79g zJZQsOm^5Ei9y*M?gbI*B`E+uI>;eqxg4Xd#@e2$~yiZyy2= z>b3LhxSsDe;~4N1ObF*qnir|jQI7mQ!Dr{}JQl#eKbF~ia4GtCXr(-m)4@bd-0{KG zWLCIE#BCH`wVlg>yGfO}&yNhV7-pUA&*KN7ZJGH6JbihFHA1c90uOv12P8vcgzj0trR2{Q*qlTgtU@Q#5A|5UcZ zokoI|te@5f_hp=h|{A<$@XW;}$f z;~2ZBxMXp1aw2_)i?v|UP%ccmh)I;m0Tm|9%1~&_*_K&+riL0Xr2BGcO-20okzchl zIB@l%`{N1@4Q2;Uh5#uJj%3uMX|;_$V|D387QOM}?rSh=H<*<)PF%{A(6bpVARXE@8c5 zgP^;6l^D(J)vzm%u4uLY!Oci+ns6CcBAq*BdV%P%Og-qVtYN*h!3 zx}(osBFm#iEw%cUGMIfd)7tyTN1&|l;F8jB4>1!#!)9!nU;$Htt}9Sv(>uJO8V`w{ zc4#elO}RVi2orI1m_PA|f$CZ*_n9@#do#b^r>TXoRxipgMj>TGjxLsW=Zubj8i}9XU7jz#!=bAalvLZPiWt99T7wA>-XhejY1T^s|7rn9# z{itqCbqjB=LKk1fie0zi`$-Fgb8{Fv4%JmzUM$iMJQQw5+1|ta3UU)tzyWJNsi_kp z6=&xZWrhHPs8{6|7x_<}Bz6FEF@8*sSa4iR%FO#8qmfGMB%h)Z%IX~F;@NENetmF@ zz;}uvg0#v^szBJhL$|mqoO5_g4p38Z`#fcf z1dJUsfFvDWQB?z53(Xj+?&^7i2^Ed3e~S0TR(uG0;tiGM!of%9&&jvsvotNh8N(G) zFUT*h{e8w6qLQNird;=uRTAmZTfXRUiu(FGW{nRJyVt9Oj?3^#UIKVenJdY61ay4Yq_4MyU&|g6j0mTu z-FS7U1h_mDDPn6a&tc%aHq)MRt4%&Ne9e~-+6CxfP@uhB$?6$>r!Sis4ApBezv9D( zQ#)kqDgnpGF^@WqNys+-Jm4{q(v%H{0b^Vo))SkvPC`3n*f~^(2idNjaw#5(>N#zG zQZ7rSziog3#e^7SOhs6W(cO@_l`Jylj@>{m=IdUhXDxP2XvGjIA&w-W4p9H2)JZ+4 zygb^ruMehdXu9s~ynUMwv_Bs8_s!YF#$FsX0zx%RRA;W%sT}96sF>PbQ}4RsTIiBX zP)<`n>Pu@CUqCO_jixeRoj?coxL~!2vUElx=d5D#h1YOTI}}g^SM@Pth{b&p75_;r zN(9koTnYY?*8dp>#lVn~`!E$r-Wl0AGU#*z#!$eB($o=YE>JNc(`1s^IU}^FPt4Vc5&`e`}bFBf27Wre%i!O)j52_rAzhQI+wj!O6lpy zFr9yyO*-n z^%|3sQZlKIRgz-O1d7w?rj}Jv4Af0nms>k8qG?sX3r@GOksB_zjEO8uFTBUXVuPz8 zB94P0?~|V+{A#X~$A3$jnjW@lNXBn_mtu7He)dE!=!tZB{K-9Cl2ESM>oV8kKtWu5 z4Qz*oLGwl`-U0aG%e7l?Qd23^b!wgLuHoR%Os54Au%zlW+M7+6c8G?5OSNZEzSlBV z+aE?TX&g%nlYqi!@bF2pL5H^;@|8TebY{6Mbop(A9>sF8*x7oInDFq4rKJYEM4p4O zP;xZU@-zlvF56sD-9v-+*m>QYD_l=BsxMd$F-z?$s}S@{waQo1PBAmL$rOeYr0P=% zHxI|ha|Og+tjuX=!t3-sJBb z9K>l<6v~apvu@m`lr|Z7zt^947TWq3`W9&v!{XvT6YJyC4zA9RWmH1zGs9#3Z^ z&Xlv`attTo+#NI3`^k4110yInu`_SfNkg`RdZIc8@Ag_8-vwdU!RE5G zPhf^-&m62xCBlz-Zss-wUJ1KhhPRYRESaJClUT8-K3!dy=8g9Wx7#uHfuz!yM%6hh z-0p70bLUuj?P%ZR*G^8%_?u>`lw7F3SzZzGbe7X?q1WMw71Q2rNp4>@Zf;XK=w?k+ zj&XYXIBn5Q@!9gIz1Fyp87KGiv}bBQ+ny1(n}?N0`2rfnMyD?ket>4w1w;ZTaI; zR8PbH&mRXBjV_tehp(kvU58;=Mq1}^A$nRbzktAYwu0Mx81eFtr@KviCsjjR`;qmU zY`(h2)n{`Rxq%vjWdo z8-UcjHE~HWt0r*p>s8|DGN$dfK(INr-MH*0vS^^pOE0&S9n#u#PxvFkFeEG?r0nIZ zkg)%}cGI`*#U50qPZkd>NIJhfq)ju67gQ=p2SG3E-P{tFsHKH(2St;O_nTWcy4vIR zK%HA=Hgs<1ZbIr}5{uB9hoZU*HFYLT#P_c$-eAs6j8f=TARP$N333O!px`1kJxf4J zab#s!NIckl1$EEQbMf80WZx~#Slb&ome-S~)->M(BNXCAj5_XAR912y*fxIpB(bC3 zK7G>%QRiU@&%q+B~`(iQm=Uw9%I}O~>@galPDcV#lBFzXyNEwHXv0L?)Vvp9&T}s9Rr_!05Y@;=` zwJ^|m@#Wc^v}rQleJp-2SbS^VmtE=O ze(__nrJYYx(=X7`!!_y8{joA`cCZ_an#?ywHVF|al)?Jf%poR^FSs=2oPG^V_}A$v zG?vB>`^8-7TqnP1=C=1YO}NUm4qXhe_FE}p5fVF`Y}4i{47V*S3=jN(=QZy$k>5^XHLZC!y8odK<;xjLN`|}CO-)U{x9;73 z6$zvz-nDLvqr*91GQX0YMcdS0;lLRnBINQxTJNk`%;TluvYWjY{f0Xpv^nNr+RWW8 z84ysjCKfDA^8B^x>*#1P@xB5rhn{p5-2}t-*jx=RkLRV|+{E_MCV2mPUmp=S&v5F3`={$#EW1hPo6ZKS1nBeTwns`k664Mf+-r)|2b0Ok%pqG7S4zH< zcJO#=_8goH>OZYrxHz2p4Tm}srfMd_R^}KbTj?$`CvGfmjph_=hDBeV{*2d+-$w7c zrcdMuQxuofIm*4AS89FUtLCe#zKoBEsq~km+gZs-eD`!Dmdin3Tl*-&?I z%$MY&yH~FmTh(QzzpiZSluD^%F?v6{IO1ECdAs?h><)5h<-T$EhsF#Yi8ix$$lVQ+ zRv({I!QZbE2boG*_}7mGdtE(|F_ye&MLiL#jFNTp&1GV-M#*0T^+E!k0Y{bX9f)*B z@qMLiw(bI*5W40%w^Oi+`E@~l6 z_kC5Je(CplwH?&@AC9KFB!+49(EbuURFyCq3N_?vH(EKZsR0!Xj5UlO!)IdrbzBnGuu|@?(B%# z7YT{j$8N@|G*)`6>MZo;=XY8@e@=M+vA*8R9cddS#%cR=ynKajm!S!BVmSL?gEg85 z5wpggw|}@t*uxj}3d!FOBjOtTaF|%5-}7Q#+Z-x+Ejz0{D1$5 zKnghNH-8_{<@FsVZV>2^Co3>qRSys1hh01+#r@au3=IwQ*EY=St?|0aUFN!CU%Z%M z;e87CkVs!Vx14$gPFSJ6nf;jHqr+| zN==m`Kixe+9O$M3Ezm6c*?I{{4Y39RSr|NIbWMx<8BeWto2iTxX3 z;B~SAD2ht7JHp(o6_+v^cbuIz?(zOAprd2>*?Y@>+`6pp&5UBTjlJ`x8QJs6+cbv-PdysF*1M5?=d+!8$i;RruF$YemEd~iAr!JGQ5aVWF_e)T!=HXD*Xu`|%!5r6&8zoxLdFb+tcUN|vdS!Gc z#>a=tc`n~_d^wnB_a_990^6nec?q<_y2EMhHiTS$;zT*z#M;576$;o6Y#LGcA|YT4x`BaVwafv3Eb5m()PU>HZaK3RGCRUPVjBOXk-1BB9NU z3ax!uUQE-$qQazij>p=s`-Wk)10#8GN8-^6n8#Cxg1+Lk@ft^x!dNe_7`?`;X*TC~ z6(RGfw4N58xGCVA@Q^^5#BGmWR8{l*(N}!9&}ShJd^(`P2BUXKYxyPCNobghrOLP_ z^F<9-tt`?GV%g1Mn5|v*m}5bhEjI4a*ZScymboXOACr8ukC$-4DlW%8V*lh$83PIt z(x&?7AM(iS4!U+81a2fZe|@Y^rCEmVNxEyrFQ`yGw|i78$R z)iSQb+R3>+C~90sG>*szKxW(Bmy-p{jWI4S-c3|c`IAFlrTc@Z)jJV!@3n?Z_;@=r zXXjDz>YmEOfwm@Jn9|q)4PcESp9RPphY4{L;uz4dOcB%Ai_wMomgKktU>vFm=`b>z9Jrr^3r_kbJc)F4lT!2BFR#E7fUy04<{}-wh>z|n#Rp}LIQrMV`SHb)3 zu30YHyR*XAH>UPjN_Aa!U3JKC`QlSMAVlrP|MM*7c6Zh!7}Rv1x>W2H0#kfkT;eO2 zOv2+#eWI}xB%`l0_-|XJpZDE24EY#JVsC8@4vxhx{>LP)l!U`KXiGaV z_bEuPTT@Yx4!mh$Yrx>z)-0N(u$cej^Io&*a3;4i4}N2a(`rLLB(0$XGS~x%gF9Cx zoDZCKOFDVjZJ(@!h4D|!6)J=Wsu0e9sAa6_64c}qjU_7ex-1+_%q6dxPj;X#pTt1$ zrtD?g?XyJZxnhK^xj0ZyUn4a)b=F!TA%4$K@ISGAi#C@5oxZu4Sjnek_HzQRk`Tr< zlZq!8kh2}cL)8wMK-0|>AOn3b1_uS{_K=b;z2CFQs|oUF6@8>k9#vLpZLl&Kj23j` zYn^2q4xhmg9Ag8ER;>^5Q zFq_!)2QlybgI0k2M)jSI(cV_SEdj1L>btyz`J};dY^IN++X0_ZrC&j1*J$M%Kc8Cm z%%Bj)2{$E41l*K-caq1^dl=3JcnM}KT^|s#F@}+XfnS2%0-vMkCe@vTt@{Xs=1qd3 z#-0-Uk$3cnc;BQ-m`2EDrmXeudzyIl&HI~GuG|Uf2m3Wr3H}*=8E>3C%|qV_l4PBc z95^P#Viroy%gNPUK{uXV)(kKd6c)Bx0&%$OVn1dVSyIwRP)Q4Z6G>wi5nNO+)V{7n z9g!hozodHe#*KT%-Eq1}&k8Wi4NeHN?~^_EC=J=;Ojn;k=Zv^!X0LVRWOHo2f%z4l zC-iE Z%WhEMVBoVw&xmH8NTD`^+9Lrnj#B=Mp>CuBseO$rIZ7FUT;=QuoJBa6>~ z%+;!6&_LI!jTMW2f7c)+E)K?gx8~-ufpd?E$(fso(YPRP+4#WriR7b4HnD>htKqY6 zoYmEJc7~?DL*C$b0!z9DtE-*!D8#??{0&Qp`J*S!pC@>{Q?}I<>hUDGVq1D+p|8Q` z)h)+VHirU?yq63!z>P`u0H3zGmW@wL+@SdB&bwa|4XI8W3wJ0P+FHfa0_~B52(!pR zkpS~T*;3=~dOu5%%V{cc=s234ol@c=%3Y<#dVD{g$dSXa(qpzPNw!rXh|07(VO_io z1>f?Rk#FsmZq^vIK3q+yTDJ*h`;8Kt4D|mbj7`Ijg#O#n6jvtx_kUS`cei<`PGBTG2f10#36(DIk;zdzZ6%N(=ACo;@?d^ez zBPqgEw0?mJJ!Pha6&#dB39z2WbtXnw=9l5IMHSw(6WYeSz*#^hr+( z@ckzOxxVuK!BcHE4d;~;e#(kw6`h7JtV~o~4I8T~z9kF8%F3qN?sC$n*RO}n9@E03 zvbW2MJrY?|GxK26r3uTD8&C4~^CL9w7s{QVSBbksf6F`o{!q)eeOQ?rxQf<3UKg{E zP7}~Q0!{_ON&2V)sZ!YA^hHX{pmL;O2m5{!lk6JG6@P6;Ok}-AoDKc-Ffy!Ur1_b` zgJQoJ;yI*!Hy7te_`ByYm%959?VG;^^EzE+X1p`PpSvVHtT;Zu%?ER(QTBrVn+q5V zj9NUQ&b+?SO5B^2p>~Trc$PL;Ej}(zb4lrDRmB4%k9YRG&z?OS79Q{Gw1qp0~=E4c}NAl)~He=R8Nio#fO<4jQDQY%Xpzoo5ofl8he5_Tqmfz z8R3*DqI|tAUStcv&PaSbTMOWhP@AKR;vUX&n{S1clX;a1b_HLTcC z&^*a!-;FejujxNn{fx=vekWcOjm*mtNkLT{PXBct_*ekT-)bs@;nH6v-fyr{$cHIe zI=!zI^Ps(jL!?Gcf8`tFylrB#Y1tb7;-xTqf5!f_v@ywy5Ci(y~ZRZz~FQKqSPjb$% zH5us~$0yE-I_l3v2Gt36yq~BR&tdU%P1joPe6@8{Cny4NT`A_7T zmNTbn`}4bIYn0^omLXp4>5YvLS;F=3+MsvdVI-v!6a0L9=Cru_rC~Kp{Y@uaLmB1T z$p7mjUQH<5L4MFJn6LHu;&PA4xW%;S=)GG%?=&84sh|h*u>)GV$dd@~#*Gi@IR|#< z_$+GplSZp!UyV^ezosUANdLuRN{AbamSaDO;KW(#r6hRPedDC2R1^>w@hN=)m*n^%Mc?10n%B-> zUH!$+?@^#WM3;BFPUF+W>-SIJmJEs(a)PI^j{r#Me%lV^i{-1c*+R8$b>@MQtrO`G zuWHeP(WNAu%aOWs?scQ9Y;ichk@-WO1rAbU|GB!%h^&o_+7EqM_u~D?FRBu)bcqKP z5l+wK^#1e#su;x)2f@?Ihj+Q(H9h-lP!M3aT5=EMRS^s|(;k&?9$@!W6e;QJCjvR- zzk(I1^-PVZ2mjya&WDxCfMQool>TKZ^4=URLhyPLMK0b8J~%nZ()c5PR?`Po1M-gj zA!C;qIQ>{HzoB)jp*2_sOcFD%3_q|>xn2FWb@vCRB-x4e6E5A6r;Pvja5JoAusLe( zj#gCjgm!+amg^8ZEKmITlS-|$BJn_qpQuftLQg!6={eXxoUFE;t-B+VTDUMAN7S|; zj7TRW^b#RDN5Wt4oH2N|KT%|k`_IKaIYYR(V$BG!>Y=AD2A_kEI^J|SyY1B*+GxJp z_S8(|>3n$j?6%51Mn*fJGeOrByuF^#t1Nc>-I?uEq~8c%hsz76OBs4{x=Z%O%<-b8 zpB`Rl^+W25+b)ch@1+FuNYvR66lC<=1a5$bimCygD0yzJn$Kf*U5R>&$~jZ{uV?xD zE`LNgi8$>=%Ds{{R3;}iia?PTWjU$@J2@_7Nn3x67d~)J;LJ=>3Si|f6~gZRaMQ!h zq3_P=o0n8JV+DVOHW{td@fM1PUqBVZ5TXOQF$^6OuP8`Xq!%>QzM$ND7VCae%n6aM zSDjFE$a&}6@>uIR@gJ}HJROl_$Id;g@LqVnY|}mc?9C;$eD$5sxA$HzW+VosrNKI0 z1mU$K0y5$@h0?T!;}`PxL)0VmlQsj$7X-X|v?#a~#JcZ#|MP*M-fAK_Rj}sg`Hei6 z{4fAu2LzZF9CWziVB0B1=0u8XMTA4oYZ^8Q54%E7zUAa~dv`~(>&Vo~Hsm8n{9}e5 zT0=o+PQP}w4S&c@9r9_qg!gJh{n9+juWgl!KKl%C^jFv)szbyDZdTF zFO?N60u>dlg}5NfN22N}S*7ZFNTJ_c_2hT>Fjnk;6o0QK3W{f{>TE@U}3m#q1JerDZr3ab14Ws z`C{Q$>1M7UAK_nLD)w@y);+7K0rkT0@7ngvcKzP2P4kmbT51e-%d=mqh9ymmS^`vA zF5~@~EobR~zkcK#`?{j=?QL>$a;Fb3?kQU6Inze`u8+x||A-KSgTX?koPHII zEE0^8(q~m^*Nt)J(^U4Mg-v={sQmAALiPX=h$en2j z5QVgkv{9~|NzdCiWwd7kup#1|$VqBO8(Np#x%(3L$dkN9JI&la4ZfQ~d92O~Cct1G2h}W9}Lv;jPy_!n;DXI%h@g0 z6bgM8_^|X3_mCx4Q@qE|07N#w7U{sXY>9qsUa>m%)mq_B?yUzb{-bVxvZ?0Z*_0X~ zJ%cLB#*Cvz-TE{%7>jUP>Tb;o2OKVb zO~Lt<=<@8$E<@x#Relc;>1sxiXo}x^t2WM-wtmtYNhv1RB{lVH@UWEmpOq(CV9@*; z)kTr$G)eo24YXT7(+XzRrpMMy@~LoxIV${-oMPf$LArk(tVNmcKJIb31mdG{+1omZ zfQ+(2-iRE2YVh* z{=*^ut7amPyt6Q|60`OxJIi}YE5O!YLdfLXXyaI|qR-XC3AI~!5w;2wOy$(`A4nMA z586ROy~ar!W+9?f#2|#z8~5hFHqb94le?0DIwvnV`-QswU#!GQ`jiCT(33V0a%2IAxE;2lS`l4q)r%w>{ z-xapw|B@-f>46%?!MKW`+jL3x?RhV&qeC6=IKQ)oghouF!4laO^mm6h)i{5mnXgu_ z^tUW#iiDr@WYZmBfqga4_g6n)lkciIa=&GW#BnmMkG;cKAPvl+SYS8VjX7!=@Ey#3 z`Tk9vd3d39kN?>6wc53^ua4{rnR1OD zL7hOmofG%)qYk`4HlBIAGVcJT`wFm~`)+B)?{4<$ngzdDN}#Wv8w{ZPOZY{4v{Ka2 z&}k)BPK*n?Rn))=VD^Ou_(+qW-r?sW3$Pyh9} z@v4fqTn0tyJ|fN_Q=uCAQ3uJ&`-AZ4Xv;2IrU=Rr)41onR_|KV2cnaSSQsgnFY8rZ zi7JrnEi>Jlb8@ZsJ!GXPkr1e&{edv~JRwx6B*L>MV!EtJIPX13yghn@V!~Tqh!DH+ z@a?Z>uwC%o_WJxv5Tw6V^mbppzr~^LlyK*cBx(_M$Mju7j_b@!5ruXI$t1|o_ zND4#W^N+XroAR$7@#7}M-Co}9k|~m4HDBeR37Ax&h8K1<=HnY94mVdcB~p+?K6>;E zRESwOHCO`3y`Osci6~KwR(??&&b0lG$z-Z$#gErWjeTFg{Rw&MSu{n5zv^z*IkNcT zp%MwZSJ@;aMl);1K1_sy94M=BdbY!S3#z{9Jv~bP4)sq}2q!UPH&RM(%%5DsX^<&~ z{U1dR`||K@vj`9uIU!mmp5ckW#E4)2Pf8u~fqBr|=w%?_ZDRkMXM~Q3o*g;2y@3?aZZ!m<$4Tp;aN| z`_YtB6R4aut!RiM*&}bJ2~xW?7BU50vlIQ1?7L#9`l8A5!at>EXJh!Rf0s=j{*gqr z+~YD{BN@2VSW=iW_<>~2n%fpMK_5MwVZ|LEk2n>_T4=fKn#auTl+w(_upgi}{acrJ zP{IzHEsbyC4W)V=YZ&211vgpfoz~?|=;Q@AT#Yn78}$btyk;z~Ruoty?r1Zn>Mxh1 z8f+%;n$u_IBITUdr;;pYR}3=JxsbpS{(WX+0!c`O&?kzq{v>XBpgQ`D(g#3FCRm`ayTO z#Q28SW&CGoPy8K`0(C(yp&Ty~;;#u%u?(Sq6{SMy(D)RhYKz%@_Zfn}g=+be4;uGz z;S8|5Qaa7g?q7L(K0bkn&Xj+I=jr!TY-BtdGlerr?CRflx+fw8HRk_c{GrCkHvuG+a2)fBkoHZ?Vhr@k@2l&6eTYYt;{(gk5Pi z%X^Zi7Z>e@?&*K1#{QK(zVW-y z>(=Re91^0V8@V3Iwdqmq+D!$tokmX8+~$m_NBAN*hnm0VNeq&$L9=2J_x}peu0H-F?^bx#@Lm><*zg%9AQysjGr&*=gnsWMmoNl!N1X z(7r6vBIC$RbRytI`cr%B++2)PZ!Zxg*2FWOIdux{6uiRT5_T<;gXHNNrH4FDZw|Xl zYtHn5gzCO&e?5#@nrYiI>3yo_Wo%66?lI!@tfJibm$vT2W7_$lUw$SIO`TG|*0Rh0 zj_XPk-)0}%!9KJ)U_5wuF!Xc{bIh7LJNJ6Co>^i1E|l#z3B+lh6x@u=S&h%?BZlZq z^=@J9obDphKb~`bDjq#Dw|!q!rc zWS3WW$%JB7H(G3!J;t|UgEzJbwB4x~A;w;CJ|E^E^`mBApZX9Z-8}s8KZMif!>l<< z1sQ|378aMp_3J@6ZJDD}IMDc1B@W{F?%w_Cr#cxG?8aXN+8TQEpKn1fbJs%TO&R*J zkeSg{KAO_}g#?7}Q>PGU#i&`fFtXiKtUrCZ_b0ljTzxKvq?}*PFvy*na0oy!23xAa zl=4BAyrl`7I>*s3K4GAgOeMgvqLJzxmVW}U3la*qBSTc>;n?~vslbfxo|n0Seib`v z%MIpx+c2oU@V+nNl>DX0|I!dAB}GI`J33~4_Sw?&dj&f^VE80TMvVMOEu*Qq0Yz8r zj3JB%GBTm3Pq#B_N?em?p~Sm?C!#L!Szk8qxRAt1-lq}Y^Km1mV&s~JPf4G5<=sA; zkhhxlfjXp&3EPpX;|n{|bz{!h6^?WeSAgmit(RCoC8Yf6C3`h>&nNy;h6I+{FJ0l~ zwFJ7OIeffo<-JqxJ#z9YD8*o6I&d2Of=vHXh9n`#xe`nqz6rH4Q>F&<_?z`D*mnz1 z=p~mXS=JpqCfafSn*3Goi?Rqk$aj^)*&oeZheMW+iW_n>TU~NA9yslK;oc>E^R@;? ztrd|g+eTKdr+HzFH}X<44vZQPE5mNVxlbHjt7tiVd0mOdfP7)0uh(kQ+uO@7s4+zL=YGy3IN737A!^c3t+qJ-=kR1u007B9*$tyv;=fgSsv>@d2;& z4LsY8aVd?^{i(ReqBOi`Z(J;9PfscR*?-@S@R`Y~kn4q~s&i8wjAuTe^VwQ+VE?!he7obu) z18yU?d02g)TTXLMT6d)^$!~o<67%7AaU(yd8b>MFaC5BORs^@{;XXVyb940?*}?Be zx^kcKz;&iI&xNKC4eaIn`u73sQ{P|1kqCIH!~xbQceZ3Zi0sUE2e*^bYR66=G;aHE zX~ni=zbQ(e%9M(d4g2HD0U373JS@N4#4W9u$&?=jrSUcA$O_)xk-R$m$t$HXh?tg9 zDeM+nmk_CG%6;GcQ%|mfQ9R(@wmWy~0VO#4q&H2 zkp~LsICf}pVMq;o!<~q=f&_n?67ciyrk)Dg)qeDB7U#`9$ynC6m-nDrOG~)+>lY8S zG*G^ATEKp{28FvdWe9!lQB;cVED$wC9kzq56Zpj|DD2t z(6!urWTM{hMv{}S;S6n+lM(*HXf1mx zbg+cvOFCimfKV2cCg|vwLCBU{ngqqRz8od|#8Ahn(0=$uV9yA756d9m?pX%`k#WG+ zuQH&E&^=!yiqA+1ze>eqrK7320D4Z?0p3U(kvMiWeWS}36#39DrRDD6ZZKo8k`x>xb|#`2zu^~lAjkX$~Tg!`@q3rRLFd__OSA*MpOY1WIAa^E}1-yj*4 z&HXb3RkH^L#L=any@7mlmBEzdskRiv0$V$J)Cn-m=>Bfg!MmRtR+iN245kTUuhML& zsLF_%A>;EkJYd+rpX6|j<0ebz!N0RirCsY>Zd7-xhPu z!ko5S-!1Fj!+p_w>9lFH1fx#M?tT@o-d;v7yM+(w(_5&9t`n)J4V_XLC7QGv;KLV} zZcL3Z@%3LAHMH!+7Cx*EVT9c(&K`5;UJ#|_2L8#BV1}X8)W8?ptnoB)ETwSy5<`sT zT9{(`9tW#Sz2<7Pre}aSl%~@k2M}JnBPD_!mMf_`d`Xo)vS(&uV#a3X5?e$()akPDg^>~>}s z6%~iQyP*jQ`-=r5Fe_8v5pA=ub3jW9$FfDcU0d=R$!2q>6ybe~%yk`-B4#-ek!qk+ zfHqODL>VH;IA|kyNz;0*=}MrE&Z=sI`%UQXp#7;bTyS~HsXy09RwX|(T1d?r0sK=T z{7F?uvdxn(vt^pm@rwm8PyTJr(;sx0OyyMaG`K!@c8&lDT$?Iiu3qV+vSMaVo^KgH zkw?DHBw*4Iz(+T6VM_{A!iB%JM?*MJ~oRNe1soP0I7SFhZ|=SjSRG2dGEn z>mAe2wxExPrl!xII9rX3>2|!U9NduGtCDN6PIG^0EZtqA5Me6?J)*8%e@Azve)V1A zN2pJ;acP;YuCDRAkIs1)tf8*Z?R)A0w%lLn%J)fFnd5w#1@a&D@W?A8Az^>l#35f^ ztBh@3-plcWgjRO``Ki#d(=R4v*FMs}=e9hIYVACA^=vWwcgBe8qx;4`E+k!dR5Ut6 ze)kLuz=l^S*g&a5c#%0Hr0gps7#WjOqh&+Yn1HoHQHV9e2f?#VcIwpAQxId$z%OPO zpZww}Rx~i^_*)S0PZ8k=P$fK_$_)&)%&|K6msqksNAtGiNr*oCmgC=n*^?O9ojG2- zGNaDfi6-d_rW*@cd8%xn6>mPG%|;FFmzSs)a72y;{d!aCm`^E zP=8n(QfFz9OXjO zblU3}K%G1an`d`-PNUn5_)CwMTEg0ou@d6Xz##y(zZ0)M`Ky^%GvGj5xBL38c#oJL zAtzlN$PWR8?yXqH$Jekj7YAn;Exj{Wi+_OqnU>W8DQLIQyL$2RqRV_YgCg~}#vKdDWs>(nj zS%hkgy$9`tHOzhb4vkny1i^fIA5@m^Mdo5;8Hm^EHL_b{y!d^Fb(3PR#Fk(3}Keks30&jdxd>%o`^{>1sEA>PxSlJj<(a%v$DtDjO<#G3QKz*ocFlB@ho$~Mma!3H!$-lc1{_bgIb6%gTzm(Q| zm5ER8q(S6+F*_c9#(YhUJbUdwRfNz;FCYP^3CL(@wsM5tZ7BewNXBAT+FW?3H^|Y)I6kVr4_cv8bB&xk-Gh2 za~SLfB<#Bdbr!mwWA!#DYp3h_laL@B|=X(U-jg0@&QPVVAune6uNN0;%k61}V<|K6E73QcAfl zf`FPgZDT$|FAD*+RA`sL!o{V@YtvsfuZP@bw(|&rj z3-+E|-1cO_l*U&CWC`avz#E^Y6vUEsu00z2Ipo6e^aA`vzxB?@3d2hCgg7h*`v$SM z1agt0fmeXRitFW+RO=UB(R7XrD?nE|bZ7n+$z#l{d*Po-(byIgZAVnD(P?-1u#Jo*=}q{CsQ;^(r!9TyaYg#tq5-Zq)nTi~=uD3N54Uf>R@M!r3q zxV6dz>=!8_3Z(lWABGGd>tRB5fl_Np{#yDO3k^+H~n zN(7Uxeg$e6dJR=Yc1C5JDl~pG~edQcI z@;feDCh`jbXyE>?WB2xS51eAQY}}`I3jo3@pfMDkq-|y=32^NeqDL?9ynF%zXJ6#O zPGJOfFjdL2?nlkzD+3uEfI+e_1YUls$Bv!d#DPjDqJjZOP(Ja9 z+6&a*$NYav)jdH6otk3ACRyL|$9OK>C z3DS0Z9~lqpLPh+++z1d{*7AwiNgb%zk|b4y0KVe^P!u`bKIh#%|VI;-L^sCD` zK@54}Pp<7xUS$HrQjbqOHvv7%KO8~ZJYXh3&kz7w;K4lVsQ70g`6wtPFR3xiIhvBo z1rhhz8EiqKtPeLMP&@5TDgOK8b?w!|tKitQPrs5w9tb;D z@Bu+H@EG$y>Smr==_4T^g&PMyIK{^`{`S2OYzvXpD*?6OPplk3zT;x2h-Ss{zt@8Q z>P8cI{n7~>+jq@_Sze*2_xD>(PJwV@LjHWK?WF zCjO}^7CqdLhHcdt%jYIzkr|d&7B7bnl}&m&uOTv z7I7Qg9IofTG=F4F`Wy>JG$AO(rQ;&%oRWvsZpi-#Km70D{QG}@EdT-MzdQO%jC<5o zjZaa8r2hwqb32Wpyxsc4H4Aw#*(gBmSOWfzzjcuDJ0_>STo~<=ZG(qSEDF%M%(7Jp zRa70Hg3$vuOr#k@NR6yF@|dTjWG<&#B)n%55_6;no$gW^IZ^d@yCiH3ZK-R-#%%it32JsR@WV*? zob#KAhopbgmXSb1!=TqNtGxb0HeV~?H4XTMc;iTV(hZ>U!sY=@g#L(^01-0$V6Ym7 z`hd~2jaL_0pgG#*Xw4ruu<9Fa4P$0Z%O~KD*yd3HghWIxv7ThF$7{7Lu|# z2d7Q$k9E3q?TE>!$O zylLt{9n}CSWw;{Jq7;>uc3Pma|B4rM&4PsP&Q7(t@W-w}PX}d9VysJ0jNN*Y@;5k7 zy=DIm&bANNz1p|QxC5DQl>+-C#B2lqNVGe?dATwJ4$c7%o~{fo2<3N7b4Ug)jj6s3*RF#`z3%$~Rs4;ECfxo6)$UU*C`tAH{ z>MeqzC6F2bydh}NcAO-x)e2^PHK*wZ$fVj=2{d!)*@3^Y!RX9;1O3^NH7W2Pcn{iL z1VJhwjE3}#;( z;SUY|qT<0tBq<1z$e5V`8q{_uTUb?Kk5bqcKBeH8Kpq?L4k&xHC;L82&?cuz<<4b?L+%$iaB}jd@{S}`g=nv5h zoZhT|T~!nCE6HJV*q&rlpDupeV|E}>AuC&5-`=BM>$$?P z|IT#HKdBQM6Zf>nOd;-C278z#zW|R|&72>ft2sMqx(kg-=FP97V5&i1-~7`n>F zfdnX~bif!8BK-Q3-btPMiqrjeWY7huua!tuW*Z97G%G9XN7XZ{tmrCBPiNR_-}M*IJE!Nmo( zYTF{ApcLZb*rU`&SAiE~n~TvHWI^{C@$^`0YqMMuDh>|5vQ&Snf@-6vw|8QkM)SY2 z9?p1wXFb4dmxnlPNxiyIxRDkV%=+m`*d5LP`5patU#Qve6DwfQUUx*`OR_8Z;Yo{G zgVb|OlTOk1=)Y!e0nfPQt-Q5Qg)h4GSA3oK7{&%99-eN)YPokRB zI&rjUT&0+ji%X2o>ac^NMDWV-Rjh`24!gxO6?5~~o|m3BR}q!JFY8b8<_~^>P~hK< zB2Z8T&gl$R(Fz|}f-w~HvsP?Q8+-sb+ol89_a8GM{4R7Zo6B#83-16zy~8F?^??T_ zab3$Msv7u>NrG?mo2Xa?>@@&SY~K~2Y`(+q0BZk=LQ&gbw*V4bXJ|buwZtKZUpdLZB@sQK-k;9X{6^njPo9G+2%z$+pnGmCd;c%Y^aS7N!;Dqs zPAXH8zIR#IxS-Ij=ia|);Cb5QaH$D`OUwOZqRTsq_Yjy5(5;XaXumy+-CWHWv+e$R zeaWa`zqPD-=VS*}ndzreK<#nan7?>oR-Wx~+74(i$})?bC591&A!|H*GIY>yA016z zhQbpJ_Y~RCCo8cYbLdqm1Gc*q{nxYMg-V{=-y?mPpERp|>xY26!@MG~tMx`LzduGB z)gR6#?9y)Sx%BvT+{3+oTizoDF9Tz6O#0nwJN93>@>Ti2DUAGLcKwW?km(1;@o-QW zk<&eXxxIY64Ufc)Q=Hf&gH+{I<-7J*wqmugfUrae0qLkBv~)8>a5!8z8kqhxRFGdo z9z^@$2RzNZQDzo8-4(b{{Wce6{OO`&H+Wn%#nHU}Q?AEl}- z7f3H3zKvjcscgB6y=MF_?bfefZ_iv3|5++uc4am~{b08GWHiiXZ) z0>SFlbbq&DTRrG(R*a=06Q$qRALionJUN(cjbgg(Yex)w`K7e4Y}f)t5ZRXx$U1SD zHgwh6>hM4TW9(0U2DvWQ<9MyE->@l_=d#R=-OJg;5G3~FoJk_a0I~A6@QK@)f2mJ} z`gdiCtR3pH(a#qUh`@cR=fbMn=8%V>Kddy~T1gLq1ORmd`HPTGzZ2;6OI<$lB(Bz$ zJCO2dtSQYPOAJijvmt;+uaF zU64EkHS{aLEk8JFCD;dd-$ZVXCM9yW@rqK^Ay4sm{Ft#+$%Q`dL1A=iDk&Km6fi|) z5J>EMUMwfFjpt_lsmtzTWt+~*X4y=gvG36T&Ya7CE}1)YMuBR*7D!4%>Oy#uC!jck zK8FfqZ+HB5MyBd3&wwFyo>4!DQ zs8|DNI-sx-1>!rZ7?%+yIupRFB;S{28@rIsBt;V4K;xoKtcVn;A4r7na9_LSX!z|h zkX3ph2=na3X$P<{tSj5A$o~GPh$4>9EsuEV3|7`CV?OH1PRE@r6XfHxtcE=cKmr>GIj5*5pY26aWC*w~1fB8e#>&G6o{z*Q{7A97Zm2wbC~E zS9OV)KrehLeAg)3RR`D46EJ{eCYNsBC%wEVN0T}9=I$Pkuyfn}$-TQO&m8y@xUVPmTLWhbIA8jpa0;?4e$hYP=)ZC739oRg1J6E!226?5~7o!%c;pw zCg7hs@|?~zRyweS?Q`IAH?p#T^s$Uo0{A|@St2AKLH)ZP_?<5BncT+s()My7swlue zLHyCT_s-cXFb7JlKXALK<|y+%o9gS4ezrh)TcX`NabTgX3C9ek2~@=&@go~wMk-CYek1bZ z(KvGh+>b9Wvy;I_$4CnJB}h8*Ur3a1w|xX7%k`>eGky(HAE^G~pxjB%z34-k@hvW< zrL8+bKgd{eEQ66D#5WPgDBx4cTUkYd_>KXzM7+t%H`7O1679?r@I3}?&#zcl&;*c* z1#K_11U{apMxMj3?_8k!b_>lU@Nzg=BP@bBI&h2EVY?rj6W$5pN*8%kV?rSAh{P@c zOFIE-zm_@>an#g$ECXb>Ke-AhQ*{HS1~dQ|wAg^y&G#tg<(A5kBm>7(dcT?ozb5w} z2l4|2@vC(8O7TOCtcPlcdV~gml|f{AX@cZ$LE+9D!*akgZ-k`|@b@n$mI@D(`p#K_NSS~?MD8PXQ3 znzSV)cps+^ng6PYnr9=QLQ+;t?{L;pMh5aYF8+7=2stq*#E}pgfx6p1dV~oF1~-S{ zyf@}?0hdlV-mk-bHL)^+FK*L9!wzJxothCCs={`ulkGRAsh&88}%?=`WRC0&1y4vT-(YMR$9TP4-<11(ctg$7iNosv8s-R3St^ znG^@y3MBbPKaZRHU6Zi$`t*KA;ZKKSG5&!SY-_-B%{ZCp}-tzF!=Z58m|37HLWC0}d>>7=+tV zop#;bj|_=NL%)HGPWwpl#r$eLufLc#qz4o#fD$@WQUqzxu|}AJ?ogUM6`y?EM>92b z5(O{^s3t z_z`k0AYx&$5)mGi=9DFL55$h9wcDFl65OoDCuizF0)Wf&j>tZ*PV(6qVBIibqt zPBO^+Sv(EzpjfxhVhb=RZ*^1j=Tuh<00bP(csTUg&gue&q@@tqVG$Zvunds!2_yY4 zU}eQ+r*%|>WIP2=#OeXxd-hyt*D5c0J`Mdd72<6$8nj+F6REI(4hD08Ngf}k` zud8>|G&P7)ZuTR&l`7H_u5+GJ5W1XUh5VbNA1n)xmhn?4m+qFq)b~AYZ^ym zrZH$txX6h@3xCpbrf96hDSS+=XnvOH)-BDq)y z{HmLN`C12kZ`5D}MQA;P?}pHNl(E^WXZlKf&TdZ$7q2|0#;Dzuo$y`*MU4FV{sNDF zf9tlHb>hZy@*@IB`ZroxT4mZ7br>uk1m}zRNcy40jUp&OXzzdvd%cc{y{b4HM<7j^`Qxx7)nC+u<)g7r8%nv#t{;1T;mzTe!|_KB`{b0+KO^6?N~DwKXXV&f+6 z+S@~P;6|rbjCO2!nOYpgkbM;;DREhGImo$T<21_(@R)oq=j~&Pe%(bTa2*e;-&E|B zc%)aPX(>-MQb3l9REOyHm6j?ooRNYtldH^hln7qV!SLr2v|F+D15dFTzpItT@~7y{ z?B(XoCzSKMfUNzvxRU4_(ehT^^j9&wFdR{G>!fu*!iNs{kQjP!>7JPy6dFV!>G<^1 zx1>d4G+x~FRX~@@!;UP=e4_IX{>;^3KqPnrxvZLalfzCoKciFo^m7k3S-lm0q;j6h z4|ul*QJCwhLs}yQA|ycjn%0@t6MWO418Se-UF6O4R*KN29}Y-Cs9Bs4p8Me8i5vU^ zj(*@@r>lA$I~w|1?34&BaXOZpl%$n%60WnjFSnND=}))?uDdHxJ?`vjXnZ*yDjzNQ z%%fKq1@cG%mk(C}R~YyCw86 zZn@X`G_ZD$^80XIG;u55#vt>88?MCE`xk4HsG-&pNdCcff5( zztgMHEtuRr;A%Fe)2ftYK7C^4`7`h~ICEd2o@+Cj)=h zUh3^W_K`0xU@U{9-T_Gnw?cV%ao7Jjadq9r1vG3YH0By;+g-i}0GaSp50DfALR*Ahcsx(KWv{T){(HLoR~OOCu^8>*HK<$10Tb8NPO@)k{FAaL7T4ns9_q^6d8kv;sFlA58j9s`nPuKR|Jj3v3FR{F(5 zH2b=Jtzb$nB?(>(gGShjE!bN_9{H4EcMh7ilAoV{v^m~CC%9^^t*?KbbUi#a20xlp zN?KYno^%_|l|y79E<8_)%_*1@$OMMUx&f-K+XW)$g|65{$OH~aDJX>Ny$8$f_GU{R#J#+$tFJEY&WnqSeSLk^OSA}xh=zMV zefk8Jyt=u&=jP^~pPdzhZO@t|5&e^wmxukJxzFeP$imQYAqbD5!D$oJM@$Wp>9;to zagN%K)og{xB1E7pG}<-IUcwq|;@n+c77LC~($dm$*_{Q$=TpJ(h=zvqWFCiwg@v_c zf|44CdCH*TT7yVJLc*Bn9#Yy4JWM%Ql0beQPZ3Ork!2a#Iwlj> z8D8gIho>OjCKI=Yw9M}dvn5ey-6s>cq6ABTHF52F4p!3rt~IscdQ%tN$Elqu41OPn zc&F!78)jNhlWjj+ePumv=Y!pU{Ax}va^pT$t zeD>^8<;!}N&$YLgmsg_e`B6b(q2=q>PtE+^id$!9W}2@K4!R+0PfSc48Tv!rS{8Qw zf3S~X!cK1hEc1O<9(YRU5^oB|;ck&PSeTo4$PNeRf>f5*+1{Ia*k&1Y2!k`|33}-S zj!y!s33{)rjLh)JNY$rLFHh55Vbsv7w^90~`N+y-#<@8cMuw8vC1Yz5Gx*n)oWAqG zhR=7WCUGz6yjc3cV^*aX6>B}NCwQ(kJ4F%%K)9lmt2n)O&O(5(tqlX|Jp}_5$4*}s z5Re-Wi0badn<*LHT@JkHFcB`odInvJze}tX6)cPKG=+(f)D${!1i!k_uC)Ohh=s`` zUk?R_@qllgTUgjtJW*?_Z`u+X+B*OyE*!0~7<~^(Pk&@;DxAf+v$M11Rc?;Gm3S+V z)g@={hs>t-G;k8BoPU13#TiM9B8Zpl3iO4AmDP|dJE@A1ZF_N1bh9!Ta8uRBo%a*d z=XqZg*~Uu8&NX{TFpL*zFjG*x)0Nx5>8c~$9L}5WXlsIELmsB3*dD@O5v_$U!~@V> zi2Ct0p=SR29+aTl_73_ybZ;(Ts^5NfB@6)=FA969o|7h8 zTfjq>GvPt^eS-N)_lC>6sC%xwBq+MTbLFxij7zJXY@;H!&U$(Vgb0EJr zZ@TQ-u{g8d@>_O`*F~wGF8a9X!aR+j%zk^$t!4{h-6(gHj?%+q7(^O@%KG20<%`+Z zu?^_Oi^rRZNN61Xyv7nW2ldV<=B}bB&K!Xc-_hB2P!|NaCC`r3r?tJ-{0daQUfr(O zI~JuIlG4zq^|^+Rm9&fVx~6d3eH|O)WM!?;skbjJEw!+)n4O&kqux#QTDf_7OLZGL zpFK-nN#k=VRnC#_?Ceal?+>YbHBr&i(^T0nnKo|P6VFn04KM+`x}cz7gVYrKI<>xH zm<^zI_kN=VnSPr+aOXNCgac0t>asYOzLu+S(5o|^%GH08c)Zm!6lHtBhU=rF)q(#W zV>ccm;;%&H%Y0_|t&-*$0D7{(Z|YV@7alyTff3>k<^uAiD31gQ&^mXU-nE9uUocND zX0pvyj47yB2Miz?e!lzztC5429oF8u-=MRS% zmK>G&#poaS(1$J#F{g%H2YcZN#RIoS@gYI$)kzifEf?`(Uu>R-6_!dTD-Hl^KE@O* zc&cvGy{Zl0#vOZrTs@=Ie^u1va+;ew9~W;*>TDc`ZHBln7?NW+j7wP41SpgmC@rHy=WGk@d?*$qLRWdM61Z8|aDiACr@SsNTgSvL4!fDGlvO=F zCk5|=s77HrVO~5Y<2a?{Infi-kjgZtW`oGpGMSPako028`+;xX2m>n@e|T4=PU)M{ zKskdVMEQ>QtPuQt#AU@P--HLPuMkksM?Sdcz;#b??+-aX>nEzY6=~vly}972Ru{pH zhb+{hoC@`Jnqe6E{KLh4md>KI`iy5ahTRHlH93l!Tja~GTG#D$)w=f{KUX#cjq`HY zxYCk8Rg?-|ZkPC8m)-(L0gEHGpx$15js4>ynIE#!v+9g&l)+J`Xo^l^DnXCvPayCV8&4XDNKz`aSx(>W9ra`MN=a`*M;MmB<=f z&{fTWlm!u2~CkMeE|D;==$B_F)sY?zmpKzPRsj{c!_>JcBb;qtX;zvPdOT z!q~2Zd+!Npg8NDDKqvUboNwLHxrm(GvrfN8BjE?(XD~bPPb;=rx>1Z=YK$^aNc8(_5a9vWYwFz6wENnUt`3QWG z%!(o6g-kZVmyyCtuuZft_a+Dura>JvSdU@{M{y05c zSu+x~P6J}Cc`84F;2JyZ39mum3MN~<9wUx%5Z)B1-07LQXZe!Ydh?CUwI`m*;}j8R z0$pqFD3UCek{_#DMRp*p5EO8vg4^5{KZgh%(XP?%&>qpA(?aM_ChUlVB+#XHP!2LW zmS{!>^UHp=ay)Vefkb(yYueFDt`FVVBC;tLDl@Cb_0ReQHlKBkG9bDug}g`6P|0sO z9V(k&G$Io&S!M-~>H|dqw~@N2KDWj`QEWeF#n|2uuJfSIQ~w)F_ly4YBNw#k-fy?o zDf2R+3=I^)gvi^xvJL!KyTItMgw?`|=yD_EA&*L`qS6c_zDAHozKvXn6p6}=f=+5M z`%wwv9kXtjkBsLx?#IzrL|i_yMI19@Ee5VbD;;w@)|+cF z07!X7xT#k#HrKL=TNb!U`ickkwFl-kuvk38db*FAt)fYrjRTPsJ&5xYIe6CuuK%0= zdRT_XX;Zx$0aXh+$Mm}$T3XG5bs$hmE2ZJi$%hFQ2$m(7@Llo79jA4{)4ofeuP1u$ zPBWXW!{$4tCijP=ru`gmKm;hEbr_x4L2s0Z?h@tlDThc?BGK-vg>0HQwksd8@Sap> z?JkOH-1zu#ny_W02KKNLVI|_1V25cS;&XQ&JDJ%=JyUlRj*wqq0*Bmt3~SSs^j5qR zGU@vxoiC^{e#hL_b!cje@9EQs8w_BdFU!5woBI0V3jt@1j{&~|D3zTO=xoM?ssjfJ zARcsm;(c7clq!lwgAXWW&|jY<{N?}Ww`d>57SMhu?9p190VxSu0B+C;9kC;gJXhAh3DdhTNV@} z4^b2cBdK!GC9>NXC%u??NfSJRbCEy!^1*Cmf$2y^yVYt+S(UOozc_vhB1UV z_?!2Rmfoukq@nWrzz@aqIyDMU8Yj({dWA7|d#-6lK66ig=Vzf*j*9J_xxXazY5h5m zsD)@kw9f;M;k@k3rUly%QKjTLIFOioZ{@t#zuvPb|08HQYhelN@UZhF+09K&X12VR z7m9<*l_>7B4r4zVe4y^FI?{B{ntohtctUzp{Z4ND{;P**x$o@JB z+MkoWagiu24uK>I9QHOced5RI+YL_6bTXG){o*h{oj|Ybg1eb7=kBQttbOv~O7E2%=#_F0-oHxuf|Jf-XNpW zwn#5e+q)sN#}Sj+@NXY(Qqyb`0I!R&5ZiHWKdBaeK7TBcrrQ+hP`(X7j#1e4{YUv2 z`WQyBF7hrW>8J2g#VGPz#0L|R`E^a5f3E2|r=`Wlw)L!rOtM=~ zj*O3UQBj$Ipcrr{v67VRpf{x@np)2N;$%CTMgbHp9fw{@SRb@37{BuIIYdj-=j1&( zeI^)WVftbvGb4-rQHuZFW(Hd@fORd%4 z>4yQKbPb?ivU498IJ9X*4xvH1ZX;1a9Xqc-#1w>t@L5k;Dq+ks-SQuXtz?9 z+oUGx()9Z04UdR@Knf_-Q?P>0wM`KH+uK(hk)fH5`17C2Sz6Lt6M?ezl@-7leJ>>= zAb`o)0a;FkhS{A2bDI)?XlM1uC?ME@D_vg5Hd1gZn?{#JcIiaFO3dDZJ+yegUiLJ{#zt^GS2PsJZ9U>$$nD zt+8%E$W^NX3MJ>usPpM5Qy}R*_vH^{;%~!b!mARRxL!{1!fkT8Kfi1X7d-Ji=?T+g?v2lg`?%8GBMA20uMG+g ze2b*mbac7^D*&dv)`tXR>D99FbuX{t+<_uE zuMaH)Ru+i(#!RD&=jCdDiKpF2?!&a|&b|)WJAolBE3h+Pi_iCwU1pY@x2Y4=c08&F zCCABDE_x^S*U}D|OY6R&zBi>@N!CW~dh|0JhYD>OP0-jlgrbW@nhhLzvv$tW$yU581}Zy&sEXY2NM8>$K=*Ka~h-oK90Z@_*1oW7H!rA)WczijuG+Nh;~ zfLqpyGpEogjYEy;j)n-_K(4hpNT9e+NRc>+4yej&3Ym^Io5J<6TF$##z-WX zt#3V$ev-=HowLfU#cna2Th9(Un{QgaS6BD%?9{Uw>v_nYk6-!KAG7k}X#MhRe{{{f zJ(Zu2-D=Di>hM_g@yvef@EV}LvacV;-%Hp+jL9+^K1$-Ujfd$IS7)pXc%9=q>LrD| zUvj-3z}L_ry>ghf?F&mn_NldC?W!_N+nfu7a(EV8lQoKB$|1sI5PmRlq)gnLkB%4$ zjLJ@b5=9keu8sH@6YlU!aoE8!KY#xLez};EsDabk0Ab?JRPAPsHO4w^a@aWCH*+kK z>Tt4aoW_G>9wUoeAh=55tIf?id4Dr}&U-k8%a+)uKS#|E_*5~PU!}a)l|SF38$DQ7 z`5pp`q;@|tcey-6F{LJnR4-C*8*#)x>?5BkRx4@ zwN0btQ?xX-cTIBFKRaE+1!1RZT7FBYZJ+ZoKZHJQq)=I@4wxi$`~26%7kbY&_TIwd zr~zQ$kG0*JAox(>#mDtT>pWc8{kiExg^BfKRbWuiIptJ-Z!kVHpmzaCj5QRDO$M@=w+z?C z_7J@79rgLN%iHEKy^*elN*<>9og3!uO4z%Flz#WC6peJ$+X~5#+?m#Ny=RRkn@8)6 z$D39Ms}7c}{u4#&a#?6vu#Hi#q2QIiUZPxsLYG~6M_DqQ#o|omSUGy;GKVde=DYOQ zj`Rz{c#sbve@QjrJp*u2%kwYUq;@=ld@eKkd-5niuaRIo-;8m%43|wZ+p8a^Jyp@e zWE_Z*{kK|w8p zdhz^%eUruTxxYU{4*qC<1}UkHC=MZEAvS3|8ykT3T63j7BCxZQ515wLQrVQ)^{^XH zyj`jUUB?>Q%o7Qke$t+n37dkD@;>P^H@8v#SG!c#Vjj~HOx+jWDy{eWu2vpmC1xtg zEra}F-`zV@kCPoUq1)ifa=9D!l7~W|+BKjJZ=^^=0`6IOxLWJHJF6}y=T{%x?BNjA zH32&VyJf1Y`D~_Yo>H|1tQ>7k{5(H?*F!xq0k85lUUD*8B&m|}LtmDvw_i4IP)O^$ zY@{t&$Wvj#Duf6bzmL8gqS~cUE-W`fl}~*Zk}%tH6%M~@WEpmRPVXh9($Gm72bR=+ zfI+B7zr3@emVMYGOD5Q2aJJXd6Bx>@H{EB$@cy4jKzGP{s|Cs^6P|5dLbSy3$#b)h zWRYHtUPYtPWBk3|(g4O|Q-S8mjHIKk)lQr#!08#AuB2FqC@8Ehb;_~Z0bH{T=#ial z0+`o>>TvVL(9Gc452@ia)1<;9u9Bl>>tUq{3sx_ZbtA`D#S)6ZM4xhzoPw|kb}=z_ z9H3t?*VZ4mwkqUVQRxr0^xbFVCwKg&QMQ z@lC1E%z6X&go%Mf4GcU>3MH%|CJDE+;5a&ZmXy3DrZik<$M15=wl#EirVV!BP1oAu zS-$|{w`MM3>iztEiNAj#<>@26b1M}Q2I59!NE$*)m%N@!PxNiQSIhEmpgjGcs;kR! zaXp@vnM6;oHeotgVPa&vd)RXXKx86(30TLm0u=|K;f+pK-8Kvn|GLwuuyZQdgYp@{ z(y%$a6UGG`8qSlo!LS4YmmOQV-VKG+A465u$FsZ8T@f6BtCN#ya}dy|Gn>NqJ!(2U zL%pn2TyB4qAuoYV!YBHWF(Vm!<@To^JFY)ZG2=#1z(&b%8!dDA(S|?QD)VDDy5+0p zy*PE741el0K>?MVxlt5~}p(ycD?Rw7H>37;wXA<4Gnu%6y(t~`kp4hjlGJjN8ihbgFH zZ@{Bp(or-1euuv+Kbx}u^XG24q%o-7;?v%253@P1>MHj163Tl0z(P%xcY1f8;^%06 zdigdTYtC*93*w1D+NjNYbW{%gsU+%UseOHcA3o)fC?8ZxWXlf9oz$_j3}zX&p_2)? zvT=DFZ2{vz~)XB?BiL#148sTO}~N>{f=&E_-LqNb&V zxxS|>k%xNmu~-PbeFyTHCV452sh%{FkiZ&zUnD*_c_&Hx;DBOv`9wcyBrBDd&c=>+ zt{f4gDKEn&6Ng_ut%q|j=t#o?`|X?QlK&~b1za|{4;X1)^QP@YtjoH@j5TR`c!xKQ z84z#3flifaA7z?%#oW7u-6+_j@JRSVxXwC!_7h|Qy(?=4r@c?=16v!Xu$AZLx7Z$W zBkaljE*zV$9mEnbM(7>nIsZ|(n1v59B|m;7ZEO^Jd*j1`rJMipIeUs;U2mqeYcsPk zi-$X2T~vsk+TDkF-b8ew_w}{o;P5|T#M~Gu=+w&;^Nl^#B$~MuS0%1jI>48=X6h%f zLlI|^lWl)Z2zmcpXgy|I!A+##YbSx`!Uqty$jWPGkN6q6K<052f$ypqE(weMxWebv zkos~?@%i7pMEcDB_3`B3kBUy(so|f=4_>%V=)1le7Ky7_-rXxweL24j+#ZmWHn(zd zbl_{#7v?@rtGq`hXwvYyQmh>@M;fo|f%iPFa*S@w z%Y$z69Hw9BlMc}5z1#Dyf~ne2dR1EB1Dw`zbHSA#7T!_+Im5z6M>W*J)OC!w9+NbLLB|Z5x~F|oPI;!% z?qs&Cxl#{YeTcru^x5JKcUa@pGngY*|0v>ebD8RgV^?RU%_5xxtsAWmtsiYLZ6s|R zZ3=A`Z9#;X{u2bxhQ(;pHjlh3>K)iqF(H{IhrC&}i+uC)C2=TgJ$G^~B#dqV|Ja6vem{TS9Q0-imKAWfoAQ@^*&*xKlc2bO(3*%5cSN%dck zF-P{mrEUJAHNEP8;|vE#gxwyeeAAVrfy|2@1ULTu?!qp(F8{aRTyD1h{Ph3nH>Vie zIa_E8&6V3cTs@RI;o#wL*?FNdtP7TE@Hv`e`mB!^8VWwk{e7v%`q3)jS{0Qgy(h+( z07&@yAy{QG=k_}8T42RkhHY%}S~_zwl|hZnN~1GlXHQf2+;e%VE6E@Yu!T0B)#Rq! zdp}Ju|K=l9L^w8Tq0(}+3QU{GFDlyDI0^soDb_QzT}AQtXTmE30-6pG0>Oj&vLpCr z+6q2**W|&$^)IqSgr&*cc2DIz&*rz+-Dp~j3JDIJ_Le2 zj|iOP9s|VL+>t+>(elSptJ$dG<8GrKiHBm1ZjQ@?Wyyf5%kk8&G9N0{m7%PEcjT}d zR-&N*di+B}iB<=Q5pG-3!=-S+BQPQZ)-T9o#cE>Hl4sPe4zrP5-f+*jDk})Og#|6R^4?V)$a`DOuDmMdxW8v+i0LxOjQ+t!b?yE+xHv zqgsDohh2M#4~I)wf=Rt)^sxR><(HlP@vpLHMVO@1NeyBmZv(Ox2LWlNcw}aFflYMM zT)rQ+WXv423xd;Iw-SaDWjZqN}<79V^@kvkOPLWi!`{_=?V9x_aLN~V*BQn_>X}rZn+w$=2z4NQn zKzRg#6QLrIUmWE@b}lC7YO9+Tkk#rehP39gp zT;?3NmSwEc%=0qjG$TP@-kF)IperlX+P?B|@wjN+dc@z_x_F0ibZkdbPCn{_L@UUC zJ~DpRvHb|$8;@G&d)`AdQUws;}72`paxKk=&-TwNDAHuPTJ|NzJcu+n2JD( z#+GJLu6no{)uT@Bsx3 zNg4~mnEE+N#FkKS@m{q#xBJYvjQ(IrtnBMc2?ox1hb$^;5?DSRlTdHkd#5ka!lGrg zs3<4zLdssy14REu&i9U=HMp(xeDvhX2DiTQv(*Z$*ObwHGjY8OU7ev*8KKWsFjwG8 zxDs?TEXvLO+LO&RRG`8DSiPa}_qvC3K5-RfOkNjbvF`Uv#FMyQy$DE~P3Gq(7FEghRcwHP^E>2g>Vao7`BL`mC3`=Hl6kqy+Cf%i%<)@Vi%KwTpV0?}6%X z&ZSEki}iRGLDmaLCw}2Ws(R}dt!nxn3eV%N0-(x3uRpoyx(<5jLcJq)5=k#(=qTb{ zl(_$rR?0bjfxO??46ssh>=7*T5<(RKKsiaIAxkdb?%mAd^(W2R%`th=vgY1X`2`;z zZb1EZLH2j>|53YVSQFati2#8oPK=)+H z@+%$C-~TgCPRscpL{d+FI_(Z_O9kDV^mKYZWG430G@bo5u=bqS4cR~@eXs@Uh2p@% z=EsCTkKnDn3$jO{r7-qsS6t1U#9hfN9?EqEPWjO_FA`{YkOvmSXT0kW0yTz=oUEp{ z0z<69M5R7bL&g4tG$_c7geKkJ_0u>NIIWx0eXw<_b59k^R$wDf>XPRXV3M4mud=@b*v4B2DnOsTeVdz{ zoSc+Y#CN1)USw6>%Sh1Fq}_LhLv1BO=FrJy-jn>Fnt>^J^ML~nzh-aSv}uuqE&n5@ z^P0Aszx=thSw>d&Z0$S77T%XCNx=H)g!rWRBfv@caA0rTaPj^$;NrDko40M;Xvkc+ z@c9&|CB3~*p_Ui|EqTIyQa{O~Zh|(jMKQzG-TktBNkYPc?c29=cW~P-|8nNiXYcbx zNl8lIcd`qZEt%W_EF~4CmjYk_Jq` z=D?GG!Qg>6aL?TG3xU#5KEs5$N^ZIL_Sc{96U_xGJlw{c4U<|B06ZZ|^Be24RN1W) zpEY&ggBfySfr|JH{c|gL^{UvRiWRyi#U$*rSZvl`c+nbWfaH`XOrMWRZawJw9ww9$ zIEnj=c={FaRRtiyC%nKliBRCwf^e7Op%uWLhG5Vj0Q5JM?a=X$y``*k!pt?(|AB-& MUHx3vIVCg!0PQSJ00000 literal 0 HcmV?d00001 diff --git a/localization/zh-TW/abstract-factory/etc/abstract-factory.urm.puml b/localization/zh-TW/abstract-factory/etc/abstract-factory.urm.puml new file mode 100644 index 000000000000..999091ef54f6 --- /dev/null +++ b/localization/zh-TW/abstract-factory/etc/abstract-factory.urm.puml @@ -0,0 +1,101 @@ +@startuml +package com.iluwatar.abstractfactory { + class App { + - LOGGER : Logger {static} + - army : Army + - castle : Castle + - king : King + + App() + + createKingdom(factory : KingdomFactory) + + getArmy() : Army + ~ getArmy(factory : KingdomFactory) : Army + + getCastle() : Castle + ~ getCastle(factory : KingdomFactory) : Castle + + getKing() : King + ~ getKing(factory : KingdomFactory) : King + + main(args : String[]) {static} + - setArmy(army : Army) + - setCastle(castle : Castle) + - setKing(king : King) + } + class FactoryMaker { + + FactoryMaker() + + makeFactory(type : KingdomType) : KingdomFactory {static} + } + enum KingdomType { + + ELF {static} + + ORC {static} + + valueOf(name : String) : KingdomType {static} + + values() : KingdomType[] {static} + } + interface Army { + + getDescription() : String {abstract} + } + interface Castle { + + getDescription() : String {abstract} + } + class ElfArmy { + ~ DESCRIPTION : String {static} + + ElfArmy() + + getDescription() : String + } + class ElfCastle { + ~ DESCRIPTION : String {static} + + ElfCastle() + + getDescription() : String + } + class ElfKing { + ~ DESCRIPTION : String {static} + + ElfKing() + + getDescription() : String + } + class ElfKingdomFactory { + + ElfKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } + interface King { + + getDescription() : String {abstract} + } + interface KingdomFactory { + + createArmy() : Army {abstract} + + createCastle() : Castle {abstract} + + createKing() : King {abstract} + } + class OrcArmy { + ~ DESCRIPTION : String {static} + + OrcArmy() + + getDescription() : String + } + class OrcCastle { + ~ DESCRIPTION : String {static} + + OrcCastle() + + getDescription() : String + } + class OrcKing { + ~ DESCRIPTION : String {static} + + OrcKing() + + getDescription() : String + } + class OrcKingdomFactory { + + OrcKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } +} +KingdomType ..+ FactoryMaker +App --> "-castle" Castle +FactoryMaker ..+ App +App --> "-king" King +App --> "-army" Army +ElfArmy ..|> Army +ElfCastle ..|> Castle +ElfKing ..|> King +ElfKingdomFactory ..|> KingdomFactory +OrcArmy ..|> Army +OrcCastle ..|> Castle +OrcKing ..|> King +OrcKingdomFactory ..|> KingdomFactory +@enduml \ No newline at end of file diff --git a/localization/zh-TW/active-object/README.md b/localization/zh-TW/active-object/README.md new file mode 100644 index 000000000000..7ed92bef3244 --- /dev/null +++ b/localization/zh-TW/active-object/README.md @@ -0,0 +1,123 @@ +--- +title: Active Object +shortTitle: Active Object +category: Concurrency +language: zh-TW +tag: + - Performance +--- + + +## 目的 +主動式物件設計模式 (Active Object Design Pattern) 將物件的方法執行與方法呼叫脫鉤,每個物件都駐留在其自身的控制執行緒中。其目的是透過使用非同步方法呼叫和用於處理請求的排程器來引入並行性 (concurrency)。 + +## 解釋 + +實作主動式物件模式的類別將包含自我同步機制,而無需使用 synchronized 方法。 + +真實世界範例 + +>獸人以其野性和頑強的靈魂而著稱。牠們的行為似乎由一個獨立的控制執行緒所驅動,該執行緒基於先前的動作做出反應。 + +為了實作出一個擁有自身控制執行緒、僅公開其 API 而不暴露其執行細節的物件,我們可以使用主動式物件模式。 + +**程序示例** + +```java +public abstract class ActiveCreature{ + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + thread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + requests.take().run(); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + } + } + ); + thread.start(); + } + + public void eat() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} is eating!",name()); + logger.info("{} has finished eating!",name()); + } + } + ); + } + + public void roam() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} has started to roam and the wastelands.",name()); + } + } + ); + } + + public String name() { + return this.name; + } +} +``` + +我們可以看到,任何繼承 ActiveCreature 的類別都將擁有自己的控制執行緒來執行和呼叫方法。 + +如,Orc (獸人) 類別: + +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } + +} +``` + +現在,我們可以建立多個生物 (例如獸人),命令牠們進食和漫遊,然後牠們將在各自的控制執行緒上執行這些動作: + +```java + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + ActiveCreature creature; + try { + for (int i = 0;i < creatures;i++) { + creature = new Orc(Orc.class.getSimpleName().toString() + i); + creature.eat(); + creature.roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + Runtime.getRuntime().exit(1); + } +``` + +## 類別圖 + +![alt text](./etc/active-object.urm.png "Active Object class diagram") diff --git a/localization/zh-TW/active-object/etc/active-object.urm.png b/localization/zh-TW/active-object/etc/active-object.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..c14f66144ee297261111c1c05529c5d00ebe393e GIT binary patch literal 19466 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 literal 0 HcmV?d00001 diff --git a/localization/zh-TW/actor-model/README.md b/localization/zh-TW/actor-model/README.md new file mode 100644 index 000000000000..652696ce8931 --- /dev/null +++ b/localization/zh-TW/actor-model/README.md @@ -0,0 +1,193 @@ +--- +title: Actor Model +shortTitle: Actor Model +category: Concurrency +language: zh-TW +tag: + - Performance +--- + +## 亦稱為 + +- 訊息傳遞並行 (Message-passing concurrency) + +- 基於 Actor 的並行 (Actor-based concurrency) + +--- + +## Actor Model 模式的意圖 +Actor Model 模式利用隔離的元件 (actor),透過非同步訊息傳遞進行互動,來建構高並行、分散式和容錯的系統。 + +--- + +## Actor Model 模式的詳細解釋與真實世界範例 + +### 📦 現實世界範例 + +想像一個客戶服務系統: +- 每一位 **客戶支援專員** 都是一個**actor**. +- 客戶 **傳送問題 (訊息) ** 給專員。 +- 每位專員一次處理一個請求,並且能夠 **非同步地回覆** 而不會干擾到其他專員。 + +--- + +### 🧠 白話解釋 + +> 「Actors 就像是獨立的工人,從不共享記憶體,只透過訊息來溝通。」 + +--- + +### 📖 維基百科說 + +> [Actor model](https://en.wikipedia.org/wiki/Actor_model) 是一種並行運算的數學模型,將「actor」視為並行運算的普世基本元素。 + +--- + +### 🧹 架構圖 + +![UML Class Diagram](./etc/Actor_Model_UML_Class_Diagram.png) + +--- + +## Java 的 Actor Model 模式程式範例 + +### Actor.java + +```java +public abstract class Actor implements Runnable { + + @Setter @Getter private String actorId; + private final BlockingQueue mailbox = new LinkedBlockingQueue<>(); + private volatile boolean active = true; + + + public void send(Message message) { + mailbox.add(message); + } + + public void stop() { + active = false; + } + + @Override + public void run() { + + } + + protected abstract void onReceive(Message message); +} + +``` + +### Message.java + +```java + +@AllArgsConstructor +@Getter +@Setter +public class Message { + private final String content; + private final String senderId; +} +``` + +### ActorSystem.java + +```java +public class ActorSystem { + public void startActor(Actor actor) { + String actorId = "actor-" + idCounter.incrementAndGet(); // Generate a new and unique ID + actor.setActorId(actorId); // assign the actor it's ID + actorRegister.put(actorId, actor); // Register and save the actor with it's ID + executor.submit(actor); // Run the actor in a thread + } + public Actor getActorById(String actorId) { + return actorRegister.get(actorId); // Find by Id + } + + public void shutdown() { + executor.shutdownNow(); // Stop all threads + } +} +``` + +### App.java + +```java +public class App { + public static void main(String[] args) { + ActorSystem system = new ActorSystem(); + Actor srijan = new ExampleActor(system); + Actor ansh = new ExampleActor2(system); + + system.startActor(srijan); + system.startActor(ansh); + ansh.send(new Message("Hello ansh", srijan.getActorId())); + srijan.send(new Message("Hello srijan!", ansh.getActorId())); + + Thread.sleep(1000); // Give time for messages to process + + srijan.stop(); // Stop the actor gracefully + ansh.stop(); + system.shutdown(); // Stop the actor system + } +} +``` + +--- + +## 何時在 Java 中使用 Actor Model 模式 +- 建立 **並行或分散式系統**時 +- 您希望 **沒有共享的可變狀態**時 +- 你需要 **非同步、訊息驅動的通訊**時 +- 元件應 **隔離且鬆散耦合** + +--- + +## Actor Model 模式的 Java 教學 + +- [Baeldung – Akka with Java](https://www.baeldung.com/java-akka) +- [Vaughn Vernon – Reactive Messaging Patterns](https://vaughnvernon.co/?p=1143) + +--- + +## Actor Model 模式的真實世界應用 + +- [Akka 框架](https://akka.io/) +- [Erlang and Elixir concurrency](https://www.erlang.org/) +- [Microsoft Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/) +- J基於 JVM 的遊戲引擎和模擬器。 + +--- + +## Actor Model 模式的優點與權衡 + +### ✅ 優點 +- 支援高並行性。 +- 易於跨執行緒或機器進行擴展。 +- 容錯隔離與恢復。 +- 保證 Actor 內部的訊息順序。 + +### ⚠️ 權衡 +- 由於非同步行為,偵錯更困難。 +- 由於訊息佇列,會有輕微的效能開銷。 +- 設計上比簡單的方法呼叫更複雜。 +--- + +## 相關的 Java 設計模式 + +- [Command Pattern](../command) +- [Mediator Pattern](../mediator) +- [Event-Driven Architecture](../event-driven-architecture) +- [Observer Pattern](../observer) + +--- + +## 參考資料與致謝 + +- *Programming Erlang*, Joe Armstrong +- *Reactive Design Patterns*, Roland Kuhn +- *The Actor Model in 10 Minutes*, [InfoQ Article](https://www.infoq.com/articles/actor-model/) +- [Akka Documentation](https://doc.akka.io/docs/akka/current/index.html) + diff --git a/localization/zh-TW/actor-model/etc/Actor_Model_UML_Class_Diagram.png b/localization/zh-TW/actor-model/etc/Actor_Model_UML_Class_Diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c34d7a75fdeec17c2665cb7012233805ae7454 GIT binary patch literal 47298 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 GjQTf&f{mL1 literal 0 HcmV?d00001 diff --git a/localization/zh-TW/actor-model/etc/actor-model.urm.puml b/localization/zh-TW/actor-model/etc/actor-model.urm.puml new file mode 100644 index 000000000000..020c1fc735a4 --- /dev/null +++ b/localization/zh-TW/actor-model/etc/actor-model.urm.puml @@ -0,0 +1,35 @@ +@startuml actor-model + +title Actor Model - UML Class Diagram + +class ActorSystem { + +actorOf(actor: Actor): Actor + +shutdown(): void +} + +class Actor { + -mailbox: BlockingQueue + -active: boolean + +send(message: Message): void + +stop(): void + +run(): void + #onReceive(message: Message): void +} + +class ExampleActor { + +onReceive(message: Message): void +} + +class Message { + -content: String + -sender: Actor + +getContent(): String + +getSender(): Actor +} + +ActorSystem --> Actor : creates +Actor <|-- ExampleActor : extends +Actor --> Message : processes +ExampleActor --> Message : uses + +@enduml From 0f67a61be1c4504e48045438ca4ae9c090216e5a Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 13:17:28 +0300 Subject: [PATCH 074/108] docs: add AnakinYen0329 as a contributor for translation (#3513) * 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 e90d733e4efb..465668e5b29c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3710,6 +3710,15 @@ "contributions": [ "code" ] + }, + { + "login": "AnakinYen0329", + "name": "Anakin Yen", + "avatar_url": "https://avatars.githubusercontent.com/u/122139183?v=4", + "profile": "https://github.com/AnakinYen0329", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 247f5f17e87a..b68b9c2338ab 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-407-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-408-orange.svg?style=flat-square)](#contributors-)
@@ -603,6 +603,7 @@ This project is licensed under the terms of the MIT license. OrbisAI Security
OrbisAI Security

🛡️ Raju Gupta
Raju Gupta

💻 김정모
김정모

💻 + Anakin Yen
Anakin Yen

🌍 From 3b758da41a02b4f768611630e8369bd2dc4246ea Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 13:44:31 +0300 Subject: [PATCH 075/108] build(deps-dev): bump org.assertj:assertj-core in /rate-limiting-pattern (#3505) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.24.2 to 3.27.7. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.24.2...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- rate-limiting-pattern/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rate-limiting-pattern/pom.xml b/rate-limiting-pattern/pom.xml index 9d5d2624ee8b..454cbc81838d 100644 --- a/rate-limiting-pattern/pom.xml +++ b/rate-limiting-pattern/pom.xml @@ -51,7 +51,7 @@ org.assertj assertj-core - 3.24.2 + 3.27.7 test From 7b4482f08ce95ef7a182939909cc70dd8bdb8ae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 7 Jun 2026 14:00:45 +0300 Subject: [PATCH 076/108] refactor: remove redundant compiler property declarations from module POM files --- dao-factory/pom.xml | 6 ------ microservices-self-registration/pom.xml | 23 +---------------------- rate-limiting-pattern/pom.xml | 2 -- 3 files changed, 1 insertion(+), 30 deletions(-) diff --git a/dao-factory/pom.xml b/dao-factory/pom.xml index 2e771e736688..719ceb9507d5 100644 --- a/dao-factory/pom.xml +++ b/dao-factory/pom.xml @@ -37,12 +37,6 @@ dao-factory - - 21 - 21 - UTF-8 - - com.h2database diff --git a/microservices-self-registration/pom.xml b/microservices-self-registration/pom.xml index 4b708cb0eb12..fd98b12d8587 100644 --- a/microservices-self-registration/pom.xml +++ b/microservices-self-registration/pom.xml @@ -39,25 +39,4 @@ greetingservice contextservice - - - 21 - ${java.version} - ${java.version} - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - ${maven.compiler.source} - ${maven.compiler.target} - - - - - - \ No newline at end of file + diff --git a/rate-limiting-pattern/pom.xml b/rate-limiting-pattern/pom.xml index 454cbc81838d..2d8d12fdc886 100644 --- a/rate-limiting-pattern/pom.xml +++ b/rate-limiting-pattern/pom.xml @@ -13,8 +13,6 @@ rate-limiter - 22 - 22 UTF-8 5.11.1 1.11.1 From 3b9a2df119ce4922ea6a238fc3494efff7b8d718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 7 Jun 2026 19:32:28 +0300 Subject: [PATCH 077/108] fix: website build failed --- immutable/README.md | 4 ---- immutable/etc/immutable.urm.puml | 21 --------------------- 2 files changed, 25 deletions(-) delete mode 100644 immutable/etc/immutable.urm.puml diff --git a/immutable/README.md b/immutable/README.md index 3d780ccf3109..07834d2b380d 100644 --- a/immutable/README.md +++ b/immutable/README.md @@ -33,10 +33,6 @@ Wikipedia says > In object-oriented and functional programming, an immutable object (unchangeable object) is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created. -Class diagram - -![Immutable class diagram](./etc/immutable.urm.puml) - ## Programmatic Example of Immutable Pattern in Java The core of the pattern is `ImmutableUser`. All fields are `final`, the mutable `roles` list is defensively copied via `List.copyOf`, and "mutation" is expressed by returning a new instance. diff --git a/immutable/etc/immutable.urm.puml b/immutable/etc/immutable.urm.puml deleted file mode 100644 index a455b1eab93b..000000000000 --- a/immutable/etc/immutable.urm.puml +++ /dev/null @@ -1,21 +0,0 @@ -@startuml -package com.iluwatar.immutable { - class App { - - LOGGER : Logger {static} - + App() - + main(args : String[]) {static} - } - class ImmutableUser { - - name : String {final} - - age : int {final} - - roles : List {final} - + ImmutableUser(name : String, age : int, roles : List) - + getName() : String - + getAge() : int - + getRoles() : List - + withAge(newAge : int) : ImmutableUser - + toString() : String - } -} -App ..> ImmutableUser : creates -@enduml From 9c5d703ddae4fd8343769f7709004319fcf466fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:56:32 +0300 Subject: [PATCH 078/108] build(deps): bump ch.qos.logback:logback-classic from 1.5.18 to 1.5.34 (#3517) Bumps [ch.qos.logback:logback-classic](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-classic dependency-version: 1.5.34 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- polling-publisher/pom.xml | 2 +- pom.xml | 2 +- rate-limiting-pattern/pom.xml | 2 +- subclass-sandbox/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/polling-publisher/pom.xml b/polling-publisher/pom.xml index 7cf4c83bae7d..2e5f7e8f35cb 100644 --- a/polling-publisher/pom.xml +++ b/polling-publisher/pom.xml @@ -98,7 +98,7 @@ ch.qos.logback logback-classic - 1.5.18 + 1.5.34 diff --git a/pom.xml b/pom.xml index 87aa35d6aa1e..7835110c008e 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ 3.4.5 5.11.4 5.14.2 - 1.5.18 + 1.5.34 2.0.17 diff --git a/rate-limiting-pattern/pom.xml b/rate-limiting-pattern/pom.xml index 2d8d12fdc886..c6529d809d58 100644 --- a/rate-limiting-pattern/pom.xml +++ b/rate-limiting-pattern/pom.xml @@ -43,7 +43,7 @@ ch.qos.logback logback-classic - 1.4.11 + 1.5.34 diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index a22acb7f716f..07aea8423443 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -35,7 +35,7 @@ subclass-sandbox 2.0.17 - 1.5.19 + 1.5.34 From 39dce8eedf3ffe64daea35b8d2b52307f8530d53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 19:02:44 +0300 Subject: [PATCH 079/108] build(deps): bump org.springframework.boot:spring-boot-starter-thymeleaf (#3520) Bumps [org.springframework.boot:spring-boot-starter-thymeleaf](https://github.com/spring-projects/spring-boot) from 3.4.4 to 4.0.6. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.4.4...v4.0.6) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-thymeleaf dependency-version: 4.0.6 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> --- page-controller/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/page-controller/pom.xml b/page-controller/pom.xml index c314459e9d14..564f73418ded 100644 --- a/page-controller/pom.xml +++ b/page-controller/pom.xml @@ -56,7 +56,7 @@ org.springframework.boot spring-boot-starter-thymeleaf - 3.4.4 + 4.0.6 org.junit.jupiter From fcdf639b15f09acb163e2f0d7772f13f184b52da Mon Sep 17 00:00:00 2001 From: OrbisAI Security Date: Wed, 10 Jun 2026 21:39:13 +0530 Subject: [PATCH 080/108] fix: remove unsafe exec() in page controller App.java (#3471) * fix: V-002 security vulnerability Automated security fix generated by Orbis Security AI * adding cross-platform support * fixing sonarqube hotspots * fixing the formating for java windows * fix: address PR review comments - Windows title bug, Unix paths, and consistency - Add empty string title arg to cmd /c start to fix paths-with-spaces bug - Revert Unix commands to bare names (open, xdg-open) with NOSONAR since xdg-open location varies by distro; absolute paths broke portability - Apply same ProcessBuilder fix to page-object/src App.java for consistency Co-Authored-By: Claude Sonnet 4.6 * fix: resolve Windows path via SystemRoot env var instead of hardcoding C:\Windows\System32\cmd.exe fails when Windows is installed on a non-C drive. Use System.getenv("SystemRoot") with a C:\Windows fallback to locate cmd.exe portably in both App.java files. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- .../java/com/iluwatar/pageobject/App.java | 25 ++++++++++++++++-- .../java/com/iluwatar/pageobject/App.java | 26 ++++++++++++++++--- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java b/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java index aaf19fb0cee2..feac06124a7e 100644 --- a/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java +++ b/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java @@ -27,6 +27,7 @@ import java.awt.Desktop; import java.io.File; import java.io.IOException; +import java.util.Locale; import lombok.extern.slf4j.Slf4j; /** @@ -77,8 +78,28 @@ public static void main(String[] args) { Desktop.getDesktop().open(applicationFile); } else { - // java Desktop not supported - above unlikely to work for Windows so try instead... - Runtime.getRuntime().exec("cmd.exe start " + applicationFile); + // java Desktop not supported - use ProcessBuilder for cross-platform support + var os = System.getProperty("os.name").toLowerCase(Locale.ROOT); + ProcessBuilder pb; + if (os.contains("win")) { + // Empty string title arg prevents cmd start treating a quoted path as the window title + var systemRoot = System.getenv("SystemRoot"); + if (systemRoot == null) { + systemRoot = "C:\\Windows"; + } + pb = + new ProcessBuilder( + systemRoot + "\\System32\\cmd.exe", + "/c", + "start", + "", + applicationFile.getAbsolutePath()); + } else if (os.contains("mac")) { + pb = new ProcessBuilder("open", applicationFile.getAbsolutePath()); // NOSONAR + } else { + pb = new ProcessBuilder("xdg-open", applicationFile.getAbsolutePath()); // NOSONAR + } + pb.start(); } } catch (IOException ex) { diff --git a/page-object/src/main/java/com/iluwatar/pageobject/App.java b/page-object/src/main/java/com/iluwatar/pageobject/App.java index 214858cdcb53..2b104a583edb 100644 --- a/page-object/src/main/java/com/iluwatar/pageobject/App.java +++ b/page-object/src/main/java/com/iluwatar/pageobject/App.java @@ -27,6 +27,7 @@ import java.awt.Desktop; import java.io.File; import java.io.IOException; +import java.util.Locale; /** * Page Object pattern wraps an UI component with an application specific API allowing you to @@ -75,9 +76,28 @@ public static void main(String[] args) { Desktop.getDesktop().open(applicationFile); } else { - // Java Desktop not supported - above unlikely to work for Windows so try the - // following instead... - new ProcessBuilder("cmd.exe", "/c", "start", "", applicationFile.getAbsolutePath()).start(); + // java Desktop not supported - use ProcessBuilder for cross-platform support + var os = System.getProperty("os.name").toLowerCase(Locale.ROOT); + ProcessBuilder pb; + if (os.contains("win")) { + // Empty string title arg prevents cmd start treating a quoted path as the window title + var systemRoot = System.getenv("SystemRoot"); + if (systemRoot == null) { + systemRoot = "C:\\Windows"; + } + pb = + new ProcessBuilder( + systemRoot + "\\System32\\cmd.exe", + "/c", + "start", + "", + applicationFile.getAbsolutePath()); + } else if (os.contains("mac")) { + pb = new ProcessBuilder("open", applicationFile.getAbsolutePath()); // NOSONAR + } else { + pb = new ProcessBuilder("xdg-open", applicationFile.getAbsolutePath()); // NOSONAR + } + pb.start(); } } catch (IOException ex) { From 448c8b5d21b363ddcea48db6d8cc788a2748e0f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:21:10 +0300 Subject: [PATCH 081/108] build(deps): bump org.slf4j:slf4j-api from 2.0.9 to 2.0.18 (#3525) Bumps org.slf4j:slf4j-api from 2.0.9 to 2.0.18. --- updated-dependencies: - dependency-name: org.slf4j:slf4j-api dependency-version: 2.0.18 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- commander/pom.xml | 2 +- pom.xml | 2 +- rate-limiting-pattern/pom.xml | 2 +- subclass-sandbox/pom.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/commander/pom.xml b/commander/pom.xml index 1dbe2dc89de5..526bb1c42ecc 100644 --- a/commander/pom.xml +++ b/commander/pom.xml @@ -34,7 +34,7 @@ commander - 2.0.17 + 2.0.18 1.5.6 diff --git a/pom.xml b/pom.xml index 7835110c008e..b856945f3b1e 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ 5.11.4 5.14.2 1.5.34 - 2.0.17 + 2.0.18 0.8.13 diff --git a/rate-limiting-pattern/pom.xml b/rate-limiting-pattern/pom.xml index c6529d809d58..517a02094a9b 100644 --- a/rate-limiting-pattern/pom.xml +++ b/rate-limiting-pattern/pom.xml @@ -37,7 +37,7 @@ org.slf4j slf4j-api - 2.0.9 + 2.0.18 diff --git a/subclass-sandbox/pom.xml b/subclass-sandbox/pom.xml index 07aea8423443..1085dddb087b 100644 --- a/subclass-sandbox/pom.xml +++ b/subclass-sandbox/pom.xml @@ -34,7 +34,7 @@ 4.0.0 subclass-sandbox - 2.0.17 + 2.0.18 1.5.34 From f179974422fc3b5580332714b50f43bb97c82510 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:22:08 +0300 Subject: [PATCH 082/108] build(deps-dev): bump de.flapdoodle.embed:de.flapdoodle.embed.mongo (#3528) Bumps [de.flapdoodle.embed:de.flapdoodle.embed.mongo](https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo) from 4.20.0 to 4.33.0. - [Commits](https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo/compare/de.flapdoodle.embed.mongo-4.20.0...de.flapdoodle.embed.mongo-4.33.0) --- updated-dependencies: - dependency-name: de.flapdoodle.embed:de.flapdoodle.embed.mongo dependency-version: 4.33.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hexagonal-architecture/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hexagonal-architecture/pom.xml b/hexagonal-architecture/pom.xml index 1ac50cecfa04..4d0a9fad318f 100644 --- a/hexagonal-architecture/pom.xml +++ b/hexagonal-architecture/pom.xml @@ -54,7 +54,7 @@ de.flapdoodle.embed de.flapdoodle.embed.mongo - 4.20.0 + 4.33.0 test From 74d2dbe0be3a18da946a9f7478638448d89122b4 Mon Sep 17 00:00:00 2001 From: Giuliano Oliveira Date: Sat, 4 Jul 2026 15:26:07 -0300 Subject: [PATCH 083/108] docs: Translation of the README.md file for active-object to pt (#2553) --- localization/pt/active-object/README.md | 127 ++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 localization/pt/active-object/README.md diff --git a/localization/pt/active-object/README.md b/localization/pt/active-object/README.md new file mode 100644 index 000000000000..07828f6fc28a --- /dev/null +++ b/localization/pt/active-object/README.md @@ -0,0 +1,127 @@ +--- +title: Active Object +category: Concurrency +language: pt +tag: + - Performance +--- + + +## Intenção +O padrão de design de objeto ativo separa a execução do método da invocação do método para objetos que residem em seu encadeamento de controle. O objetivo é introduzir simultaneidade, usando invocação de método assíncrono e um agendador para lidar com solicitações. + +## Explicação + +A classe que implementa o padrão de objeto ativo conterá um mecanismo de auto-sincronização sem usar métodos 'sincronizados'. + +Exemplo do mundo real + + +>Os Orcs são conhecidos por sua selvageria e alma indomável. Parece que eles têm seu próprio fio de controle com base no comportamento anterior. + +Para implementar uma criatura que possui seu próprio mecanismo de thread de controle e expor apenas sua API e não a execução em si, podemos usar o padrão Active Object. + + +**Exemplo programático** + +```java +public abstract class ActiveCreature{ + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + thread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + requests.take().run(); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + } + } + ); + thread.start(); + } + + public void eat() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} is eating!",name()); + logger.info("{} has finished eating!",name()); + } + } + ); + } + + public void roam() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} has started to roam the wastelands.",name()); + } + } + ); + } + + public String name() { + return this.name; + } +} +``` + +Podemos ver que qualquer classe que estenderá a classe ActiveCreature terá seu próprio thread de controle para invocar e executar métodos. + +Por exemplo, a classe Orc: +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } + +} +``` + +Agora, podemos criar várias criaturas, como Orcs, dizer-lhes para comer e vagar, e eles o executarão em seu próprio fio de controle: + +```java + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + ActiveCreature creature; + try { + for (int i = 0;i < creatures;i++) { + creature = new Orc(Orc.class.getSimpleName().toString() + i); + creature.eat(); + creature.roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + Runtime.getRuntime().exit(1); + } +``` + +## Diagrama de classes + +![alt text](./etc/active-object.urm.png "Active Object class diagram") + +## Tutoriais + +* [Android and Java Concurrency: The Active Object Pattern](https://www.youtube.com/watch?v=Cd8t2u5Qmvc) \ No newline at end of file From b55fc2bcb5f8e1c4b884bca0a38d402d19fe467c Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:26:44 +0300 Subject: [PATCH 084/108] docs: add SrGiuliano77 as a contributor for translation (#3537) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 465668e5b29c..94c3cb43c478 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3719,6 +3719,15 @@ "contributions": [ "translation" ] + }, + { + "login": "SrGiuliano77", + "name": "Giuliano Oliveira", + "avatar_url": "https://avatars.githubusercontent.com/u/128543464?v=4", + "profile": "https://github.com/SrGiuliano77", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index b68b9c2338ab..9109b48ae93e 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-408-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-409-orange.svg?style=flat-square)](#contributors-)
@@ -605,6 +605,9 @@ This project is licensed under the terms of the MIT license. 김정모
김정모

💻 Anakin Yen
Anakin Yen

🌍 + + Giuliano Oliveira
Giuliano Oliveira

🌍 + From 688095a4c7c1831631d23a1136ec26a477bf410c Mon Sep 17 00:00:00 2001 From: Hattori Henzo Date: Sun, 16 Aug 2026 13:30:42 -0400 Subject: [PATCH 085/108] 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 086/108] 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 087/108] 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 088/108] 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 089/108] 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 090/108] 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 091/108] 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 092/108] 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 093/108] 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 094/108] 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 095/108] 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 096/108] 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 097/108] 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 098/108] 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 099/108] 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 100/108] 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 101/108] 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 From 4f28d4eb5b2aaac3e66b4989e68c0e6f42782356 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 07:30:43 +0300 Subject: [PATCH 102/108] build(deps): bump io.zipkin.reporter2:zipkin-reporter-brave (#3579) Bumps [io.zipkin.reporter2:zipkin-reporter-brave](https://github.com/openzipkin/zipkin-reporter-java) from 3.5.0 to 3.5.3. - [Release notes](https://github.com/openzipkin/zipkin-reporter-java/releases) - [Changelog](https://github.com/openzipkin/zipkin-reporter-java/blob/master/RELEASE.md) - [Commits](https://github.com/openzipkin/zipkin-reporter-java/compare/3.5.0...3.5.3) --- updated-dependencies: - dependency-name: io.zipkin.reporter2:zipkin-reporter-brave dependency-version: 3.5.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- microservices-distributed-tracing/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/microservices-distributed-tracing/pom.xml b/microservices-distributed-tracing/pom.xml index c7dddf0fa0b6..fa9e288879f1 100644 --- a/microservices-distributed-tracing/pom.xml +++ b/microservices-distributed-tracing/pom.xml @@ -52,7 +52,7 @@ io.zipkin.reporter2 zipkin-reporter-brave - 3.5.0 + 3.5.3 org.junit.jupiter From 5698dea49b11216c180725cb07c787a62dcdcb2f Mon Sep 17 00:00:00 2001 From: Sandhya <128058717+SandhyaDevadiga@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:09:07 +0530 Subject: [PATCH 103/108] feat: Add Fork/Join design pattern (#3227) (#3550) * Add fork-join pattern implementation * Add input validation for start > end in SumTask Signed-off-by: SandhyaDevadiga * Add fork-join module to parent pom.xml * Add missing assertThrows import in SumTaskTest * Format fork-join code with Spotless * Add AppTest to satisfy coverage requirements Signed-off-by: SandhyaDevadiga --------- Signed-off-by: SandhyaDevadiga --- fork-join/README.md | 161 ++++++++++++++++++ fork-join/pom.xml | 50 ++++++ .../main/java/com/iluwatar/forkjoin/App.java | 43 +++++ .../forkjoin/ForkJoinSumCalculator.java | 44 +++++ .../java/com/iluwatar/forkjoin/SumTask.java | 93 ++++++++++ .../java/com/iluwatar/forkjoin/AppTest.java | 11 ++ .../forkjoin/ForkJoinSumCalculatorTest.java | 56 ++++++ .../com/iluwatar/forkjoin/SumTaskTest.java | 85 +++++++++ pom.xml | 1 + 9 files changed, 544 insertions(+) create mode 100644 fork-join/README.md create mode 100644 fork-join/pom.xml create mode 100644 fork-join/src/main/java/com/iluwatar/forkjoin/App.java create mode 100644 fork-join/src/main/java/com/iluwatar/forkjoin/ForkJoinSumCalculator.java create mode 100644 fork-join/src/main/java/com/iluwatar/forkjoin/SumTask.java create mode 100644 fork-join/src/test/java/com/iluwatar/forkjoin/AppTest.java create mode 100644 fork-join/src/test/java/com/iluwatar/forkjoin/ForkJoinSumCalculatorTest.java create mode 100644 fork-join/src/test/java/com/iluwatar/forkjoin/SumTaskTest.java diff --git a/fork-join/README.md b/fork-join/README.md new file mode 100644 index 000000000000..b94af1de02ac --- /dev/null +++ b/fork-join/README.md @@ -0,0 +1,161 @@ +--- +title: "Fork/Join Pattern in Java: Parallel Divide-and-Conquer Processing" +shortTitle: Fork/Join +description: "Learn the Fork/Join design pattern in Java with real-world examples, class diagrams, and code samples. Understand how to split large tasks into parallel subtasks for improved performance." +category: Concurrency +language: en +tag: + - Performance + - Scalability + - Concurrency +--- + +## Also known as + +* Divide and Conquer Parallelism +* Work-Stealing Parallelism + +## Intent of Fork/Join Design Pattern + +The Fork/Join pattern recursively splits a large task into independent subtasks (fork), +processes them in parallel across multiple threads, and combines their results (join) to +produce a final outcome. It maximizes CPU utilization for computationally intensive problems. + +## Detailed Explanation of Fork/Join Pattern with Real-World Examples + +Real-world example + +> Imagine a large warehouse that needs to count all its inventory items across 100 aisles. +> Instead of one person counting every aisle sequentially, the manager divides the warehouse +> into sections and assigns a team of workers to count each section simultaneously. Once +> every section is counted, the manager collects all partial counts and sums them into the +> total inventory. This is the Fork/Join pattern: split the work, do it in parallel, merge +> the results. + +In plain words + +> Fork/Join splits a big problem into smaller pieces, solves each piece in parallel on +> separate threads, then combines all results back together. + +## Programmatic Example of Fork/Join Pattern in Java + +We demonstrate the pattern by computing the sum of a large array in parallel using Java's +built-in `ForkJoinPool` and `RecursiveTask`. + +The `SumTask` is a recursive task that splits the array when it's too large: + +```java +public class SumTask extends RecursiveTask { + + private static final int THRESHOLD = 1000; + private final long[] numbers; + private final int start; + private final int end; + + @Override + protected Long compute() { + int length = end - start; + + if (length <= THRESHOLD) { + // Base case: sum directly + long sum = 0; + for (int i = start; i < end; i++) { + sum += numbers[i]; + } + return sum; + } + + // Fork: split into two halves + int mid = start + length / 2; + SumTask leftTask = new SumTask(numbers, start, mid); + SumTask rightTask = new SumTask(numbers, mid, end); + + leftTask.fork(); // run left half asynchronously + long rightResult = rightTask.compute(); // compute right half here + long leftResult = leftTask.join(); // wait for left half + + // Join: combine results + return leftResult + rightResult; + } +} +``` + +The `ForkJoinSumCalculator` provides a clean API: + +```java +public class ForkJoinSumCalculator { + + private final ForkJoinPool pool; + + public ForkJoinSumCalculator() { + this.pool = ForkJoinPool.commonPool(); + } + + public long calculateSum(long[] numbers) { + SumTask task = new SumTask(numbers, 0, numbers.length); + return pool.invoke(task); + } +} +``` + +Running the example in `App`: + +```java +long[] numbers = LongStream.rangeClosed(1, 10_000_000).toArray(); +ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); +long result = calculator.calculateSum(numbers); +System.out.println("Fork/Join sum: " + result); +``` + +Program output: + +``` +Fork/Join sum: 50000005000000 +Expected sum: 50000005000000 +Correct: true +Time taken: 45 ms +Available processors: 8 +``` + +## When to Use the Fork/Join Pattern in Java + +* When you have a large, CPU-intensive task that can be divided into independent subtasks. +* When the subtasks are roughly the same size and don't depend on each other. +* When you want to utilize multiple CPU cores without manually managing threads. +* When the problem naturally fits a divide-and-conquer strategy (e.g., sorting, searching, + numerical computation). + +## When NOT to Use Fork/Join + +* For I/O-bound tasks (network calls, file reads) — use virtual threads or async I/O instead. +* When subtasks are too small — the overhead of forking exceeds the benefit. +* When tasks have dependencies on each other and cannot run independently. + +## Benefits and Trade-offs of Fork/Join Pattern + +Benefits: + +* Maximizes CPU utilization through work-stealing algorithm. +* Scales automatically with the number of available processors. +* Built into Java's standard library (`java.util.concurrent`) — no external dependencies. +* Clean recursive decomposition makes the code readable and maintainable. + +Trade-offs: + +* Overhead from task creation and thread management for very small problems. +* Requires tasks to be independent — shared mutable state introduces bugs. +* Choosing an appropriate threshold requires tuning for optimal performance. +* Debugging parallel code is inherently harder than sequential code. + +## Related Java Design Patterns + +* [Divide and Conquer](https://java-design-patterns.com/patterns/divide-and-conquer/): + Fork/Join is the parallel execution variant of the classic divide-and-conquer strategy. +* [Thread Pool](https://java-design-patterns.com/patterns/thread-pool/): Fork/Join uses a + specialized pool with work-stealing semantics. + +## References + +* [Java Documentation for ForkJoinPool](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ForkJoinPool.html) +* [Java Concurrency in Practice — Brian Goetz](https://amzn.to/4aRMruW) +* [Java Documentation for RecursiveTask](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/RecursiveTask.html) diff --git a/fork-join/pom.xml b/fork-join/pom.xml new file mode 100644 index 000000000000..23958727728a --- /dev/null +++ b/fork-join/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + fork-join + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.forkjoin.App + + + + + + + + + + diff --git a/fork-join/src/main/java/com/iluwatar/forkjoin/App.java b/fork-join/src/main/java/com/iluwatar/forkjoin/App.java new file mode 100644 index 000000000000..a53bdcec6de7 --- /dev/null +++ b/fork-join/src/main/java/com/iluwatar/forkjoin/App.java @@ -0,0 +1,43 @@ +package com.iluwatar.forkjoin; + +import java.util.stream.LongStream; + +/** + * The Fork/Join pattern is a concurrency design pattern that splits a large task into smaller + * subtasks (fork), processes them in parallel, and then combines the results (join). + * + *

In Java, this pattern is implemented using {@link java.util.concurrent.ForkJoinPool} and + * {@link java.util.concurrent.RecursiveTask}. Worker threads in the pool use a work-stealing + * algorithm — idle threads take tasks from busy threads — maximizing CPU utilization. + * + *

In this example, we demonstrate the pattern by computing the sum of a large array in parallel. + * The array is recursively split in half until each piece is small enough to sum directly, then + * results are combined back up. + */ +public final class App { + + private App() {} + + /** + * @param args command line arguments, not used + */ + public static void main(String[] args) { + // Create an array of 10 million numbers: [1, 2, 3, ..., 10_000_000] + long[] numbers = LongStream.rangeClosed(1, 10_000_000).toArray(); + + // Calculate sum using Fork/Join + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); + long startTime = System.currentTimeMillis(); + long result = calculator.calculateSum(numbers); + long endTime = System.currentTimeMillis(); + + // The expected sum of 1 to N is N*(N+1)/2 + long expected = 10_000_000L * 10_000_001L / 2; + + System.out.println("Fork/Join sum: " + result); + System.out.println("Expected sum: " + expected); + System.out.println("Correct: " + (result == expected)); + System.out.println("Time taken: " + (endTime - startTime) + " ms"); + System.out.println("Available processors: " + Runtime.getRuntime().availableProcessors()); + } +} diff --git a/fork-join/src/main/java/com/iluwatar/forkjoin/ForkJoinSumCalculator.java b/fork-join/src/main/java/com/iluwatar/forkjoin/ForkJoinSumCalculator.java new file mode 100644 index 000000000000..0e9dff32cda8 --- /dev/null +++ b/fork-join/src/main/java/com/iluwatar/forkjoin/ForkJoinSumCalculator.java @@ -0,0 +1,44 @@ +package com.iluwatar.forkjoin; + +import java.util.concurrent.ForkJoinPool; + +/** + * ForkJoinSumCalculator provides a convenient API to sum an array of numbers using the Fork/Join + * framework. It creates a {@link ForkJoinPool}, submits a {@link SumTask}, and returns the computed + * sum. + * + *

The pool manages a set of worker threads that process subtasks in parallel. Idle threads can + * "steal" work from busy threads, maximizing CPU utilization. + */ +public class ForkJoinSumCalculator { + + private final ForkJoinPool pool; + + /** Creates a calculator using the common ForkJoinPool (uses all available CPU cores). */ + public ForkJoinSumCalculator() { + this.pool = ForkJoinPool.commonPool(); + } + + /** + * Creates a calculator with a specific number of threads. + * + * @param parallelism the number of worker threads to use + */ + public ForkJoinSumCalculator(int parallelism) { + this.pool = new ForkJoinPool(parallelism); + } + + /** + * Calculates the sum of all elements in the array using Fork/Join parallelism. + * + * @param numbers the array of numbers to sum + * @return the total sum of all elements + */ + public long calculateSum(long[] numbers) { + if (numbers == null || numbers.length == 0) { + return 0; + } + SumTask task = new SumTask(numbers, 0, numbers.length); + return pool.invoke(task); + } +} diff --git a/fork-join/src/main/java/com/iluwatar/forkjoin/SumTask.java b/fork-join/src/main/java/com/iluwatar/forkjoin/SumTask.java new file mode 100644 index 000000000000..acbd5f0516b7 --- /dev/null +++ b/fork-join/src/main/java/com/iluwatar/forkjoin/SumTask.java @@ -0,0 +1,93 @@ +package com.iluwatar.forkjoin; + +import java.util.concurrent.RecursiveTask; + +/** + * SumTask demonstrates the Fork/Join pattern by recursively splitting an array summation problem + * into smaller subtasks until each subtask is small enough to compute directly. + * + *

How it works: If the portion of the array is smaller than THRESHOLD, sum it in a simple loop. + * Otherwise, split the array in half, fork one half to run in parallel, compute the other half in + * the current thread, and then join the results. This approach utilizes multiple CPU cores to + * perform the summation significantly faster than a single-threaded loop for large arrays. + */ +public class SumTask extends RecursiveTask { + + /** + * If the number of elements to process is at or below this threshold, the task computes the sum + * directly instead of splitting further. + */ + private static final int THRESHOLD = 1000; + + private final long[] numbers; + private final int start; + private final int end; + + /** + * Creates a task to sum elements of the given array from index {@code start} (inclusive) to index + * {@code end} (exclusive). + * + * @param numbers the array of numbers to sum + * @param start the starting index (inclusive) + * @param end the ending index (exclusive) + */ + public SumTask(long[] numbers, int start, int end) { + if (start > end) { + throw new IllegalArgumentException( + "start (" + start + ") must not be greater than end (" + end + ")"); + } + this.numbers = numbers; + this.start = start; + this.end = end; + } + + /** + * The main computation method. This is where the fork/join magic happens. + * + * @return the sum of elements from start to end + */ + @Override + protected Long compute() { + int length = end - start; + + // BASE CASE: if the chunk is small enough, just sum directly + if (length <= THRESHOLD) { + return computeDirectly(); + } + + // FORK: split the task into two halves + int mid = start + length / 2; + + // Create subtask for the left half + SumTask leftTask = new SumTask(numbers, start, mid); + + // Create subtask for the right half + SumTask rightTask = new SumTask(numbers, mid, end); + + // Fork the left task — it will run in a separate thread + leftTask.fork(); + + // Compute the right task in the current thread (no need to fork both) + long rightResult = rightTask.compute(); + + // JOIN: wait for the left task to finish and get its result + long leftResult = leftTask.join(); + + // Combine the results from both halves + return leftResult + rightResult; + } + + /** + * Computes the sum directly using a simple loop. This is used when the chunk size is at or below + * the threshold — no further splitting needed. + * + * @return the sum of elements in the range [start, end) + */ + private long computeDirectly() { + long sum = 0; + for (int i = start; i < end; i++) { + sum += numbers[i]; + } + return sum; + } +} diff --git a/fork-join/src/test/java/com/iluwatar/forkjoin/AppTest.java b/fork-join/src/test/java/com/iluwatar/forkjoin/AppTest.java new file mode 100644 index 000000000000..c66f8610cc55 --- /dev/null +++ b/fork-join/src/test/java/com/iluwatar/forkjoin/AppTest.java @@ -0,0 +1,11 @@ +package com.iluwatar.forkjoin; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void shouldExecuteWithoutException() { + App.main(new String[] {}); + } +} diff --git a/fork-join/src/test/java/com/iluwatar/forkjoin/ForkJoinSumCalculatorTest.java b/fork-join/src/test/java/com/iluwatar/forkjoin/ForkJoinSumCalculatorTest.java new file mode 100644 index 000000000000..6af56dfc38e1 --- /dev/null +++ b/fork-join/src/test/java/com/iluwatar/forkjoin/ForkJoinSumCalculatorTest.java @@ -0,0 +1,56 @@ +package com.iluwatar.forkjoin; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.LongStream; +import org.junit.jupiter.api.Test; + +class ForkJoinSumCalculatorTest { + + @Test + void shouldReturnZeroForNullArray() { + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); + + assertEquals(0L, calculator.calculateSum(null)); + } + + @Test + void shouldReturnZeroForEmptyArray() { + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); + + assertEquals(0L, calculator.calculateSum(new long[0])); + } + + @Test + void shouldCalculateSumOfSmallArray() { + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); + long[] numbers = {10, 20, 30, 40, 50}; + + long result = calculator.calculateSum(numbers); + + assertEquals(150L, result); + } + + @Test + void shouldCalculateSumOfLargeArray() { + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(); + long[] numbers = LongStream.rangeClosed(1, 100_000).toArray(); + + long result = calculator.calculateSum(numbers); + + long expected = 100_000L * 100_001L / 2; + assertEquals(expected, result); + } + + @Test + void shouldWorkWithCustomParallelism() { + // Use only 2 threads + ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(2); + long[] numbers = LongStream.rangeClosed(1, 50_000).toArray(); + + long result = calculator.calculateSum(numbers); + + long expected = 50_000L * 50_001L / 2; + assertEquals(expected, result); + } +} diff --git a/fork-join/src/test/java/com/iluwatar/forkjoin/SumTaskTest.java b/fork-join/src/test/java/com/iluwatar/forkjoin/SumTaskTest.java new file mode 100644 index 000000000000..03df6a6bc268 --- /dev/null +++ b/fork-join/src/test/java/com/iluwatar/forkjoin/SumTaskTest.java @@ -0,0 +1,85 @@ +package com.iluwatar.forkjoin; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.concurrent.ForkJoinPool; +import java.util.stream.LongStream; +import org.junit.jupiter.api.Test; + +class SumTaskTest { + + @Test + void shouldSumSmallArrayDirectly() { + // Array smaller than threshold — should compute without forking + long[] numbers = {1, 2, 3, 4, 5}; + SumTask task = new SumTask(numbers, 0, numbers.length); + + long result = ForkJoinPool.commonPool().invoke(task); + + assertEquals(15L, result); + } + + @Test + void shouldSumLargeArrayUsingForkJoin() { + // Array larger than threshold — will fork into subtasks + long[] numbers = LongStream.rangeClosed(1, 10_000).toArray(); + SumTask task = new SumTask(numbers, 0, numbers.length); + + long result = ForkJoinPool.commonPool().invoke(task); + + // Sum of 1 to N = N*(N+1)/2 + long expected = 10_000L * 10_001L / 2; + assertEquals(expected, result); + } + + @Test + void shouldSumPartialRange() { + // Sum only a portion of the array (indices 2 to 5) + long[] numbers = {10, 20, 30, 40, 50, 60}; + SumTask task = new SumTask(numbers, 2, 5); + + long result = ForkJoinPool.commonPool().invoke(task); + + // 30 + 40 + 50 = 120 + assertEquals(120L, result); + } + + @Test + void shouldReturnZeroForEmptyRange() { + long[] numbers = {1, 2, 3}; + SumTask task = new SumTask(numbers, 1, 1); // start == end, empty range + + long result = ForkJoinPool.commonPool().invoke(task); + + assertEquals(0L, result); + } + + @Test + void shouldHandleSingleElement() { + long[] numbers = {42}; + SumTask task = new SumTask(numbers, 0, 1); + + long result = ForkJoinPool.commonPool().invoke(task); + + assertEquals(42L, result); + } + + @Test + void shouldProduceCorrectResultForMillionElements() { + long[] numbers = LongStream.rangeClosed(1, 1_000_000).toArray(); + SumTask task = new SumTask(numbers, 0, numbers.length); + + long result = ForkJoinPool.commonPool().invoke(task); + + long expected = 1_000_000L * 1_000_001L / 2; + assertEquals(expected, result); + } + + @Test + void shouldThrowExceptionWhenStartGreaterThanEnd() { + long[] numbers = {1, 2, 3, 4, 5}; + + assertThrows(IllegalArgumentException.class, () -> new SumTask(numbers, 4, 2)); + } +} diff --git a/pom.xml b/pom.xml index 46cec4ee61c4..9a4ba4de8ca2 100644 --- a/pom.xml +++ b/pom.xml @@ -139,6 +139,7 @@ fluent-interface flux flyweight + fork-join front-controller function-composition game-loop From aa11f6b6be465fc29bda4334678d2168ff01400e Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 07:39:42 +0300 Subject: [PATCH 104/108] docs: add SandhyaDevadiga as a contributor for code (#3585) * 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 | 5 ++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index df0e170f068f..83b0ddaf8072 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3773,6 +3773,15 @@ "contributions": [ "code" ] + }, + { + "login": "SandhyaDevadiga", + "name": "Sandhya", + "avatar_url": "https://avatars.githubusercontent.com/u/128058717?v=4", + "profile": "https://github.com/SandhyaDevadiga", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index f0e461c0fb76..c5c284f6b29f 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-414-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-415-orange.svg?style=flat-square)](#contributors-)
@@ -613,6 +613,9 @@ This project is licensed under the terms of the MIT license. Anvesh Srivastava
Anvesh Srivastava

💻 Mukul Howale
Mukul Howale

💻 + + Sandhya
Sandhya

💻 + From b0c34db084dc3309087d10e77775662528bfcbc7 Mon Sep 17 00:00:00 2001 From: dev-ikae <98100047+devikae@users.noreply.github.com> Date: Tue, 25 Aug 2026 13:47:35 +0900 Subject: [PATCH 105/108] feat: Implement Write-Ahead Log (WAL) pattern (#3576) (#3582) * feat: Implement Write-Ahead Log (WAL) pattern (#3576) * test: Add exception handling tests and verify coverage --- pom.xml | 1 + write-ahead-log/README.md | 217 ++++++++++++++++++ write-ahead-log/pom.xml | 87 +++++++ .../java/com/iluwatar/writeaheadlog/App.java | 82 +++++++ .../iluwatar/writeaheadlog/DatabaseStore.java | 131 +++++++++++ .../com/iluwatar/writeaheadlog/LogEntry.java | 83 +++++++ .../iluwatar/writeaheadlog/OperationType.java | 33 +++ .../iluwatar/writeaheadlog/WriteAheadLog.java | 134 +++++++++++ .../com/iluwatar/writeaheadlog/AppTest.java | 38 +++ .../writeaheadlog/DatabaseStoreTest.java | 96 ++++++++ .../iluwatar/writeaheadlog/LogEntryTest.java | 80 +++++++ .../writeaheadlog/WriteAheadLogTest.java | 134 +++++++++++ 12 files changed, 1116 insertions(+) create mode 100644 write-ahead-log/README.md create mode 100644 write-ahead-log/pom.xml create mode 100644 write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/App.java create mode 100644 write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/DatabaseStore.java create mode 100644 write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/LogEntry.java create mode 100644 write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/OperationType.java create mode 100644 write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/WriteAheadLog.java create mode 100644 write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/AppTest.java create mode 100644 write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/DatabaseStoreTest.java create mode 100644 write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/LogEntryTest.java create mode 100644 write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/WriteAheadLogTest.java diff --git a/pom.xml b/pom.xml index 9a4ba4de8ca2..4ed64e643219 100644 --- a/pom.xml +++ b/pom.xml @@ -253,6 +253,7 @@ view-helper virtual-proxy visitor + write-ahead-log backpressure actor-model rate-limiting-pattern diff --git a/write-ahead-log/README.md b/write-ahead-log/README.md new file mode 100644 index 000000000000..45caab13cadf --- /dev/null +++ b/write-ahead-log/README.md @@ -0,0 +1,217 @@ +--- +title: "Write-Ahead Log (WAL) Pattern in Java: Ensuring Data Durability and Crash Recovery" +shortTitle: Write-Ahead Log +description: "Learn about the Write-Ahead Log (WAL) design pattern in Java. Discover how append-only logging guarantees data durability and fast crash recovery in database engines and distributed systems." +category: Data Access +language: en +tag: + - Data access + - Storage + - Fault tolerance + - Transactions + - Performance +--- + +## Also known as + +* Append-Only Log +* Redo Log +* Journaling + +## Intent of Write-Ahead Log Pattern + +The Write-Ahead Log (WAL) design pattern ensures data durability and system recoverability in database engines, distributed consensus protocols, and transactional systems. It enforces a strict order of operations where any state mutation (e.g., insert, update, delete) must be written sequentially to an append-only log file on stable storage (disk) before it is applied to the main database state or in-memory storage structures. + +## Detailed Explanation of Write-Ahead Log Pattern with Real-World Examples + +Real-world example + +> Imagine an accountant managing a company's ledger. Before modifying the main financial summary balance sheets, the accountant immediately records every incoming transaction line-by-line into a sequential physical logbook. If power cuts out mid-day or the summary balance sheets are damaged, the accountant can re-open the physical logbook, replay every recorded entry from the beginning, and perfectly recalculate the final financial state. + +In plain words + +> Write-Ahead Log guarantees that no state mutation is lost during sudden system crashes by writing changes to a fast append-only disk log file before updating the in-memory store. + +Wikipedia says + +> In computer science, write-ahead logging (WAL) is a family of techniques for providing atomicity and durability (two of the ACID properties) in database systems. In a system using WAL, all modifications are written to a log before they are applied. Usually both redo and undo information are stored in the log. + +Class Diagram + +```mermaid +classDiagram + class OperationType { + <> + SET + DELETE + CHECKPOINT + } + + class LogEntry { + -long sequenceNumber + -OperationType type + -String key + -String value + +toLogString() String + +fromLogString(String line)$ LogEntry + } + + class WriteAheadLog { + -File logFile + -AtomicLong sequenceNumberCounter + +append(OperationType type, String key, String value) LogEntry + +readAll() List~LogEntry~ + +clear() void + } + + class DatabaseStore { + -WriteAheadLog wal + -Map~String, String~ memTable + +put(String key, String value) void + +delete(String key) void + +get(String key) String + +checkpoint() void + +simulateCrash() void + +recover() void + } + + DatabaseStore --> WriteAheadLog + WriteAheadLog --> LogEntry + LogEntry --> OperationType +``` + +## Programmatic Example of Write-Ahead Log Pattern in Java + +The `WriteAheadLog` class manages append-only sequential writes to disk: + +```java +public class WriteAheadLog { + private final File logFile; + private final AtomicLong sequenceNumberCounter = new AtomicLong(0); + + public synchronized LogEntry append(OperationType type, String key, String value) throws IOException { + long nextSeq = sequenceNumberCounter.incrementAndGet(); + LogEntry entry = new LogEntry(nextSeq, type, key, value); + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true))) { + writer.write(entry.toLogString()); + writer.newLine(); + writer.flush(); + } + return entry; + } +} +``` + +The `DatabaseStore` class coordinates writing to the log before modifying its in-memory `MemTable`: + +```java +public class DatabaseStore { + private final WriteAheadLog wal; + private final Map memTable = new HashMap<>(); + + public synchronized void put(String key, String value) throws IOException { + wal.append(OperationType.SET, key, value); + memTable.put(key, value); + } + + public synchronized void delete(String key) throws IOException { + wal.append(OperationType.DELETE, key, null); + memTable.remove(key); + } + + public synchronized void recover() { + memTable.clear(); + List entries = wal.readAll(); + for (LogEntry entry : entries) { + if (entry.getType() == OperationType.SET) { + memTable.put(entry.getKey(), entry.getValue()); + } else if (entry.getType() == OperationType.DELETE) { + memTable.remove(entry.getKey()); + } + } + } +} +``` + +The `App` class demonstrates initialization, writes, crash simulation, and WAL recovery: + +```java +@Slf4j +public class App { + public static void main(String[] args) { + try { + File logFile = File.createTempFile("wal_demo", ".log"); + WriteAheadLog wal = new WriteAheadLog(logFile); + DatabaseStore store = new DatabaseStore(wal); + + store.put("user:101", "Alice"); + store.put("user:102", "Bob"); + store.delete("user:103"); + + // Simulating system crash where in-memory state is lost + store.simulateCrash(); + + // System reboot & recovery from WAL log replay + store.recover(); + + LOGGER.info("MemTable post recovery: {}", store.getMemTableSnapshot()); + } catch (IOException e) { + LOGGER.error("Error running WAL demo", e); + } + } +} +``` + +Program output: + +```text +15:45:00.100 [main] INFO com.iluwatar.writeaheadlog.App -- === 1. Initializing Storage Engine with WAL === +15:45:00.105 [main] INFO com.iluwatar.writeaheadlog.WriteAheadLog -- WAL Entry appended & flushed to disk: LogEntry(sequenceNumber=1, type=SET, key=user:101, value=Alice) +15:45:00.106 [main] INFO com.iluwatar.writeaheadlog.DatabaseStore -- Applied SET operation to MemTable: user:101 = Alice +15:45:00.107 [main] INFO com.iluwatar.writeaheadlog.App -- === 3. Simulating Unexpected System Crash === +15:45:00.108 [main] INFO com.iluwatar.writeaheadlog.DatabaseStore -- !!! SIMULATED SYSTEM CRASH: In-memory MemTable has been wiped !!! +15:45:00.109 [main] INFO com.iluwatar.writeaheadlog.App -- === 4. System Restart & Recovery from WAL === +15:45:00.110 [main] INFO com.iluwatar.writeaheadlog.DatabaseStore -- Starting recovery process from WAL... +15:45:00.112 [main] INFO com.iluwatar.writeaheadlog.DatabaseStore -- Recovery completed. Replayed 5 log entries into MemTable. +15:45:00.113 [main] INFO com.iluwatar.writeaheadlog.App -- MemTable snapshot post recovery: {user:101=Alice, user:102=Bob Smith} +``` + +## When to Use the Write-Ahead Log Pattern in Java + +* Building storage engines or key-value data stores requiring ACID durability guarantees. +* Implementing fault-tolerant distributed consensus protocols (e.g., Raft, Paxos). +* System architectures where random disk I/O is expensive, allowing sequential append-only writes for maximum throughput. +* Message brokers or event streams requiring replayability after failure. + +## Real-World Applications of Write-Ahead Log Pattern in Java + +* **PostgreSQL / MySQL (InnoDB):** Uses WAL / Redo Log for crash recovery and replication. +* **SQLite:** Write-Ahead Logging mode for concurrency and atomic commits. +* **Apache Cassandra / RocksDB:** Appends mutations to CommitLog / WAL before MemTable updates. +* **Apache Kafka / Raft:** Log replication across distributed nodes for consensus and state machine replication. + +## Benefits and Trade-offs of Write-Ahead Log Pattern + +Benefits: + +* **High Performance:** Sequential disk writes are significantly faster than random disk updates (e.g., updating B-Trees directly). +* **Durability & Fault Tolerance:** Guarantees no committed transaction is lost during sudden system crashes. +* **Simplicity of Recovery:** Replaying ordered log records deterministically restores the exact last-known state. + +Trade-offs: + +* **Storage Overhead:** Log files grow over time, requiring periodic checkpointing and log truncation. +* **Recovery Time:** Large log files without checkpoints can lead to slow startup/recovery times. + +## Related Java Design Patterns + +* [Event Sourcing](https://java-design-patterns.com/patterns/event-sourcing/): Captures state mutations as a sequence of events, similar to log replay. +* [Command](https://java-design-patterns.com/patterns/command/): Encapsulates requests as objects, which can be serialized into WAL entries. +* [Memento](https://java-design-patterns.com/patterns/memento/): Stores state snapshots (checkpoints) to truncate logs. + +## References and Credits + +* [Designing Data-Intensive Applications (Martin Kleppmann)](https://www.oreilly.com/library/view/designing-data-intensive-applications/9781491903063/) +* [PostgreSQL Documentation: Write-Ahead Logging (WAL)](https://www.postgresql.org/docs/current/wal-intro.html) +* [Raft Consensus Algorithm Paper](https://raft.github.io/) diff --git a/write-ahead-log/pom.xml b/write-ahead-log/pom.xml new file mode 100644 index 000000000000..adb766953a47 --- /dev/null +++ b/write-ahead-log/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + write-ahead-log + 1.26.0-SNAPSHOT + write-ahead-log + http://maven.apache.org + + UTF-8 + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.projectlombok + lombok + ${lombok.version} + provided + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.writeaheadlog.App + + + + + + + + + diff --git a/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/App.java b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/App.java new file mode 100644 index 000000000000..e8e9fae2f763 --- /dev/null +++ b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/App.java @@ -0,0 +1,82 @@ +/* + * 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.writeaheadlog; + +import java.io.File; +import java.io.IOException; +import lombok.extern.slf4j.Slf4j; + +/** + * Main application class demonstrating the Write-Ahead Log (WAL) design pattern. + * + *

The WAL pattern guarantees durability by ensuring every mutation (SET, DELETE) is written to a + * persistent append-only log file on disk BEFORE updating in-memory state. If the system crashes + * unexpectedly, replaying log entries from the WAL file restores state. + */ +@Slf4j +public class App { + + /** + * Application entry point. + * + * @param args command line arguments + */ + public static void main(String[] args) { + try { + File logFile = File.createTempFile("wal_demo", ".log"); + logFile.deleteOnExit(); + + LOGGER.info( + "=== 1. Initializing Storage Engine with WAL at {} ===", logFile.getAbsolutePath()); + WriteAheadLog wal = new WriteAheadLog(logFile); + DatabaseStore store = new DatabaseStore(wal); + + LOGGER.info("=== 2. Performing Data Operations (Write-Ahead Logging) ==="); + store.put("user:101", "Alice"); + store.put("user:102", "Bob"); + store.put("user:103", "Charlie"); + store.put("user:102", "Bob Smith"); + store.delete("user:103"); + store.checkpoint(); + + LOGGER.info("MemTable snapshot before crash: {}", store.getMemTableSnapshot()); + + LOGGER.info("=== 3. Simulating Unexpected System Crash ==="); + store.simulateCrash(); + LOGGER.info("MemTable snapshot after crash: {}", store.getMemTableSnapshot()); + + LOGGER.info("=== 4. System Restart & Recovery from WAL ==="); + store.recover(); + LOGGER.info("MemTable snapshot post recovery: {}", store.getMemTableSnapshot()); + + if (logFile.exists()) { + logFile.delete(); + } + } catch (IOException e) { + LOGGER.error("An error occurred during WAL demonstration: {}", e.getMessage(), e); + } + } +} diff --git a/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/DatabaseStore.java b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/DatabaseStore.java new file mode 100644 index 000000000000..dd6d94fce7aa --- /dev/null +++ b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/DatabaseStore.java @@ -0,0 +1,131 @@ +/* + * 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.writeaheadlog; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * Storage engine demonstrating Write-Ahead Log (WAL) pattern. All mutations are logged and flushed + * to persistent WAL storage before modifying the in-memory MemTable. + */ +@Slf4j +public class DatabaseStore { + + @Getter private final WriteAheadLog wal; + private final Map memTable = new HashMap<>(); + + /** + * Constructs DatabaseStore with the specified WriteAheadLog. + * + * @param wal persistent write-ahead log manager + */ + public DatabaseStore(WriteAheadLog wal) { + this.wal = wal; + } + + /** + * Stores a key-value pair. First writes to WAL on disk, then updates the in-memory MemTable. + * + * @param key target entry key + * @param value target entry value + * @throws IOException if writing to WAL fails + */ + public synchronized void put(String key, String value) throws IOException { + wal.append(OperationType.SET, key, value); + memTable.put(key, value); + LOGGER.info("Applied SET operation to MemTable: {} = {}", key, value); + } + + /** + * Removes a key-value pair. First writes DELETE operation to WAL on disk, then updates the + * in-memory MemTable. + * + * @param key target entry key to delete + * @throws IOException if writing to WAL fails + */ + public synchronized void delete(String key) throws IOException { + wal.append(OperationType.DELETE, key, null); + memTable.remove(key); + LOGGER.info("Applied DELETE operation to MemTable: {}", key); + } + + /** + * Retrieves value associated with key from the in-memory MemTable. + * + * @param key key to lookup + * @return value or null if non-existent + */ + public synchronized String get(String key) { + return memTable.get(key); + } + + /** + * Returns an unmodifiable view of current in-memory MemTable state. + * + * @return unmodifiable map of stored data + */ + public synchronized Map getMemTableSnapshot() { + return Collections.unmodifiableMap(new HashMap<>(memTable)); + } + + /** + * Writes a CHECKPOINT log record. + * + * @throws IOException if writing to WAL fails + */ + public synchronized void checkpoint() throws IOException { + wal.append(OperationType.CHECKPOINT, null, null); + LOGGER.info("Checkpoint written to WAL."); + } + + /** Simulates a system crash or power outage where in-memory state is wiped. */ + public synchronized void simulateCrash() { + memTable.clear(); + LOGGER.info("!!! SIMULATED SYSTEM CRASH: In-memory MemTable has been wiped !!!"); + } + + /** Replays log entries from persistent Write-Ahead Log to fully recover in-memory state. */ + public synchronized void recover() { + LOGGER.info("Starting recovery process from WAL..."); + memTable.clear(); + List entries = wal.readAll(); + + for (LogEntry entry : entries) { + if (entry.getType() == OperationType.SET) { + memTable.put(entry.getKey(), entry.getValue()); + } else if (entry.getType() == OperationType.DELETE) { + memTable.remove(entry.getKey()); + } + } + LOGGER.info("Recovery completed. Replayed {} log entries into MemTable.", entries.size()); + } +} diff --git a/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/LogEntry.java b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/LogEntry.java new file mode 100644 index 000000000000..7ae212c8337c --- /dev/null +++ b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/LogEntry.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.writeaheadlog; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +/** Represents a single record entry in the Write-Ahead Log. */ +@Getter +@AllArgsConstructor +@EqualsAndHashCode +@ToString +public class LogEntry { + + private static final String DELIMITER = "|"; + + private final long sequenceNumber; + private final OperationType type; + private final String key; + private final String value; + + /** + * Serializes the LogEntry to a delimited string format suitable for append-only logging. + * + * @return delimited log line representation + */ + public String toLogString() { + return sequenceNumber + + DELIMITER + + type + + DELIMITER + + (key != null ? key : "") + + DELIMITER + + (value != null ? value : ""); + } + + /** + * Deserializes a delimited string line into a LogEntry instance. + * + * @param line serialized log line + * @return parsed LogEntry + * @throws IllegalArgumentException if the log line format is invalid + */ + public static LogEntry fromLogString(String line) { + if (line == null || line.isBlank()) { + throw new IllegalArgumentException("Log line cannot be null or blank"); + } + String[] parts = line.split("\\|", -1); + if (parts.length < 4) { + throw new IllegalArgumentException("Invalid log line format: " + line); + } + long sequenceNumber = Long.parseLong(parts[0]); + OperationType type = OperationType.valueOf(parts[1]); + String key = parts[2].isEmpty() ? null : parts[2]; + String value = parts[3].isEmpty() ? null : parts[3]; + return new LogEntry(sequenceNumber, type, key, value); + } +} diff --git a/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/OperationType.java b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/OperationType.java new file mode 100644 index 000000000000..33e06111bdc4 --- /dev/null +++ b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/OperationType.java @@ -0,0 +1,33 @@ +/* + * 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.writeaheadlog; + +/** Enumeration representing the type of operations logged in the Write-Ahead Log. */ +public enum OperationType { + SET, + DELETE, + CHECKPOINT +} diff --git a/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/WriteAheadLog.java b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/WriteAheadLog.java new file mode 100644 index 000000000000..4ea2044ff2fc --- /dev/null +++ b/write-ahead-log/src/main/java/com/iluwatar/writeaheadlog/WriteAheadLog.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.writeaheadlog; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/** + * Manages sequential append-only logging to persistent disk storage. Ensures state changes are + * flushed to stable storage before in-memory updates. + */ +@Slf4j +public class WriteAheadLog { + + @Getter private final File logFile; + private final AtomicLong sequenceNumberCounter = new AtomicLong(0); + + /** + * Initializes WriteAheadLog with target log file. If log file exists, calculates the initial + * sequence number from existing entries. + * + * @param logFile file to use for append-only log entries + */ + public WriteAheadLog(File logFile) { + this.logFile = logFile; + initSequenceNumber(); + } + + private void initSequenceNumber() { + if (logFile.exists()) { + List existingEntries = readAll(); + if (!existingEntries.isEmpty()) { + long maxSeq = existingEntries.get(existingEntries.size() - 1).getSequenceNumber(); + sequenceNumberCounter.set(maxSeq); + } + } + } + + /** + * Appends an entry to the log file and flushes to ensure persistence. + * + * @param type operation type (SET, DELETE, CHECKPOINT) + * @param key operation target key + * @param value operation target value + * @return recorded LogEntry + * @throws IOException if writing to persistent storage fails + */ + public synchronized LogEntry append(OperationType type, String key, String value) + throws IOException { + long nextSeq = sequenceNumberCounter.incrementAndGet(); + LogEntry entry = new LogEntry(nextSeq, type, key, value); + + try (BufferedWriter writer = new BufferedWriter(new FileWriter(logFile, true))) { + writer.write(entry.toLogString()); + writer.newLine(); + writer.flush(); + } + LOGGER.info("WAL Entry appended & flushed to disk: {}", entry); + return entry; + } + + /** + * Reads all log entries sequentially from the persistent log file. + * + * @return list of parsed LogEntries in sequential order + */ + public synchronized List readAll() { + List entries = new ArrayList<>(); + if (!logFile.exists()) { + return entries; + } + + try (BufferedReader reader = new BufferedReader(new FileReader(logFile))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.isBlank()) { + entries.add(LogEntry.fromLogString(line)); + } + } + } catch (IOException e) { + LOGGER.error("Failed to read log entries from WAL file: {}", logFile.getAbsolutePath(), e); + } + return entries; + } + + /** + * Clears the log file and resets the sequence number counter. Typically invoked after a + * successful checkpoint. + */ + public synchronized void clear() { + if (logFile.exists()) { + try { + Files.delete(logFile.toPath()); + sequenceNumberCounter.set(0); + LOGGER.info("WAL log cleared successfully."); + } catch (IOException e) { + LOGGER.error("Failed to clear WAL file: {}", logFile.getAbsolutePath(), e); + } + } + } +} diff --git a/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/AppTest.java b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/AppTest.java new file mode 100644 index 000000000000..b3bdbe3360ba --- /dev/null +++ b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/AppTest.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.writeaheadlog; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +class AppTest { + + @Test + void testAppMainExecutesWithoutExceptions() { + assertDoesNotThrow(() -> App.main(new String[0])); + } +} diff --git a/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/DatabaseStoreTest.java b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/DatabaseStoreTest.java new file mode 100644 index 000000000000..08288547348b --- /dev/null +++ b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/DatabaseStoreTest.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.writeaheadlog; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class DatabaseStoreTest { + + private File tempFile; + private WriteAheadLog wal; + private DatabaseStore store; + + @BeforeEach + void setUp() throws IOException { + tempFile = File.createTempFile("db_store_test", ".log"); + wal = new WriteAheadLog(tempFile); + store = new DatabaseStore(wal); + } + + @AfterEach + void tearDown() { + if (tempFile != null && tempFile.exists()) { + tempFile.delete(); + } + } + + @Test + void testPutAndGet() throws IOException { + store.put("key1", "val1"); + assertEquals("val1", store.get("key1")); + } + + @Test + void testDelete() throws IOException { + store.put("key1", "val1"); + assertEquals("val1", store.get("key1")); + + store.delete("key1"); + assertNull(store.get("key1")); + } + + @Test + void testSimulateCrashAndRecovery() throws IOException { + store.put("key1", "val1"); + store.put("key2", "val2"); + store.put("key1", "val1_updated"); + store.delete("key2"); + store.checkpoint(); + + Map beforeCrashSnapshot = store.getMemTableSnapshot(); + assertEquals("val1_updated", beforeCrashSnapshot.get("key1")); + assertNull(beforeCrashSnapshot.get("key2")); + + store.simulateCrash(); + assertNull(store.get("key1")); + assertNull(store.get("key2")); + assertTrue(store.getMemTableSnapshot().isEmpty()); + + store.recover(); + Map recoveredSnapshot = store.getMemTableSnapshot(); + assertEquals("val1_updated", recoveredSnapshot.get("key1")); + assertNull(recoveredSnapshot.get("key2")); + } +} diff --git a/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/LogEntryTest.java b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/LogEntryTest.java new file mode 100644 index 000000000000..ea031e04c8a0 --- /dev/null +++ b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/LogEntryTest.java @@ -0,0 +1,80 @@ +/* + * 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.writeaheadlog; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class LogEntryTest { + + @Test + void testToLogStringAndFromLogString() { + LogEntry entry = new LogEntry(1, OperationType.SET, "key1", "val1"); + String logString = entry.toLogString(); + assertEquals("1|SET|key1|val1", logString); + + LogEntry parsed = LogEntry.fromLogString(logString); + assertEquals(entry, parsed); + assertEquals(1, parsed.getSequenceNumber()); + assertEquals(OperationType.SET, parsed.getType()); + assertEquals("key1", parsed.getKey()); + assertEquals("val1", parsed.getValue()); + } + + @Test + void testDeleteLogEntrySerialization() { + LogEntry entry = new LogEntry(2, OperationType.DELETE, "key2", null); + String logString = entry.toLogString(); + assertEquals("2|DELETE|key2|", logString); + + LogEntry parsed = LogEntry.fromLogString(logString); + assertEquals(entry, parsed); + assertEquals("key2", parsed.getKey()); + assertNull(parsed.getValue()); + } + + @Test + void testInvalidLogStringThrowsException() { + assertThrows(IllegalArgumentException.class, () -> LogEntry.fromLogString(null)); + assertThrows(IllegalArgumentException.class, () -> LogEntry.fromLogString(" ")); + assertThrows(IllegalArgumentException.class, () -> LogEntry.fromLogString("1|SET|key1")); + } + + @Test + void testEqualsAndHashCode() { + LogEntry entry1 = new LogEntry(1, OperationType.SET, "k", "v"); + LogEntry entry2 = new LogEntry(1, OperationType.SET, "k", "v"); + LogEntry entry3 = new LogEntry(2, OperationType.SET, "k", "v"); + + assertEquals(entry1, entry2); + assertEquals(entry1.hashCode(), entry2.hashCode()); + assertNotEquals(entry1, entry3); + } +} diff --git a/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/WriteAheadLogTest.java b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/WriteAheadLogTest.java new file mode 100644 index 000000000000..8f0410414e3c --- /dev/null +++ b/write-ahead-log/src/test/java/com/iluwatar/writeaheadlog/WriteAheadLogTest.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.writeaheadlog; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class WriteAheadLogTest { + + private File tempFile; + private WriteAheadLog wal; + + @BeforeEach + void setUp() throws IOException { + tempFile = File.createTempFile("wal_test", ".log"); + wal = new WriteAheadLog(tempFile); + } + + @AfterEach + void tearDown() { + if (tempFile != null && tempFile.exists()) { + if (tempFile.isDirectory()) { + File[] files = tempFile.listFiles(); + if (files != null) { + for (File f : files) { + f.delete(); + } + } + } + tempFile.delete(); + } + } + + @Test + void testAppendAndReadAll() throws IOException { + LogEntry e1 = wal.append(OperationType.SET, "k1", "v1"); + LogEntry e2 = wal.append(OperationType.SET, "k2", "v2"); + LogEntry e3 = wal.append(OperationType.DELETE, "k1", null); + + assertEquals(1, e1.getSequenceNumber()); + assertEquals(2, e2.getSequenceNumber()); + assertEquals(3, e3.getSequenceNumber()); + + List entries = wal.readAll(); + assertEquals(3, entries.size()); + assertEquals(e1, entries.get(0)); + assertEquals(e2, entries.get(1)); + assertEquals(e3, entries.get(2)); + } + + @Test + void testSequenceNumberResumptionOnReopen() throws IOException { + wal.append(OperationType.SET, "k1", "v1"); + wal.append(OperationType.SET, "k2", "v2"); + + WriteAheadLog reopenedWal = new WriteAheadLog(tempFile); + LogEntry newEntry = reopenedWal.append(OperationType.SET, "k3", "v3"); + + assertEquals(3, newEntry.getSequenceNumber()); + } + + @Test + void testClear() throws IOException { + wal.append(OperationType.SET, "k1", "v1"); + assertTrue(tempFile.exists()); + + wal.clear(); + assertFalse(tempFile.exists()); + + List entries = wal.readAll(); + assertNotNull(entries); + assertTrue(entries.isEmpty()); + } + + @Test + void testReadAllIOExceptionHandling() throws IOException { + File dir = Files.createTempDirectory("wal_dir_test").toFile(); + WriteAheadLog dirWal = new WriteAheadLog(dir); + + List entries = dirWal.readAll(); + assertNotNull(entries); + assertTrue(entries.isEmpty()); + + dir.delete(); + } + + @Test + void testClearIOExceptionHandling() throws IOException { + File dir = Files.createTempDirectory("wal_nonempty_dir_test").toFile(); + File child = new File(dir, "child.txt"); + child.createNewFile(); + + WriteAheadLog dirWal = new WriteAheadLog(dir); + dirWal.clear(); + + assertTrue(dir.exists()); + + child.delete(); + dir.delete(); + } +} From d7327917cfdced69d9c8707815434333c2678ef0 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 07:48:14 +0300 Subject: [PATCH 106/108] docs: add devikae as a contributor for code (#3586) * 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 83b0ddaf8072..1d73d46a4e14 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3782,6 +3782,15 @@ "contributions": [ "code" ] + }, + { + "login": "devikae", + "name": "dev-ikae", + "avatar_url": "https://avatars.githubusercontent.com/u/98100047?v=4", + "profile": "https://github.com/devikae", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index c5c284f6b29f..8db0c3bfb3a2 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-415-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-416-orange.svg?style=flat-square)](#contributors-)
@@ -615,6 +615,7 @@ This project is licensed under the terms of the MIT license. Sandhya
Sandhya

💻 + dev-ikae
dev-ikae

💻 From c8423198cd4b6349c50226dbe9ce7dac9f725dca Mon Sep 17 00:00:00 2001 From: zanarelli Date: Tue, 25 Aug 2026 01:51:26 -0300 Subject: [PATCH 107/108] docs: pt: add localization for polling-publisher, money, delegation patterns (#3583) Add Brazilian Portuguese (pt) translations for three previously untranslated pattern READMEs, following the existing localization/pt/ convention documented in the wiki (15. Support for multiple languages). Frontmatter and section headers follow the same structure used by the most recently updated existing translation (singleton), keeping code blocks, links, and image references unchanged from the English source. --- localization/pt/delegation/README.md | 157 ++++++++++++++++++++ localization/pt/money/README.md | 131 ++++++++++++++++ localization/pt/polling-publisher/README.md | 119 +++++++++++++++ 3 files changed, 407 insertions(+) create mode 100644 localization/pt/delegation/README.md create mode 100644 localization/pt/money/README.md create mode 100644 localization/pt/polling-publisher/README.md diff --git a/localization/pt/delegation/README.md b/localization/pt/delegation/README.md new file mode 100644 index 000000000000..9f424895891d --- /dev/null +++ b/localization/pt/delegation/README.md @@ -0,0 +1,157 @@ +--- +title: "Delegation Pattern in Java: Mastering Efficient Task Assignment" +shortTitle: Delegation +description: "Explore the Delegation Design Pattern in Java with real-world examples, class diagrams, and its benefits. Learn how to enhance your code flexibility and reuse." +category: Behavioral +language: pt +tag: + - Decoupling + - Delegation + - Object composition +--- + +## Também conhecido como + +* Helper +* Surrogate + +## Propósito + +Permitir que um objeto delegue a responsabilidade por uma tarefa a outro objeto auxiliar. + +## Explicação + +Exemplo do mundo real + +> Em um restaurante, o chef principal delega tarefas aos sous-chefs: um cuida das grelhas, outro das saladas e um terceiro é responsável pelas sobremesas. Cada sous-chef é especializado em sua área, permitindo que o chef principal se concentre na gestão geral da cozinha. Isso reflete o padrão Delegation, no qual um objeto principal delega tarefas específicas a objetos auxiliares, cada um especialista em seu domínio. + +Em outras palavras + +> Delegation é um padrão de design em que um objeto repassa uma tarefa a um objeto auxiliar. + +De acordo com a Wikipédia + +> Em programação orientada a objetos, delegação se refere a avaliar um membro (propriedade ou método) de um objeto (o receptor) no contexto de outro objeto original (o remetente). A delegação pode ser feita explicitamente, passando o objeto remetente para o objeto receptor, o que pode ser feito em qualquer linguagem orientada a objetos; ou implicitamente, pelas regras de busca de membros da linguagem, o que exige suporte da linguagem para esse recurso. + +Diagrama de sequência + +![Delegation sequence diagram](../../../delegation/etc/delegation-sequence-diagram.png) + +## Exemplo Programático + +Vamos considerar um exemplo de impressão. + +Temos uma interface `Printer` e três implementações: `CanonPrinter`, `EpsonPrinter` e `HpPrinter`. + +```java +public interface Printer { + void print(final String message); +} + +@Slf4j +public class CanonPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("Canon Printer : {}", message); + } +} + +@Slf4j +public class EpsonPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("Epson Printer : {}", message); + } +} + +@Slf4j +public class HpPrinter implements Printer { + @Override + public void print(String message) { + LOGGER.info("HP Printer : {}", message); + } +} +``` + +O `PrinterController` pode ser usado como um `Printer`, delegando qualquer trabalho tratado por essa interface a um objeto que a implemente. + +```java +public class PrinterController implements Printer { + + private final Printer printer; + + public PrinterController(Printer printer) { + this.printer = printer; + } + + @Override + public void print(String message) { + printer.print(message); + } +} +``` + +No código cliente, os controladores de impressora podem imprimir mensagens de formas diferentes, dependendo do objeto para o qual delegam esse trabalho. + +```java +public class App { + + private static final String MESSAGE_TO_PRINT = "hello world"; + + public static void main(String[] args) { + var hpPrinterController = new PrinterController(new HpPrinter()); + var canonPrinterController = new PrinterController(new CanonPrinter()); + var epsonPrinterController = new PrinterController(new EpsonPrinter()); + + hpPrinterController.print(MESSAGE_TO_PRINT); + canonPrinterController.print(MESSAGE_TO_PRINT); + epsonPrinterController.print(MESSAGE_TO_PRINT); + } +} +``` + +Saída do programa: + +``` +HP Printer:hello world +Canon Printer:hello world +Epson Printer:hello world +``` + +## Quando usar o padrão Delegation + +* Quando você deseja passar a responsabilidade de uma classe para outra sem usar herança. +* Para obter reutilização baseada em composição em vez de herança. +* Quando você precisa usar diversas classes auxiliares intercambiáveis em tempo de execução. + +## Aplicações do mundo real do padrão Delegation + +* O pacote java.awt.event do Java, no qual listeners são frequentemente usados para tratar eventos. +* Classes wrapper do Java Collections Framework (java.util.Collections), que delegam a outros objetos de coleção. +* No Spring Framework, a delegação é usada extensivamente no container IoC, no qual beans delegam tarefas a outros beans. + +## Benefícios e desafios do padrão Delegation + +Benefícios: + +* Reduz a criação de subclasses: os objetos podem delegar operações a objetos diferentes e alterá-los em tempo de execução, reduzindo a necessidade de criar subclasses. +* Incentiva a reutilização: a delegação promove a reutilização do código do objeto auxiliar. +* Aumenta a flexibilidade: ao delegar tarefas a objetos auxiliares, é possível alterar o comportamento das suas classes em tempo de execução. + +Desafios: + +* Sobrecarga em tempo de execução: a delegação pode introduzir camadas adicionais de indireção, o que pode resultar em pequenos custos de desempenho. +* Complexidade: o design pode se tornar mais complicado, pois envolve classes e interfaces adicionais para gerenciar a delegação. + +## Padrões relacionados + +* [Composite](https://java-design-patterns.com/patterns/composite/): a delegação pode ser usada dentro de um padrão composite para delegar comportamentos específicos de componentes a componentes filhos. +* [Strategy](https://java-design-patterns.com/patterns/strategy/): a delegação é frequentemente usada no padrão strategy, no qual um objeto de contexto delega tarefas a um objeto de estratégia. +* https://java-design-patterns.com/patterns/proxy/: o padrão proxy é uma forma de delegação em que um objeto proxy controla o acesso a outro objeto, ao qual delega o trabalho. + +## Referências e Créditos + +* [Effective Java](https://amzn.to/4aGE7gX) +* [Head First Design Patterns](https://amzn.to/3J9tuaB) +* [Refactoring: Improving the Design of Existing Code](https://amzn.to/3VOcRsw) +* [Delegate Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Delegation_pattern) diff --git a/localization/pt/money/README.md b/localization/pt/money/README.md new file mode 100644 index 000000000000..278924fb1315 --- /dev/null +++ b/localization/pt/money/README.md @@ -0,0 +1,131 @@ +--- +title: "Money Pattern in Java: Encapsulating Monetary Values with Currency Consistency" +shortTitle: Money +description: "Learn how the Money design pattern in Java ensures currency safety, precision handling, and maintainable financial operations. Explore examples, applicability, and benefits of the pattern." +category: Structural +language: pt +tag: + - Business + - Domain + - Encapsulation + - Immutable +--- + +## Também conhecido como + +* Monetary Value Object + +## Propósito + +Encapsular valores monetários e sua moeda associada em um objeto específico do domínio. + +## Explicação + +Exemplo do mundo real + +> Imagine um sistema de vale-presente on-line, no qual cada vale-presente mantém um saldo específico em uma determinada moeda. Em vez de usar apenas um valor de ponto flutuante para o saldo, o sistema usa um objeto Money para rastrear o valor e a moeda com precisão. Sempre que alguém usa o vale-presente, o saldo é atualizado com cálculos precisos que evitam erros de arredondamento de ponto flutuante, garantindo que a lógica de domínio permaneça consistente e correta. + +Em outras palavras + +> O padrão Money encapsula tanto um valor quanto sua moeda, garantindo que as operações financeiras sejam precisas, consistentes e fáceis de manter. + +De acordo com a Wikipédia + +> O padrão de design Money encapsula um valor monetário e sua moeda, permitindo operações aritméticas e conversões seguras, ao mesmo tempo em que preserva a precisão e a consistência nos cálculos financeiros. + +Mapa mental + +![Money Pattern Mind Map](../../../money/etc/money-mind-map.png) + +Fluxograma + +![Money Pattern Flowchart](../../../money/etc/money-flowchart.png) + +## Exemplo Programático + +Neste exemplo, criamos uma classe `Money` para demonstrar como valores monetários podem ser encapsulados junto com sua moeda. Essa abordagem ajuda a evitar imprecisões de ponto flutuante, garante que as operações aritméticas sejam tratadas de forma consistente e fornece uma maneira clara e centrada no domínio de trabalhar com dinheiro. + +```java +@AllArgsConstructor +@Getter +public class Money { + private double amount; + private String currency; + + public Money(double amnt, String curr) { + this.amount = amnt; + this.currency = curr; + } + + private double roundToTwoDecimals(double value) { + return Math.round(value * 100.0) / 100.0; + } + + public void addMoney(Money moneyToBeAdded) throws CannotAddTwoCurrienciesException { + if (!moneyToBeAdded.getCurrency().equals(this.currency)) { + throw new CannotAddTwoCurrienciesException("You are trying to add two different currencies"); + } + this.amount = roundToTwoDecimals(this.amount + moneyToBeAdded.getAmount()); + } + + public void subtractMoney(Money moneyToBeSubtracted) throws CannotSubtractException { + if (!moneyToBeSubtracted.getCurrency().equals(this.currency)) { + throw new CannotSubtractException("You are trying to subtract two different currencies"); + } else if (moneyToBeSubtracted.getAmount() > this.amount) { + throw new CannotSubtractException("The amount you are trying to subtract is larger than the amount you have"); + } + this.amount = roundToTwoDecimals(this.amount - moneyToBeSubtracted.getAmount()); + } + + public void multiply(int factor) { + if (factor < 0) { + throw new IllegalArgumentException("Factor must be non-negative"); + } + this.amount = roundToTwoDecimals(this.amount * factor); + } + + public void exchangeCurrency(String currencyToChangeTo, double exchangeRate) { + if (exchangeRate < 0) { + throw new IllegalArgumentException("Exchange rate must be non-negative"); + } + this.amount = roundToTwoDecimals(this.amount * exchangeRate); + this.currency = currencyToChangeTo; + } +} +``` + +Ao encapsular toda a lógica relacionada a dinheiro em uma única classe, reduzimos o risco de misturar moedas diferentes, melhoramos a clareza do código-base e facilitamos futuras modificações, como adicionar novas moedas ou refinar as regras de arredondamento. Esse padrão fortalece o modelo de domínio ao tratar o dinheiro como um conceito distinto, e não apenas como mais um valor numérico. + +## Quando usar o padrão Money + +* Quando cálculos financeiros ou manipulações de dinheiro fazem parte da lógica de negócio +* Quando é necessário um tratamento preciso de valores monetários para evitar imprecisões de ponto flutuante +* Quando princípios de domain-driven design e tipagem forte são desejados + +## Aplicações do mundo real do padrão Money + +* A biblioteca JSR 354 (Java Money and Currency) em Java +* Modelos de domínio personalizados em sistemas de e-commerce e contabilidade + +## Benefícios e desafios do padrão Money + +Benefícios + +* Fornece uma representação única e type-safe para valores monetários e moeda +* Incentiva o encapsulamento de operações relacionadas, como adição, subtração e formatação +* Evita erros de ponto flutuante ao usar inteiros ou bibliotecas decimais especializadas + +Desafios + +* Requer classes e infraestrutura adicionais para lidar com conversões e formatação de moeda +* Pode introduzir sobrecarga de desempenho ao realizar um grande número de operações monetárias + +## Padrões relacionados + +* [Value Object](https://java-design-patterns.com/patterns/value-object/): Money é tipicamente um exemplo clássico de value object em domain-driven design. + +## Referências e Créditos + +* [Domain-Driven Design: Tackling Complexity in the Heart of Software](https://amzn.to/3wlDrze) +* [Implementing Domain-Driven Design](https://amzn.to/4dmBjrB) +* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR) diff --git a/localization/pt/polling-publisher/README.md b/localization/pt/polling-publisher/README.md new file mode 100644 index 000000000000..d9cf98a550b3 --- /dev/null +++ b/localization/pt/polling-publisher/README.md @@ -0,0 +1,119 @@ +--- +title: "Polling Publisher-Subscriber Pattern in Java: Mastering Asynchronous Messaging Elegantly" +shortTitle: Polling Pub/Sub +description: "Learn how to implement a Polling Publisher-Subscriber system in Java using Spring Boot and Kafka. Explore the architecture, real-world analogies, and benefits of asynchronous communication with clean code examples." +category: Architectural +language: pt +tag: + - Spring Boot + - Kafka + - Microservices + - Asynchronous Messaging + - Decoupling +--- + +## Também conhecido como + +* Event-Driven Architecture +* Asynchronous Pub/Sub Pattern +* Message Queue-Based Polling System + +## Propósito + +O padrão Polling Publisher-Subscriber desacopla os produtores de dados dos consumidores ao permitir uma comunicação assíncrona e orientada a mensagens. Um serviço consulta periodicamente (poll) uma fonte de dados e publica mensagens em um message broker (por exemplo, Kafka), que são então consumidas por um ou mais serviços assinantes. + +## Explicação + +### Exemplo do mundo real + +> Uma agência de notícias consulta constantemente as últimas atualizações. Assim que recebe novas informações, ela as publica em diferentes veículos (TV, jornais, aplicativos). Cada veículo consome e exibe as atualizações de forma independente. + +### Em outras palavras + +> Um serviço verifica regularmente se há atualizações (polling) e envia mensagens para o Kafka. Outro serviço escuta o Kafka e processa as mensagens de forma assíncrona. + +### De acordo com a Wikipédia + +> Este padrão se assemelha muito ao [modelo Publish–subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern), no qual as mensagens são enviadas pelos publicadores e recebidas pelos assinantes sem que eles se conheçam. + +### Fluxo da arquitetura + +``` ++------------+ +--------+ +-------------+ +| Publisher | ---> | Kafka | ---> | Subscriber | ++------------+ +--------+ +-------------+ +``` + +## Exemplo Programático (Spring Boot + Kafka) + +### Serviço Publisher + +- Usa o `@Scheduled` do Spring para consultar dados periodicamente. +- Publica dados em um tópico do Kafka. +- Opcionalmente expõe uma API REST para publicação manual de dados. + +```java +@Scheduled(fixedRate = 5000) +public void pollAndPublish() { + String data = pollingService.getLatestData(); + kafkaTemplate.send("updates-topic", data); +} +``` + +### Serviço Subscriber + +- Escuta um tópico do Kafka usando `@KafkaListener`. +- Processa as mensagens de forma assíncrona. + +```java +@KafkaListener(topics = "updates-topic") +public void processUpdate(String message) { + log.info("Received update: {}", message); + updateProcessor.handle(message); +} +``` + +## Quando usar o padrão Polling Publisher-Subscriber + +Use esse padrão quando: + +* Não é possível o produtor enviar dados em tempo real (push). +* Deseja-se um baixo acoplamento entre produtores e consumidores. +* É necessário processamento de eventos assíncrono e escalável. +* Você está construindo uma arquitetura de microsserviços orientada a eventos. + +## Aplicações do mundo real + +* Painéis de relatórios em tempo real +* Agregadores de health check para sistemas distribuídos +* Processamento de telemetria de IoT +* Sistemas de notificação e alerta + +## Benefícios e desafios do padrão Polling Pub/Sub + +### Benefícios + +* Baixo acoplamento entre serviços +* Arquitetura assíncrona e escalável +* Tolerante a falhas, com persistência de mensagens no Kafka +* Fácil de estender com novos consumidores ou publicadores + +### Desafios + +* O polling introduz latência entre a geração e o consumo dos dados +* Requer o gerenciamento e a configuração do Kafka (ou de outro broker) +* Implantação e infraestrutura ligeiramente mais complexas + +## Padrões relacionados + +* [Observer Pattern](https://java-design-patterns.com/patterns/observer/) +* [Mediator Pattern](https://java-design-patterns.com/patterns/mediator/) +* [Message Queue Pattern](https://java-design-patterns.com/patterns/event-queue/) + +## Referências e Créditos + +* [Apache Kafka Documentation](https://kafka.apache.org/documentation/) +* [Spring Kafka Documentation](https://docs.spring.io/spring-kafka) +* [Spring Scheduled Tasks](https://www.baeldung.com/spring-scheduled-tasks) +* [Spring Kafka Tutorial – Baeldung](https://www.baeldung.com/spring-kafka) +* Inspired by: [iluwatar/java-design-patterns](https://github.com/iluwatar/java-design-patterns) From 126ad5fa1f064676ee6dde1a220db2a766375c23 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2026 07:52:05 +0300 Subject: [PATCH 108/108] docs: add zanarellidev as a contributor for translation (#3587) * 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 1d73d46a4e14..ccc740df15e1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3791,6 +3791,15 @@ "contributions": [ "code" ] + }, + { + "login": "zanarellidev", + "name": "zanarelli", + "avatar_url": "https://avatars.githubusercontent.com/u/268068569?v=4", + "profile": "https://github.com/zanarellidev", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 6, diff --git a/README.md b/README.md index 8db0c3bfb3a2..eb821177e73e 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-416-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-417-orange.svg?style=flat-square)](#contributors-)
@@ -616,6 +616,7 @@ This project is licensed under the terms of the MIT license. Sandhya
Sandhya

💻 dev-ikae
dev-ikae

💻 + zanarelli
zanarelli

🌍