mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-10-14 06:17:55 +00:00
* Implement Gateway pattern * Fixed docstrings * Fixed README.md * Fixed App * Fixed pom.xml * Fixed pom.xml * Fixed pom.xml * Fixed pom.xml * fixed checkstyle errors and directory names * fixed pom.xml * fixed checkstyle errors * Bug fixed * Bug fixed * Bug fixed * Bug fixed and code improvement * Bug fixed and code improvement * Bug fixed and update README.md * update APP.java * update gateway pattern * Revert "update gateway pattern" This reverts commit f31a00c268889b2c6b7690e07847df7247725999. * update gateway pattern --------- Co-authored-by: Finn <u7552286@anu.edu.au>
This commit is contained in:
1 parent
ec80239e5e
commit
2d54709d1a
12 files changed
+642
No files matched your search
@@ -0,0 +1,150 @@
|
|||||||
|
---
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To operate these external services, Here's the `App` class:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public class App {
|
||||||
|
/**
|
||||||
|
* Simulate an application calling external services.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
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
|
||||||
|
Gateway serviceA = gatewayFactory.getGateway("ServiceA");
|
||||||
|
Gateway serviceB = gatewayFactory.getGateway("ServiceB");
|
||||||
|
Gateway serviceC = gatewayFactory.getGateway("ServiceC");
|
||||||
|
|
||||||
|
// Execute external services
|
||||||
|
try {
|
||||||
|
serviceA.execute();
|
||||||
|
serviceB.execute();
|
||||||
|
serviceC.execute();
|
||||||
|
} catch (ThreadDeath e) {
|
||||||
|
System.out.println("Interrupted!" + e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,43 @@
|
|||||||
|
@startuml GatewayPattern
|
||||||
|
package com.iluwatar.gateway{
|
||||||
|
class App {
|
||||||
|
+main(args: String[]): void
|
||||||
|
}
|
||||||
|
|
||||||
|
class GatewayFactory {
|
||||||
|
-gateways: Map<String, Gateway>
|
||||||
|
+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
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in 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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.iluwatar</groupId>
|
||||||
|
<artifactId>java-design-patterns</artifactId>
|
||||||
|
<version>1.26.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<artifactId>gateway</artifactId>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>com.iluwatar.gateway.App</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt).
|
||||||
|
*
|
||||||
|
* The MIT License
|
||||||
|
* Copyright © 2014-2022 Ilkka Seppälä
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in 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;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* <p>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.
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
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 execution
|
||||||
|
Gateway serviceA = gatewayFactory.getGateway("ServiceA");
|
||||||
|
Gateway serviceB = gatewayFactory.getGateway("ServiceB");
|
||||||
|
Gateway serviceC = gatewayFactory.getGateway("ServiceC");
|
||||||
|
|
||||||
|
// Execute external services
|
||||||
|
try {
|
||||||
|
serviceA.execute();
|
||||||
|
serviceB.execute();
|
||||||
|
serviceC.execute();
|
||||||
|
} catch (ThreadDeath e) {
|
||||||
|
LOGGER.info("Interrupted!" + e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
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 {
|
||||||
|
LOGGER.info("Executing Service A");
|
||||||
|
// Simulate a time-consuming task
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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.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");
|
||||||
|
// Simulate a time-consuming task
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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.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");
|
||||||
|
// Simulate a time-consuming task
|
||||||
|
Thread.sleep(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void error() throws Exception {
|
||||||
|
// Simulate an exception
|
||||||
|
throw new RuntimeException("Service C encountered an error");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package com.iluwatar.gateway;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service interface.
|
||||||
|
*/
|
||||||
|
interface Gateway {
|
||||||
|
void execute() throws Exception;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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.
|
||||||
|
*/
|
||||||
|
public class GatewayFactory {
|
||||||
|
private Map<String, Gateway> gateways = new HashMap<>();
|
||||||
|
|
||||||
|
public void registerGateway(String key, Gateway gateway) {
|
||||||
|
gateways.put(key, gateway);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gateway getGateway(String key) {
|
||||||
|
return gateways.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.iluwatar.gateway;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package com.iluwatar.gateway;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
import static org.junit.jupiter.api.Assertions.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");
|
||||||
|
|
||||||
|
// 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
|
||||||
|
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("This should not fail", !failed.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user