From e65262983dbf9923c6de53ab0df071fd407e3c3d Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 24 Oct 2023 19:12:13 +1100 Subject: [PATCH 01/21] Implement Gateway pattern --- gateway/README.md | 173 ++++++++++++++++++ gateway/etc/gateway.urm.png | Bin 0 -> 46237 bytes gateway/etc/gateway.urm.puml | 43 +++++ gateway/pom.xml | 67 +++++++ gateway/src/main/java/com/iluwatar/App.java | 139 ++++++++++++++ .../src/main/java/com/iluwatar/Gateway.java | 8 + .../java/com/iluwatar/GatewayFactory.java | 18 ++ .../src/test/java/com/iluwatar/AppTest.java | 82 +++++++++ .../java/com/iluwatar/ServiceFactoryTest.java | 64 +++++++ pom.xml | 1 + 10 files changed, 595 insertions(+) create mode 100644 gateway/README.md create mode 100644 gateway/etc/gateway.urm.png create mode 100644 gateway/etc/gateway.urm.puml create mode 100644 gateway/pom.xml create mode 100644 gateway/src/main/java/com/iluwatar/App.java create mode 100644 gateway/src/main/java/com/iluwatar/Gateway.java create mode 100644 gateway/src/main/java/com/iluwatar/GatewayFactory.java create mode 100644 gateway/src/test/java/com/iluwatar/AppTest.java create mode 100644 gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java diff --git a/gateway/README.md b/gateway/README.md new file mode 100644 index 000000000000..7ef065ac2312 --- /dev/null +++ b/gateway/README.md @@ -0,0 +1,173 @@ +--- +title: Gateway +category: Structural +language: en +tag: + - Gang of Four + - Decoupling +--- + +## Intent +Provide a interface to access a set of external systems or functionalities. Gateway provides a simple uniform view of +external resources to the internals of an application. + +## Explanation + +Real-world example + +> Gateway acts like a real front gate of a certain city. The people inside the city are called +> internal system, and different outside cities are called external services. The gateway is here +> to provide access for internal system to different external services. + +In plain words + +> Gateway can provide an interface which lets internal system to utilize external service. + +Wikipedia says + +> A server that acts as an API front-end, receives API requests, enforces throttling and security +> policies, passes requests to the back-end service and then passes the response back to the requester. + +**Programmatic Example** + +The main class in our example is the `ExternalService` that contains items. + +```java +class ExternalServiceA implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service A"); + // Simulate a time-consuming task + Thread.sleep(1000); + } +} + +// Concrete Gateway for Service B +class ExternalServiceB implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service B"); + // Simulate a time-consuming task + Thread.sleep(1000); + // Simulate an exception + // throw new RuntimeException("Service B encountered an error"); + } +} + +// Concrete Gateway for Service B +class ExternalServiceC implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service C"); + // Simulate a time-consuming task + Thread.sleep(1000); + } + + public void error() throws Exception{ + // Simulate an exception + throw new RuntimeException("Service B encountered an error"); + } +} + +``` + +To operate these external services, Here's the `App` class: + +```java +public class App { + public static void main(String[] args) { + GatewayFactory gatewayFactory = new GatewayFactory(); + + // Register different gateways + gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); + gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); + gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); + + // Use an executor service for asynchronous execution + ExecutorService executorService = Executors.newFixedThreadPool(2); + + try { + // Execute Service A asynchronously + Future serviceAFuture = executorService.submit(() -> { + try { + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + serviceA.execute(); + } catch (Exception e) { + System.err.println("Error executing Service A: " + e.getMessage()); + } + }); + + // Execute Service B asynchronously + Future serviceBFuture = executorService.submit(() -> { + try { + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + serviceB.execute(); + } catch (Exception e) { + System.err.println("Error executing Service B: " + e.getMessage()); + } + }); + + // Execute Service C asynchronously + Future servicecFuture = executorService.submit(() -> { + try { + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + serviceC.execute(); + } catch (Exception e) { + System.err.println("Error executing Service C: " + e.getMessage()); + } + }); + + // Wait for both tasks to complete + serviceAFuture.get(); + serviceBFuture.get(); + servicecFuture.get(); + } catch (Exception e) { + System.err.println("Error in the main client: " + e.getMessage()); + } finally { + executorService.shutown(); + } + } +} +``` + +The `Gateway` interface is extremely simple. + +```java +interface Gateway { + void execute() throws Exception; +} +``` + +Program output: + +```java + Executing Service A + Executing Service B + Executing Service C +``` + +## Class diagram + +![alt text](./etc/gateway.urm.png "gateway") + +## Applicability + +Use the Gateway pattern + +* To access an aggregate object's contents without exposing its internal representation. +* To integration with multiple external services or APIs. +* To provide a uniform interface for traversing different aggregate structures. + +## Tutorials + +* [Pattern: API Gateway / Backends for Frontends](https://microservices.io/patterns/apigateway.html) + +## Known uses + +* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/) +* [10 most common use cases of an API Gateway](https://apisix.apache.org/blog/2022/10/27/ten-use-cases-api-gateway/) + +## Credits + +* [Gateway](https://martinfowler.com/articles/gateway-pattern.html) +* [What is the difference between Facade and Gateway design patterns?](https://stackoverflow.com/questions/4422211/what-is-the-difference-between-facade-and-gateway-design-patterns) diff --git a/gateway/etc/gateway.urm.png b/gateway/etc/gateway.urm.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8ad6c9a8f839b82d4ad148d1e3eb25945e6710 GIT binary patch literal 46237 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 C)*Mp+ literal 0 HcmV?d00001 diff --git a/gateway/etc/gateway.urm.puml b/gateway/etc/gateway.urm.puml new file mode 100644 index 000000000000..3439ca17f6ae --- /dev/null +++ b/gateway/etc/gateway.urm.puml @@ -0,0 +1,43 @@ +@startuml GatewayPattern +package com.iluwatar.gateway{ +class App { + +main(args: String[]): void +} + +class GatewayFactory { + -gateways: Map + +registerGateway(key: String, gateway: Gateway): void + +getGateway(key: String): Gateway +} + +interface Gateway { + {abstract} +execute(): void +} + +class ExternalServiceA { + +execute(): void +} + +class ExternalServiceB { + +execute(): void +} + +class ExternalServiceC { + +execute(): void + +error(): void +} + +App --> GatewayFactory : Uses + + +GatewayFactory --> Gateway : Creates + +GatewayFactory --> ExternalServiceA : Registers +GatewayFactory --> ExternalServiceB : Registers +GatewayFactory --> ExternalServiceC : Registers + +ExternalServiceA --> Gateway : Implements +ExternalServiceB --> Gateway : Implements +ExternalServiceC --> Gateway : Implements + +@enduml diff --git a/gateway/pom.xml b/gateway/pom.xml new file mode 100644 index 000000000000..66b0c4d926a2 --- /dev/null +++ b/gateway/pom.xml @@ -0,0 +1,67 @@ + + + + + java-design-patterns + com.iluwatar + 1.26.0-SNAPSHOT + + 4.0.0 + balking + + + org.junit.jupiter + junit-jupiter-engine + test + + + junit + junit + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.balking.App + + + + + + + + + diff --git a/gateway/src/main/java/com/iluwatar/App.java b/gateway/src/main/java/com/iluwatar/App.java new file mode 100644 index 000000000000..378524b67887 --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/App.java @@ -0,0 +1,139 @@ +/* + * 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 java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + + +/** + * The "App" class serves as the main entry point for the application implementing the Gateway design pattern. + * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the + * execution of various services asynchronously. + * + *

In this example, there are three virtual service. GateFactory is the factory class and it + * provides a method to create different kinds of external services. + */ +public class App { + public static void main(String[] args) { + GatewayFactory gatewayFactory = new GatewayFactory(); + + // Register different gateways + gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); + gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); + gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); + + // Use an executor service for asynchronous execution + ExecutorService executorService = Executors.newFixedThreadPool(2); + + try { + // Execute Service A asynchronously + Future serviceAFuture = executorService.submit(() -> { + try { + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + serviceA.execute(); + } catch (Exception e) { + System.err.println("Error executing Service A: " + e.getMessage()); + } + }); + + // Execute Service B asynchronously + Future serviceBFuture = executorService.submit(() -> { + try { + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + serviceB.execute(); + } catch (Exception e) { + System.err.println("Error executing Service B: " + e.getMessage()); + } + }); + + // Execute Service C asynchronously + Future servicecFuture = executorService.submit(() -> { + try { + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + serviceC.execute(); + } catch (Exception e) { + System.err.println("Error executing Service C: " + e.getMessage()); + } + }); + + // Wait for both tasks to complete + serviceAFuture.get(); + serviceBFuture.get(); + servicecFuture.get(); + } catch (Exception e) { + System.err.println("Error in the main client: " + e.getMessage()); + } finally { + executorService.shutdown(); + } + } +} + +/** + * ExternalServiceA is one of external services. + */ +class ExternalServiceA implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service A"); + // Simulate a time-consuming task + Thread.sleep(1000); + } +} + +/** + * ExternalServiceB is one of external services. + */ +class ExternalServiceB implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service B"); + // Simulate a time-consuming task + Thread.sleep(1000); + } + + public void error() throws Exception{ + // Simulate an exception + throw new RuntimeException("Service B encountered an error"); + } +} + +/** + * ExternalServiceC is one of external services. + */ +class ExternalServiceC implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service C"); + // Simulate a time-consuming task + Thread.sleep(1000); + } + + public void error() throws Exception{ + // Simulate an exception + throw new RuntimeException("Service C encountered an error"); + } +} diff --git a/gateway/src/main/java/com/iluwatar/Gateway.java b/gateway/src/main/java/com/iluwatar/Gateway.java new file mode 100644 index 000000000000..0092251cb276 --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/Gateway.java @@ -0,0 +1,8 @@ +package com.iluwatar; + +/** + * Service interface. + */ +interface Gateway { + void execute() throws Exception; +} \ No newline at end of file diff --git a/gateway/src/main/java/com/iluwatar/GatewayFactory.java b/gateway/src/main/java/com/iluwatar/GatewayFactory.java new file mode 100644 index 000000000000..dba797eb0d1d --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/GatewayFactory.java @@ -0,0 +1,18 @@ +package com.iluwatar; +import java.util.HashMap; +import java.util.Map; +/** + * The "GatewayFactory" class is responsible for providing different external services in this Gateway design pattern + * example. It allows clients to register and retrieve specific gateways based on unique keys. + */ +public class GatewayFactory { + private Map gateways = new HashMap<>(); + + public void registerGateway(String key, Gateway gateway) { + gateways.put(key, gateway); + } + + public Gateway getGateway(String key) { + return gateways.get(key); + } +} diff --git a/gateway/src/test/java/com/iluwatar/AppTest.java b/gateway/src/test/java/com/iluwatar/AppTest.java new file mode 100644 index 000000000000..2d38e0814481 --- /dev/null +++ b/gateway/src/test/java/com/iluwatar/AppTest.java @@ -0,0 +1,82 @@ +package com.iluwatar; + +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class AppTest { + private GatewayFactory gatewayFactory; + private ExecutorService executorService; + + @Before + public void setUp() { + gatewayFactory = new GatewayFactory(); + executorService = Executors.newFixedThreadPool(2); + gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); + gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); + gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); + } + + @Test + public void testServiceAExecution() throws InterruptedException, ExecutionException { + // Test Service A execution + Future serviceAFuture = executorService.submit(() -> { + try { + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + serviceA.execute(); + } catch (Exception e) { + fail("Service A should not throw an exception."); + } + }); + + // Wait for Service A to complete + serviceAFuture.get(); + } + + @Test + public void testServiceCExecutionWithException() throws InterruptedException, ExecutionException { + // Test Service B execution with an exception + Future serviceBFuture = executorService.submit(() -> { + try { + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + serviceB.execute(); + } catch (Exception e) { + fail("Service B should not throw an exception."); + } + }); + + // Wait for Service B to complete + serviceBFuture.get(); + } + + @Test + public void testServiceCExecution() throws InterruptedException, ExecutionException { + // Test Service C execution + Future serviceCFuture = executorService.submit(() -> { + try { + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + serviceC.execute(); + } catch (Exception e) { + fail("Service C should not throw an exception."); + } + }); + + // Wait for Service C to complete + serviceCFuture.get(); + } + + @Test + public void testServiceCError() { + try { + ExternalServiceC serviceC = (ExternalServiceC) gatewayFactory.getGateway("ServiceC"); + serviceC.error(); + fail("Service C should throw an exception."); + } catch (Exception e) { + assertEquals("Service C encountered an error", e.getMessage()); + } + } +} diff --git a/gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java b/gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java new file mode 100644 index 000000000000..09d2877e11a3 --- /dev/null +++ b/gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java @@ -0,0 +1,64 @@ +package com.iluwatar; + +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicBoolean; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ServiceFactoryTest { + private GatewayFactory gatewayFactory; + private ExecutorService executorService; + @Before + public void setUp() { + gatewayFactory = new GatewayFactory(); + executorService = Executors.newFixedThreadPool(2); + gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); + gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); + gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); + } + @Test + public void testGatewayFactoryRegistrationAndRetrieval() { + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + + assertTrue(serviceA instanceof ExternalServiceA); + assertTrue(serviceB instanceof ExternalServiceB); + assertTrue(serviceC instanceof ExternalServiceC); + } + + @Test + public void testGatewayFactoryRegistrationWithNonExistingKey() { + Gateway nonExistingService = gatewayFactory.getGateway("NonExistingService"); + assertEquals(null, nonExistingService); + } + + @Test + public void testGatewayFactoryConcurrency() throws InterruptedException { + int numThreads = 10; + CountDownLatch latch = new CountDownLatch(numThreads); + AtomicBoolean failed = new AtomicBoolean(false); + + for (int i = 0; i < numThreads; i++) { + executorService.submit(() -> { + try { + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + serviceA.execute(); + } catch (Exception e) { + failed.set(true); + } finally { + latch.countDown(); + } + }); + } + + latch.await(); + assertTrue(!failed.get()); + } +} diff --git a/pom.xml b/pom.xml index 4169976ff444..b99742350dad 100644 --- a/pom.xml +++ b/pom.xml @@ -208,6 +208,7 @@ thread-local-storage optimistic-offline-lock crtp + gateway From ea59c1589aae70d984d364c77d3bd92f6f714951 Mon Sep 17 00:00:00 2001 From: Finn Date: Tue, 24 Oct 2023 19:17:46 +1100 Subject: [PATCH 02/21] Fixed docstrings --- gateway/src/main/java/com/iluwatar/App.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gateway/src/main/java/com/iluwatar/App.java b/gateway/src/main/java/com/iluwatar/App.java index 378524b67887..647f9200a11f 100644 --- a/gateway/src/main/java/com/iluwatar/App.java +++ b/gateway/src/main/java/com/iluwatar/App.java @@ -30,12 +30,12 @@ /** - * The "App" class serves as the main entry point for the application implementing the Gateway design pattern. + * The App class serves as the main entry point for the application implementing the Gateway design pattern. * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the * execution of various services asynchronously. * - *

In this example, there are three virtual service. GateFactory is the factory class and it - * provides a method to create different kinds of external services. + *

In this example, there are three virtual service. GateFactory is the factory class and it provides a method + * to create different kinds of external services. */ public class App { public static void main(String[] args) { From c2c407287ec0573ec935df82645a334ea7b915b2 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 18:46:25 +1100 Subject: [PATCH 03/21] Fixed README.md --- gateway/README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index 7ef065ac2312..a454f5fa043f 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -42,19 +42,26 @@ class ExternalServiceA implements Gateway { } } -// Concrete Gateway for Service B +/** + * ExternalServiceB is one of external services. + */ class ExternalServiceB implements Gateway { @Override public void execute() throws Exception { System.out.println("Executing Service B"); // Simulate a time-consuming task Thread.sleep(1000); + } + + public void error() throws Exception{ // Simulate an exception - // throw new RuntimeException("Service B encountered an error"); + throw new RuntimeException("Service B encountered an error"); } } -// Concrete Gateway for Service B +/** + * ExternalServiceC is one of external services. + */ class ExternalServiceC implements Gateway { @Override public void execute() throws Exception { @@ -65,10 +72,9 @@ class ExternalServiceC implements Gateway { public void error() throws Exception{ // Simulate an exception - throw new RuntimeException("Service B encountered an error"); + throw new RuntimeException("Service C encountered an error"); } } - ``` To operate these external services, Here's the `App` class: From 957c67cecf70d2ad6838ea66008dacdd527475f8 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 18:53:30 +1100 Subject: [PATCH 04/21] Fixed App --- gateway/README.md | 5 ----- gateway/src/main/java/com/iluwatar/App.java | 5 ----- 2 files changed, 10 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index a454f5fa043f..8b42a9f409f5 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -52,11 +52,6 @@ class ExternalServiceB implements Gateway { // Simulate a time-consuming task Thread.sleep(1000); } - - public void error() throws Exception{ - // Simulate an exception - throw new RuntimeException("Service B encountered an error"); - } } /** diff --git a/gateway/src/main/java/com/iluwatar/App.java b/gateway/src/main/java/com/iluwatar/App.java index 647f9200a11f..d481f1c90106 100644 --- a/gateway/src/main/java/com/iluwatar/App.java +++ b/gateway/src/main/java/com/iluwatar/App.java @@ -114,11 +114,6 @@ public void execute() throws Exception { // Simulate a time-consuming task Thread.sleep(1000); } - - public void error() throws Exception{ - // Simulate an exception - throw new RuntimeException("Service B encountered an error"); - } } /** From a364c571b0dea3239e027db597d6a81a8e8b5937 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 19:05:54 +1100 Subject: [PATCH 05/21] Fixed pom.xml --- gateway/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gateway/pom.xml b/gateway/pom.xml index 66b0c4d926a2..43738603de88 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -32,7 +32,7 @@ 1.26.0-SNAPSHOT 4.0.0 - balking + gateway org.junit.jupiter @@ -55,7 +55,7 @@ - com.iluwatar.balking.App + com.iluwatar.gateway.App From 79f0827996ba7d75387cc5c7410558d55d6f7282 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 19:40:42 +1100 Subject: [PATCH 06/21] Fixed pom.xml --- gateway/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway/pom.xml b/gateway/pom.xml index 43738603de88..9137ab3042b4 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -26,12 +26,12 @@ --> + 4.0.0 java-design-patterns com.iluwatar 1.26.0-SNAPSHOT - 4.0.0 gateway From 0eaf22fce27ff23fbe869e84cfacf50e652b9810 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 19:42:13 +1100 Subject: [PATCH 07/21] Fixed pom.xml --- gateway/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/gateway/pom.xml b/gateway/pom.xml index 9137ab3042b4..05aea9ea0f4b 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -39,11 +39,6 @@ junit-jupiter-engine test - - junit - junit - test - From 95fd46c70242e089748538acbdd082c81d85f062 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 20:32:23 +1100 Subject: [PATCH 08/21] Fixed pom.xml --- gateway/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gateway/pom.xml b/gateway/pom.xml index 05aea9ea0f4b..9137ab3042b4 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -39,6 +39,11 @@ junit-jupiter-engine test + + junit + junit + test + From f895c8ee72cda0e1f9fe58cfa5153ad1659c5f16 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 21:13:47 +1100 Subject: [PATCH 09/21] fixed checkstyle errors and directory names --- gateway/README.md | 19 +++++++++++-------- gateway/pom.xml | 3 ++- .../java/com/iluwatar/{ => gateway}/App.java | 4 ++-- .../com/iluwatar/{ => gateway}/Gateway.java | 2 +- .../{ => gateway}/GatewayFactory.java | 4 +++- .../com/iluwatar/{ => gateway}/AppTest.java | 8 ++++++-- .../{ => gateway}/ServiceFactoryTest.java | 5 ++++- 7 files changed, 29 insertions(+), 16 deletions(-) rename gateway/src/main/java/com/iluwatar/{ => gateway}/App.java (98%) rename gateway/src/main/java/com/iluwatar/{ => gateway}/Gateway.java (74%) rename gateway/src/main/java/com/iluwatar/{ => gateway}/GatewayFactory.java (94%) rename gateway/src/test/java/com/iluwatar/{ => gateway}/AppTest.java (92%) rename gateway/src/test/java/com/iluwatar/{ => gateway}/ServiceFactoryTest.java (97%) diff --git a/gateway/README.md b/gateway/README.md index 8b42a9f409f5..66c0637a6ef5 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -3,21 +3,24 @@ title: Gateway category: Structural language: en tag: - - Gang of Four - - Decoupling + +- Gang of Four +- Decoupling + --- ## Intent -Provide a interface to access a set of external systems or functionalities. Gateway provides a simple uniform view of + +Provide a interface to access a set of external systems or functionalities. Gateway provides a simple uniform view of external resources to the internals of an application. ## Explanation Real-world example -> Gateway acts like a real front gate of a certain city. The people inside the city are called +> Gateway acts like a real front gate of a certain city. The people inside the city are called > internal system, and different outside cities are called external services. The gateway is here -> to provide access for internal system to different external services. +> to provide access for internal system to different external services. In plain words @@ -25,7 +28,7 @@ In plain words Wikipedia says -> A server that acts as an API front-end, receives API requests, enforces throttling and security +> A server that acts as an API front-end, receives API requests, enforces throttling and security > policies, passes requests to the back-end service and then passes the response back to the requester. **Programmatic Example** @@ -65,7 +68,7 @@ class ExternalServiceC implements Gateway { Thread.sleep(1000); } - public void error() throws Exception{ + public void error() throws Exception { // Simulate an exception throw new RuntimeException("Service C encountered an error"); } @@ -142,7 +145,7 @@ interface Gateway { Program output: ```java - Executing Service A + Executing Service A Executing Service B Executing Service C ``` diff --git a/gateway/pom.xml b/gateway/pom.xml index 9137ab3042b4..1bd7171988d3 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -25,7 +25,8 @@ THE SOFTWARE. --> - + 4.0.0 java-design-patterns diff --git a/gateway/src/main/java/com/iluwatar/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java similarity index 98% rename from gateway/src/main/java/com/iluwatar/App.java rename to gateway/src/main/java/com/iluwatar/gateway/App.java index d481f1c90106..2b9b94d6eb9a 100644 --- a/gateway/src/main/java/com/iluwatar/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -22,7 +22,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package com.iluwatar; +package com.iluwatar.gateway; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -127,7 +127,7 @@ public void execute() throws Exception { Thread.sleep(1000); } - public void error() throws Exception{ + public void error() throws Exception { // Simulate an exception throw new RuntimeException("Service C encountered an error"); } diff --git a/gateway/src/main/java/com/iluwatar/Gateway.java b/gateway/src/main/java/com/iluwatar/gateway/Gateway.java similarity index 74% rename from gateway/src/main/java/com/iluwatar/Gateway.java rename to gateway/src/main/java/com/iluwatar/gateway/Gateway.java index 0092251cb276..6c113e8b8d04 100644 --- a/gateway/src/main/java/com/iluwatar/Gateway.java +++ b/gateway/src/main/java/com/iluwatar/gateway/Gateway.java @@ -1,4 +1,4 @@ -package com.iluwatar; +package com.iluwatar.gateway; /** * Service interface. diff --git a/gateway/src/main/java/com/iluwatar/GatewayFactory.java b/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java similarity index 94% rename from gateway/src/main/java/com/iluwatar/GatewayFactory.java rename to gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java index dba797eb0d1d..7514eeebe2d9 100644 --- a/gateway/src/main/java/com/iluwatar/GatewayFactory.java +++ b/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java @@ -1,6 +1,8 @@ -package com.iluwatar; +package com.iluwatar.gateway; + import java.util.HashMap; import java.util.Map; + /** * The "GatewayFactory" class is responsible for providing different external services in this Gateway design pattern * example. It allows clients to register and retrieve specific gateways based on unique keys. diff --git a/gateway/src/test/java/com/iluwatar/AppTest.java b/gateway/src/test/java/com/iluwatar/gateway/AppTest.java similarity index 92% rename from gateway/src/test/java/com/iluwatar/AppTest.java rename to gateway/src/test/java/com/iluwatar/gateway/AppTest.java index 2d38e0814481..39fbceeea46f 100644 --- a/gateway/src/test/java/com/iluwatar/AppTest.java +++ b/gateway/src/test/java/com/iluwatar/gateway/AppTest.java @@ -1,9 +1,13 @@ -package com.iluwatar; +package com.iluwatar.gateway; +import com.iluwatar.*; import org.junit.Before; import org.junit.Test; -import java.util.concurrent.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; diff --git a/gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java similarity index 97% rename from gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java rename to gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java index 09d2877e11a3..38720087aced 100644 --- a/gateway/src/test/java/com/iluwatar/ServiceFactoryTest.java +++ b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java @@ -1,5 +1,6 @@ -package com.iluwatar; +package com.iluwatar.gateway; +import com.iluwatar.*; import org.junit.Before; import org.junit.Test; @@ -14,6 +15,7 @@ public class ServiceFactoryTest { private GatewayFactory gatewayFactory; private ExecutorService executorService; + @Before public void setUp() { gatewayFactory = new GatewayFactory(); @@ -22,6 +24,7 @@ public void setUp() { gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); } + @Test public void testGatewayFactoryRegistrationAndRetrieval() { Gateway serviceA = gatewayFactory.getGateway("ServiceA"); From 3d8d64c74e13b6401ce0e1757e41eabc966637f4 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 22:12:39 +1100 Subject: [PATCH 10/21] fixed pom.xml --- gateway/pom.xml | 11 +++-------- .../src/test/java/com/iluwatar/gateway/AppTest.java | 1 - .../java/com/iluwatar/gateway/ServiceFactoryTest.java | 2 +- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/gateway/pom.xml b/gateway/pom.xml index 1bd7171988d3..c84f44857d3f 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -25,14 +25,14 @@ THE SOFTWARE. --> - + 4.0.0 - java-design-patterns com.iluwatar + java-design-patterns 1.26.0-SNAPSHOT + jar gateway @@ -40,11 +40,6 @@ junit-jupiter-engine test - - junit - junit - test - diff --git a/gateway/src/test/java/com/iluwatar/gateway/AppTest.java b/gateway/src/test/java/com/iluwatar/gateway/AppTest.java index 39fbceeea46f..ad75d517576e 100644 --- a/gateway/src/test/java/com/iluwatar/gateway/AppTest.java +++ b/gateway/src/test/java/com/iluwatar/gateway/AppTest.java @@ -1,6 +1,5 @@ package com.iluwatar.gateway; -import com.iluwatar.*; import org.junit.Before; import org.junit.Test; diff --git a/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java index 38720087aced..16eb92afc553 100644 --- a/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java +++ b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java @@ -1,6 +1,6 @@ package com.iluwatar.gateway; -import com.iluwatar.*; + import org.junit.Before; import org.junit.Test; From 2f5ec5d789ed13c7ca40a6ab497ca32103cffbde Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 22:41:06 +1100 Subject: [PATCH 11/21] fixed checkstyle errors --- gateway/pom.xml | 5 + .../main/java/com/iluwatar/gateway/App.java | 128 ++++++------------ .../iluwatar/gateway/ExternalServiceA.java | 39 ++++++ .../iluwatar/gateway/ExternalServiceB.java | 39 ++++++ .../iluwatar/gateway/ExternalServiceC.java | 43 ++++++ .../java/com/iluwatar/gateway/Gateway.java | 2 +- .../com/iluwatar/gateway/GatewayFactory.java | 14 +- .../iluwatar/gateway/ServiceFactoryTest.java | 10 +- 8 files changed, 185 insertions(+), 95 deletions(-) create mode 100644 gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java create mode 100644 gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java create mode 100644 gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java diff --git a/gateway/pom.xml b/gateway/pom.xml index c84f44857d3f..88c15cd586ea 100644 --- a/gateway/pom.xml +++ b/gateway/pom.xml @@ -40,6 +40,11 @@ junit-jupiter-engine test + + junit + junit + test + diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index 2b9b94d6eb9a..23ea7faf9fe5 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -38,97 +38,59 @@ * to create different kinds of external services. */ public class App { - public static void main(String[] args) { - GatewayFactory gatewayFactory = new GatewayFactory(); + /** + * Simulate an application calling external services. + */ + public static void main(String[] args) { + GatewayFactory gatewayFactory = new GatewayFactory(); - // Register different gateways - gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); - gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); - gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); + // Register different gateways + gatewayFactory.registerGateway("ServiceA", new ExternalServiceA()); + gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); + gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); - // Use an executor service for asynchronous execution - ExecutorService executorService = Executors.newFixedThreadPool(2); + // Use an executor service for asynchronous execution + ExecutorService executorService = Executors.newFixedThreadPool(2); + try { + // Execute Service A asynchronously + Future serviceFutureA = executorService.submit(() -> { try { - // Execute Service A asynchronously - Future serviceAFuture = executorService.submit(() -> { - try { - Gateway serviceA = gatewayFactory.getGateway("ServiceA"); - serviceA.execute(); - } catch (Exception e) { - System.err.println("Error executing Service A: " + e.getMessage()); - } - }); - - // Execute Service B asynchronously - Future serviceBFuture = executorService.submit(() -> { - try { - Gateway serviceB = gatewayFactory.getGateway("ServiceB"); - serviceB.execute(); - } catch (Exception e) { - System.err.println("Error executing Service B: " + e.getMessage()); - } - }); - - // Execute Service C asynchronously - Future servicecFuture = executorService.submit(() -> { - try { - Gateway serviceC = gatewayFactory.getGateway("ServiceC"); - serviceC.execute(); - } catch (Exception e) { - System.err.println("Error executing Service C: " + e.getMessage()); - } - }); - - // Wait for both tasks to complete - serviceAFuture.get(); - serviceBFuture.get(); - servicecFuture.get(); + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + serviceA.execute(); } catch (Exception e) { - System.err.println("Error in the main client: " + e.getMessage()); - } finally { - executorService.shutdown(); + System.err.println("Error executing Service A: " + e.getMessage()); } - } -} - -/** - * ExternalServiceA is one of external services. - */ -class ExternalServiceA implements Gateway { - @Override - public void execute() throws Exception { - System.out.println("Executing Service A"); - // Simulate a time-consuming task - Thread.sleep(1000); - } -} + }); -/** - * ExternalServiceB is one of external services. - */ -class ExternalServiceB implements Gateway { - @Override - public void execute() throws Exception { - System.out.println("Executing Service B"); - // Simulate a time-consuming task - Thread.sleep(1000); - } -} + // Execute Service B asynchronously + Future serviceFutureB = executorService.submit(() -> { + try { + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + serviceB.execute(); + } catch (Exception e) { + System.err.println("Error executing Service B: " + e.getMessage()); + } + }); -/** - * ExternalServiceC is one of external services. - */ -class ExternalServiceC implements Gateway { - @Override - public void execute() throws Exception { - System.out.println("Executing Service C"); - // Simulate a time-consuming task - Thread.sleep(1000); - } + // Execute Service C asynchronously + Future serviceFutureC = executorService.submit(() -> { + try { + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + serviceC.execute(); + } catch (Exception e) { + System.err.println("Error executing Service C: " + e.getMessage()); + } + }); - public void error() throws Exception { - // Simulate an exception - throw new RuntimeException("Service C encountered an error"); + // Wait for both tasks to complete + serviceFutureA.get(); + serviceFutureB.get(); + serviceFutureC.get(); + } catch (Exception e) { + System.err.println("Error in the main client: " + e.getMessage()); + } finally { + executorService.shutdown(); } + } } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java new file mode 100644 index 000000000000..c467e1fe009b --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.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.gateway; + + +/** +* ExternalServiceA is one of external services. +*/ +class ExternalServiceA implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service A"); + // Simulate a time-consuming task + Thread.sleep(1000); + } +} + diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java new file mode 100644 index 000000000000..144c9b6b2536 --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.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.gateway; + + +/** +* ExternalServiceB is one of external services. +*/ +class ExternalServiceB implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service B"); + // Simulate a time-consuming task + Thread.sleep(1000); + } +} + diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java new file mode 100644 index 000000000000..067d4917040a --- /dev/null +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.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.gateway; + + +/** +* ExternalServiceC is one of external services. +*/ +class ExternalServiceC implements Gateway { + @Override + public void execute() throws Exception { + System.out.println("Executing Service C"); + // Simulate a time-consuming task + Thread.sleep(1000); + } + + public void error() throws Exception { + // Simulate an exception + throw new RuntimeException("Service C encountered an error"); + } +} diff --git a/gateway/src/main/java/com/iluwatar/gateway/Gateway.java b/gateway/src/main/java/com/iluwatar/gateway/Gateway.java index 6c113e8b8d04..912f78b4737b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/Gateway.java +++ b/gateway/src/main/java/com/iluwatar/gateway/Gateway.java @@ -4,5 +4,5 @@ * Service interface. */ interface Gateway { - void execute() throws Exception; + void execute() throws Exception; } \ No newline at end of file diff --git a/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java b/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java index 7514eeebe2d9..0a76368a349c 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java +++ b/gateway/src/main/java/com/iluwatar/gateway/GatewayFactory.java @@ -8,13 +8,13 @@ * example. It allows clients to register and retrieve specific gateways based on unique keys. */ public class GatewayFactory { - private Map gateways = new HashMap<>(); + private Map gateways = new HashMap<>(); - public void registerGateway(String key, Gateway gateway) { - gateways.put(key, gateway); - } + public void registerGateway(String key, Gateway gateway) { + gateways.put(key, gateway); + } - public Gateway getGateway(String key) { - return gateways.get(key); - } + public Gateway getGateway(String key) { + return gateways.get(key); + } } diff --git a/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java index 16eb92afc553..f6dd640f31b9 100644 --- a/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java +++ b/gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; public class ServiceFactoryTest { private GatewayFactory gatewayFactory; @@ -31,9 +32,10 @@ public void testGatewayFactoryRegistrationAndRetrieval() { Gateway serviceB = gatewayFactory.getGateway("ServiceB"); Gateway serviceC = gatewayFactory.getGateway("ServiceC"); - assertTrue(serviceA instanceof ExternalServiceA); - assertTrue(serviceB instanceof ExternalServiceB); - assertTrue(serviceC instanceof ExternalServiceC); + // Check if the retrieved instances match their expected types + assertTrue("ServiceA should be an instance of ExternalServiceA", serviceA instanceof ExternalServiceA); + assertTrue("ServiceB should be an instance of ExternalServiceB", serviceB instanceof ExternalServiceB); + assertTrue("ServiceC should be an instance of ExternalServiceC", serviceC instanceof ExternalServiceC); } @Test @@ -62,6 +64,6 @@ public void testGatewayFactoryConcurrency() throws InterruptedException { } latch.await(); - assertTrue(!failed.get()); + assertTrue("This should not fail", !failed.get()); } } From fbac2142d1e775ae3af97693b1c086dc370db0c2 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 23:10:59 +1100 Subject: [PATCH 12/21] Bug fixed --- gateway/src/main/java/com/iluwatar/gateway/App.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index 23ea7faf9fe5..a2751eef02e6 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -84,9 +84,16 @@ public static void main(String[] args) { }); // Wait for both tasks to complete - serviceFutureA.get(); - serviceFutureB.get(); - serviceFutureC.get(); + try { + serviceFutureA.get(); + serviceFutureB.get(); + serviceFutureC.get(); + } catch (Exception e) { + System.err.println("Error in the main client: " + e.getMessage()); + } finally { + executorService.shutdown(); + } + } catch (Exception e) { System.err.println("Error in the main client: " + e.getMessage()); } finally { From 29fc5c77ffaa38820266d40b9a0ebd88e2ede6e6 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 23:30:35 +1100 Subject: [PATCH 13/21] Bug fixed --- gateway/src/main/java/com/iluwatar/gateway/App.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index a2751eef02e6..b93438bd97e9 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,6 +24,7 @@ */ package com.iluwatar.gateway; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -88,12 +89,11 @@ public static void main(String[] args) { serviceFutureA.get(); serviceFutureB.get(); serviceFutureC.get(); - } catch (Exception e) { + } catch (InterruptedException e) { System.err.println("Error in the main client: " + e.getMessage()); } finally { executorService.shutdown(); } - } catch (Exception e) { System.err.println("Error in the main client: " + e.getMessage()); } finally { From dd4471b8899101c81d617b58ed52819caad62bc9 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 25 Oct 2023 23:51:48 +1100 Subject: [PATCH 14/21] Bug fixed --- gateway/src/main/java/com/iluwatar/gateway/App.java | 1 + 1 file changed, 1 insertion(+) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index b93438bd97e9..25a8f691db0b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -96,6 +96,7 @@ public static void main(String[] args) { } } catch (Exception e) { System.err.println("Error in the main client: " + e.getMessage()); + Thread.currentThread().interrupt(); } finally { executorService.shutdown(); } From f2bbc5ec65b76b0d2b7f2e6992ba171a3e6ecdda Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 26 Oct 2023 00:08:54 +1100 Subject: [PATCH 15/21] Bug fixed and code improvement --- gateway/src/main/java/com/iluwatar/gateway/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index 25a8f691db0b..af319f4244fe 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,7 +24,6 @@ */ package com.iluwatar.gateway; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; @@ -91,6 +90,7 @@ public static void main(String[] args) { serviceFutureC.get(); } catch (InterruptedException e) { System.err.println("Error in the main client: " + e.getMessage()); + Thread.currentThread().interrupt(); } finally { executorService.shutdown(); } From 77b0bfde293cd8ec1b8892f0ac030b3952e676dd Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 26 Oct 2023 00:29:00 +1100 Subject: [PATCH 16/21] Bug fixed and code improvement --- .../main/java/com/iluwatar/gateway/App.java | 63 +++---------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index af319f4244fe..6aa5edb1d563 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,11 +24,6 @@ */ package com.iluwatar.gateway; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - - /** * The App class serves as the main entry point for the application implementing the Gateway design pattern. * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the @@ -41,7 +36,7 @@ public class App { /** * Simulate an application calling external services. */ - public static void main(String[] args) { + public static void main(String[] args) throws Exception { GatewayFactory gatewayFactory = new GatewayFactory(); // Register different gateways @@ -50,55 +45,17 @@ public static void main(String[] args) { gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); // Use an executor service for asynchronous execution - ExecutorService executorService = Executors.newFixedThreadPool(2); + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + // Execute external services try { - // Execute Service A asynchronously - Future serviceFutureA = executorService.submit(() -> { - try { - Gateway serviceA = gatewayFactory.getGateway("ServiceA"); - serviceA.execute(); - } catch (Exception e) { - System.err.println("Error executing Service A: " + e.getMessage()); - } - }); - - // Execute Service B asynchronously - Future serviceFutureB = executorService.submit(() -> { - try { - Gateway serviceB = gatewayFactory.getGateway("ServiceB"); - serviceB.execute(); - } catch (Exception e) { - System.err.println("Error executing Service B: " + e.getMessage()); - } - }); - - // Execute Service C asynchronously - Future serviceFutureC = executorService.submit(() -> { - try { - Gateway serviceC = gatewayFactory.getGateway("ServiceC"); - serviceC.execute(); - } catch (Exception e) { - System.err.println("Error executing Service C: " + e.getMessage()); - } - }); - - // Wait for both tasks to complete - try { - serviceFutureA.get(); - serviceFutureB.get(); - serviceFutureC.get(); - } catch (InterruptedException e) { - System.err.println("Error in the main client: " + e.getMessage()); - Thread.currentThread().interrupt(); - } finally { - executorService.shutdown(); - } - } catch (Exception e) { - System.err.println("Error in the main client: " + e.getMessage()); - Thread.currentThread().interrupt(); - } finally { - executorService.shutdown(); + serviceA.execute(); + serviceB.execute(); + serviceC.execute(); + } catch (InterruptedException e) { + e.printStackTrace(); } } } From 09e3ecd69e0d519605f9ea5384b11f74fe3f2f8a Mon Sep 17 00:00:00 2001 From: Finn Date: Thu, 26 Oct 2023 00:53:50 +1100 Subject: [PATCH 17/21] Bug fixed and update README.md --- gateway/README.md | 54 +++++-------------- .../main/java/com/iluwatar/gateway/App.java | 5 +- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index 66c0637a6ef5..47506d12df14 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -79,7 +79,10 @@ To operate these external services, Here's the `App` class: ```java public class App { - public static void main(String[] args) { + /** + * Simulate an application calling external services. + */ + public static void main(String[] args) throws Exception { GatewayFactory gatewayFactory = new GatewayFactory(); // Register different gateways @@ -88,47 +91,18 @@ public class App { gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); // Use an executor service for asynchronous execution - ExecutorService executorService = Executors.newFixedThreadPool(2); + Gateway serviceA = gatewayFactory.getGateway("ServiceA"); + Gateway serviceB = gatewayFactory.getGateway("ServiceB"); + Gateway serviceC = gatewayFactory.getGateway("ServiceC"); + // Execute external services try { - // Execute Service A asynchronously - Future serviceAFuture = executorService.submit(() -> { - try { - Gateway serviceA = gatewayFactory.getGateway("ServiceA"); - serviceA.execute(); - } catch (Exception e) { - System.err.println("Error executing Service A: " + e.getMessage()); - } - }); - - // Execute Service B asynchronously - Future serviceBFuture = executorService.submit(() -> { - try { - Gateway serviceB = gatewayFactory.getGateway("ServiceB"); - serviceB.execute(); - } catch (Exception e) { - System.err.println("Error executing Service B: " + e.getMessage()); - } - }); - - // Execute Service C asynchronously - Future servicecFuture = executorService.submit(() -> { - try { - Gateway serviceC = gatewayFactory.getGateway("ServiceC"); - serviceC.execute(); - } catch (Exception e) { - System.err.println("Error executing Service C: " + e.getMessage()); - } - }); - - // Wait for both tasks to complete - serviceAFuture.get(); - serviceBFuture.get(); - servicecFuture.get(); - } catch (Exception e) { - System.err.println("Error in the main client: " + e.getMessage()); - } finally { - executorService.shutown(); + serviceA.execute(); + serviceB.execute(); + serviceC.execute(); + } catch (ThreadDeath e) { + System.out.println("Interrupted!" + e); + throw e; } } } diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index 6aa5edb1d563..f939f8aebda2 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -54,8 +54,9 @@ public static void main(String[] args) throws Exception { serviceA.execute(); serviceB.execute(); serviceC.execute(); - } catch (InterruptedException e) { - e.printStackTrace(); + } catch (ThreadDeath e) { + System.out.println("Interrupted!" + e); + throw e; } } } From 9e2ba364af8495c84cdb5d78797d3441b082d793 Mon Sep 17 00:00:00 2001 From: Finn Date: Sat, 28 Oct 2023 18:00:10 +1100 Subject: [PATCH 18/21] update APP.java --- gateway/src/main/java/com/iluwatar/gateway/App.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index f939f8aebda2..cca64a066b2b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -44,7 +44,7 @@ public static void main(String[] args) throws Exception { gatewayFactory.registerGateway("ServiceB", new ExternalServiceB()); gatewayFactory.registerGateway("ServiceC", new ExternalServiceC()); - // Use an executor service for asynchronous execution + // Use an executor service for execution Gateway serviceA = gatewayFactory.getGateway("ServiceA"); Gateway serviceB = gatewayFactory.getGateway("ServiceB"); Gateway serviceC = gatewayFactory.getGateway("ServiceC"); From f31a00c268889b2c6b7690e07847df7247725999 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 3 Jan 2024 18:22:06 +1100 Subject: [PATCH 19/21] update gateway pattern --- facade/README.md | 2 +- gateway/README.md | 1 - .../main/java/com/iluwatar/gateway/App.java | 21 ++++++++++++------- .../iluwatar/gateway/ExternalServiceA.java | 5 ++++- .../iluwatar/gateway/ExternalServiceB.java | 5 ++++- .../iluwatar/gateway/ExternalServiceC.java | 5 ++++- 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/facade/README.md b/facade/README.md index 4efa8f7b76c7..e015db37b52d 100644 --- a/facade/README.md +++ b/facade/README.md @@ -214,7 +214,7 @@ communicate with each other solely through their facades. ## Tutorials -*[DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) +* [DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) * [Refactoring Guru](https://refactoring.guru/design-patterns/facade) * [GeekforGeeks](https://www.geeksforgeeks.org/facade-design-pattern-introduction/) * [Tutorialspoint](https://www.tutorialspoint.com/design_pattern/facade_pattern.htm) diff --git a/gateway/README.md b/gateway/README.md index 47506d12df14..f1152ec6cfb4 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -3,7 +3,6 @@ title: Gateway category: Structural language: en tag: - - Gang of Four - Decoupling diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index cca64a066b2b..49b4f6b58dd5 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,14 +24,20 @@ */ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** - * The App class serves as the main entry point for the application implementing the Gateway design pattern. - * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the - * execution of various services asynchronously. + * The Gateway design pattern is a structural design pattern that provides an interface to a set of services + * in a subsystem. It involves creating a Gateway interface that serves as a common entry point for interacting + * with various services, and concrete implementations of this interface for different external services. * - *

In this example, there are three virtual service. GateFactory is the factory class and it provides a method - * to create different kinds of external services. + *

In this example, there are three virtual service. GateFactory is the factory class, and it provides a method + * to create different kinds of external services. ExternalServiceA, ExternalServiceB, and ExternalServiceC are concrete + * implementations of the Gateway interface. Each service provides its own implementation of the execute() method. + * The interface in App class is the common interface for all external services. It calls execute() method in different + * classes that represents the functionality to be executed by each service. */ +@Slf4j public class App { /** * Simulate an application calling external services. @@ -55,8 +61,7 @@ public static void main(String[] args) throws Exception { serviceB.execute(); serviceC.execute(); } catch (ThreadDeath e) { - System.out.println("Interrupted!" + e); + LOGGER.info("Interrupted!" + e); throw e; } - } -} + }} diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java index c467e1fe009b..c14617089790 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java @@ -25,13 +25,16 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** * ExternalServiceA is one of external services. */ +@Slf4j class ExternalServiceA implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service A"); + LOGGER.info("Executing Service A"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java index 144c9b6b2536..153cfc5b2d4c 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java @@ -25,13 +25,16 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** * ExternalServiceB is one of external services. */ +@Slf4j class ExternalServiceB implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service B"); + LOGGER.info("Executing Service B"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java index 067d4917040a..7b6d2c6fd324 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java @@ -25,13 +25,16 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** * ExternalServiceC is one of external services. */ +@Slf4j class ExternalServiceC implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service C"); + LOGGER.info("Executing Service C"); // Simulate a time-consuming task Thread.sleep(1000); } From c29e050662a2c0212a0c49217b6d90947eca7a85 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 3 Jan 2024 18:25:48 +1100 Subject: [PATCH 20/21] Revert "update gateway pattern" This reverts commit f31a00c268889b2c6b7690e07847df7247725999. --- facade/README.md | 2 +- gateway/README.md | 1 + .../main/java/com/iluwatar/gateway/App.java | 21 +++++++------------ .../iluwatar/gateway/ExternalServiceA.java | 5 +---- .../iluwatar/gateway/ExternalServiceB.java | 5 +---- .../iluwatar/gateway/ExternalServiceC.java | 5 +---- 6 files changed, 13 insertions(+), 26 deletions(-) diff --git a/facade/README.md b/facade/README.md index e015db37b52d..4efa8f7b76c7 100644 --- a/facade/README.md +++ b/facade/README.md @@ -214,7 +214,7 @@ communicate with each other solely through their facades. ## Tutorials -* [DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) +*[DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) * [Refactoring Guru](https://refactoring.guru/design-patterns/facade) * [GeekforGeeks](https://www.geeksforgeeks.org/facade-design-pattern-introduction/) * [Tutorialspoint](https://www.tutorialspoint.com/design_pattern/facade_pattern.htm) diff --git a/gateway/README.md b/gateway/README.md index f1152ec6cfb4..47506d12df14 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -3,6 +3,7 @@ title: Gateway category: Structural language: en tag: + - Gang of Four - Decoupling diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index 49b4f6b58dd5..cca64a066b2b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,20 +24,14 @@ */ package com.iluwatar.gateway; -import lombok.extern.slf4j.Slf4j; - /** - * The Gateway design pattern is a structural design pattern that provides an interface to a set of services - * in a subsystem. It involves creating a Gateway interface that serves as a common entry point for interacting - * with various services, and concrete implementations of this interface for different external services. + * The App class serves as the main entry point for the application implementing the Gateway design pattern. + * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the + * execution of various services asynchronously. * - *

In this example, there are three virtual service. GateFactory is the factory class, and it provides a method - * to create different kinds of external services. ExternalServiceA, ExternalServiceB, and ExternalServiceC are concrete - * implementations of the Gateway interface. Each service provides its own implementation of the execute() method. - * The interface in App class is the common interface for all external services. It calls execute() method in different - * classes that represents the functionality to be executed by each service. + *

In this example, there are three virtual service. GateFactory is the factory class and it provides a method + * to create different kinds of external services. */ -@Slf4j public class App { /** * Simulate an application calling external services. @@ -61,7 +55,8 @@ public static void main(String[] args) throws Exception { serviceB.execute(); serviceC.execute(); } catch (ThreadDeath e) { - LOGGER.info("Interrupted!" + e); + System.out.println("Interrupted!" + e); throw e; } - }} + } +} diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java index c14617089790..c467e1fe009b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java @@ -25,16 +25,13 @@ package com.iluwatar.gateway; -import lombok.extern.slf4j.Slf4j; - /** * ExternalServiceA is one of external services. */ -@Slf4j class ExternalServiceA implements Gateway { @Override public void execute() throws Exception { - LOGGER.info("Executing Service A"); + System.out.println("Executing Service A"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java index 153cfc5b2d4c..144c9b6b2536 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java @@ -25,16 +25,13 @@ package com.iluwatar.gateway; -import lombok.extern.slf4j.Slf4j; - /** * ExternalServiceB is one of external services. */ -@Slf4j class ExternalServiceB implements Gateway { @Override public void execute() throws Exception { - LOGGER.info("Executing Service B"); + System.out.println("Executing Service B"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java index 7b6d2c6fd324..067d4917040a 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java @@ -25,16 +25,13 @@ package com.iluwatar.gateway; -import lombok.extern.slf4j.Slf4j; - /** * ExternalServiceC is one of external services. */ -@Slf4j class ExternalServiceC implements Gateway { @Override public void execute() throws Exception { - LOGGER.info("Executing Service C"); + System.out.println("Executing Service C"); // Simulate a time-consuming task Thread.sleep(1000); } From 7f1e7195471b17d880bdc6f38ecf5b1918254c88 Mon Sep 17 00:00:00 2001 From: Finn Date: Wed, 3 Jan 2024 18:36:46 +1100 Subject: [PATCH 21/21] update gateway pattern --- gateway/README.md | 1 - .../main/java/com/iluwatar/gateway/App.java | 18 ++++++++++++------ .../com/iluwatar/gateway/ExternalServiceA.java | 6 +++++- .../com/iluwatar/gateway/ExternalServiceB.java | 5 ++++- .../com/iluwatar/gateway/ExternalServiceC.java | 5 ++++- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/gateway/README.md b/gateway/README.md index 47506d12df14..f1152ec6cfb4 100644 --- a/gateway/README.md +++ b/gateway/README.md @@ -3,7 +3,6 @@ title: Gateway category: Structural language: en tag: - - Gang of Four - Decoupling diff --git a/gateway/src/main/java/com/iluwatar/gateway/App.java b/gateway/src/main/java/com/iluwatar/gateway/App.java index cca64a066b2b..811cd4f7cc3b 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/App.java +++ b/gateway/src/main/java/com/iluwatar/gateway/App.java @@ -24,14 +24,20 @@ */ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** - * The App class serves as the main entry point for the application implementing the Gateway design pattern. - * It demonstrates the use of the GatewayFactory to manage different gateway implementations, allowing for the - * execution of various services asynchronously. + * the Gateway design pattern is a structural design pattern that provides a unified interface to a set of + * interfaces in a subsystem. It involves creating a Gateway interface that serves as a common entry point for + * interacting with various services, and concrete implementations of this interface for different external services. * - *

In this example, there are three virtual service. GateFactory is the factory class and it provides a method - * to create different kinds of external services. + *

In this example, GateFactory is the factory class, and it provides a method to create different kinds of external + * services. ExternalServiceA, B, and C are virtual implementations of the external services. Each service provides its + * own implementation of the execute() method. The Gateway interface is the common interface for all external services. + * The App class serves as the main entry point for the application implementing the Gateway design pattern. Through + * the Gateway interface, the App class could call each service with much less complexity. */ +@Slf4j public class App { /** * Simulate an application calling external services. @@ -55,7 +61,7 @@ public static void main(String[] args) throws Exception { serviceB.execute(); serviceC.execute(); } catch (ThreadDeath e) { - System.out.println("Interrupted!" + e); + LOGGER.info("Interrupted!" + e); throw e; } } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java index c467e1fe009b..d6437e61197f 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java @@ -25,13 +25,17 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; + /** * ExternalServiceA is one of external services. */ +@Slf4j class ExternalServiceA implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service A"); + LOGGER.info("Executing Service A"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java index 144c9b6b2536..153cfc5b2d4c 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceB.java @@ -25,13 +25,16 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** * ExternalServiceB is one of external services. */ +@Slf4j class ExternalServiceB implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service B"); + LOGGER.info("Executing Service B"); // Simulate a time-consuming task Thread.sleep(1000); } diff --git a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java index 067d4917040a..7b6d2c6fd324 100644 --- a/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java +++ b/gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java @@ -25,13 +25,16 @@ package com.iluwatar.gateway; +import lombok.extern.slf4j.Slf4j; + /** * ExternalServiceC is one of external services. */ +@Slf4j class ExternalServiceC implements Gateway { @Override public void execute() throws Exception { - System.out.println("Executing Service C"); + LOGGER.info("Executing Service C"); // Simulate a time-consuming task Thread.sleep(1000); }