Skip to content

Commit 35bd486

Browse files
authored
Merge branch 'iluwatar:master' into master
2 parents 43d2f79 + c0e20ec commit 35bd486

File tree

9 files changed

+140
-71
lines changed

9 files changed

+140
-71
lines changed

gateway/README.md

+43-22
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,35 @@
11
---
22
title: Gateway
3-
category: Structural
3+
category: Integration
44
language: en
55
tag:
6-
- Decoupling
7-
6+
- API design
7+
- Data access
8+
- Decoupling
9+
- Enterprise patterns
810
---
911

12+
## Also known as
13+
14+
* Service Gateway
15+
1016
## Intent
1117

12-
Provide a interface to access a set of external systems or functionalities. Gateway provides a simple uniform view of
13-
external resources to the internals of an application.
18+
The Gateway design pattern aims to encapsulate the interaction with a remote service or external system, providing a simpler and more unified API to the rest of the application.
1419

1520
## Explanation
1621

1722
Real-world example
1823

19-
> Gateway acts like a real front gate of a certain city. The people inside the city are called
20-
> internal system, and different outside cities are called external services. The gateway is here
21-
> to provide access for internal system to different external services.
24+
> 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.
2225
2326
In plain words
2427

2528
> Gateway can provide an interface which lets internal system to utilize external service.
2629
2730
Wikipedia says
2831

29-
> A server that acts as an API front-end, receives API requests, enforces throttling and security
30-
> policies, passes requests to the back-end service and then passes the response back to the requester.
32+
> 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.
3133
3234
**Programmatic Example**
3335

@@ -117,33 +119,52 @@ interface Gateway {
117119
Program output:
118120

119121
```java
120-
Executing Service A
121-
Executing Service B
122-
Executing Service C
122+
Executing Service A
123+
Executing Service B
124+
Executing Service C
123125
```
124126

125127
## Class diagram
126128

127-
![alt text](./etc/gateway.urm.png "gateway")
129+
![Gateway](./etc/gateway.urm.png "gateway")
128130

129131
## Applicability
130132

131-
Use the Gateway pattern
132-
133-
* To access an aggregate object's contents without exposing its internal representation.
134-
* To integration with multiple external services or APIs.
135-
* To provide a uniform interface for traversing different aggregate structures.
133+
Use the Gateway pattern when you need to integrate with remote services or APIs, and you want to minimize the coupling between your application and external systems. It is particularly useful in microservices architectures where different services need to communicate through well-defined APIs.
136134

137135
## Tutorials
138136

139137
* [Pattern: API Gateway / Backends for Frontends](https://microservices.io/patterns/apigateway.html)
140138

141139
## Known uses
142140

143-
* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/)
144141
* [10 most common use cases of an API Gateway](https://apisix.apache.org/blog/2022/10/27/ten-use-cases-api-gateway/)
142+
* API Gateways in Microservices: Acts as an intermediary that processes incoming requests from clients, directing them to appropriate services within a microservices architecture.
143+
* Database Gateways: Provides a unified interface to access data from various database systems, hiding the specifics of database querying and data retrieval.
144+
145+
## Consequences
146+
147+
Benefits:
148+
149+
* Reduces complexity by hiding the details of the external API or service behind a simpler interface.
150+
* Promotes loose coupling between the application and its dependencies on external systems.
151+
* Makes the system easier to test and maintain.
152+
153+
Trade-offs:
154+
155+
* Introduces an additional layer that could potentially impact performance.
156+
* Requires careful design to avoid creating a monolithic gateway that becomes a bottleneck.
157+
158+
## Related Patterns
159+
160+
* [Facade](https://java-design-patterns.com/patterns/facade/): Similar to Gateway in abstracting complex subsystems, but Gateway specifically targets external or remote interfaces.
161+
* [Adapter](https://java-design-patterns.com/patterns/adapter/): While both patterns provide a different interface to a subsystem, Gateway focuses more on networked data sources and services.
162+
* [Proxy](https://java-design-patterns.com/patterns/proxy/): Often used together, as both can control and manage access to another object, but Gateway specifically deals with external services.
163+
* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/): Often considered a specialization of the Gateway pattern, it specifically manages API requests and routes them to the appropriate services within a backend system.
145164

146165
## Credits
147166

148-
* [Gateway](https://martinfowler.com/articles/gateway-pattern.html)
149-
* [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)
167+
* [Gateway - Martin Fowler](https://martinfowler.com/articles/gateway-pattern.html)
168+
* [What is the difference between Facade and Gateway design patterns? - Stack Overflow](https://stackoverflow.com/questions/4422211/what-is-the-difference-between-facade-and-gateway-design-patterns)
169+
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://amzn.to/3WcFVui)
170+
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)

gateway/src/main/java/com/iluwatar/gateway/ExternalServiceA.java

-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727

2828
import lombok.extern.slf4j.Slf4j;
29-
import org.slf4j.Logger;
3029

3130
/**
3231
* ExternalServiceA is one of external services.
@@ -40,4 +39,3 @@ public void execute() throws Exception {
4039
Thread.sleep(1000);
4140
}
4241
}
43-

gateway/src/main/java/com/iluwatar/gateway/ExternalServiceC.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void execute() throws Exception {
3939
Thread.sleep(1000);
4040
}
4141

42-
public void error() throws Exception {
42+
public void error() {
4343
// Simulate an exception
4444
throw new RuntimeException("Service C encountered an error");
4545
}

gateway/src/test/java/com/iluwatar/gateway/ServiceFactoryTest.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@
2525
package com.iluwatar.gateway;
2626

2727

28-
import org.junit.Before;
29-
import org.junit.Test;
28+
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertFalse;
30+
import static org.junit.Assert.assertNull;
31+
import static org.junit.Assert.assertTrue;
3032

3133
import java.util.concurrent.CountDownLatch;
3234
import java.util.concurrent.ExecutorService;
3335
import java.util.concurrent.Executors;
3436
import java.util.concurrent.atomic.AtomicBoolean;
35-
36-
import static org.junit.Assert.assertEquals;
37-
import static org.junit.Assert.assertTrue;
38-
import static org.junit.jupiter.api.Assertions.assertTrue;
37+
import org.junit.Before;
38+
import org.junit.Test;
3939

4040
public class ServiceFactoryTest {
4141
private GatewayFactory gatewayFactory;
@@ -65,7 +65,7 @@ public void testGatewayFactoryRegistrationAndRetrieval() {
6565
@Test
6666
public void testGatewayFactoryRegistrationWithNonExistingKey() {
6767
Gateway nonExistingService = gatewayFactory.getGateway("NonExistingService");
68-
assertEquals(null, nonExistingService);
68+
assertNull(nonExistingService);
6969
}
7070

7171
@Test
@@ -88,6 +88,6 @@ public void testGatewayFactoryConcurrency() throws InterruptedException {
8888
}
8989

9090
latch.await();
91-
assertTrue("This should not fail", !failed.get());
91+
assertFalse("This should not fail", failed.get());
9292
}
9393
}

guarded-suspension/README.md

+69-22
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,51 @@ title: Guarded Suspension
33
category: Concurrency
44
language: en
55
tag:
6-
- Decoupling
6+
- Asynchronous
7+
- Decoupling
8+
- Resource management
9+
- Synchronization
10+
- Thread management
711
---
812

9-
## Intent
10-
Use Guarded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state.
13+
## Also known as
1114

12-
## Class diagram
13-
![Guarded Suspension diagram](./etc/guarded-suspension.png)
15+
* Conditional Block
16+
* Suspended Execution
1417

15-
## Applicability
16-
Use Guarded Suspension pattern when the developer knows that the method execution will be blocked for a finite period of time
18+
## Intent
19+
20+
The Guarded Suspension pattern manages operations that require both a lock and a condition to proceed, allowing a thread to wait for an appropriate condition while being efficient with resource use.
1721

1822
## Explanation
1923

2024
Real world example
2125

22-
> When we reserve a dining room online and arrive to find it unready, the manager has it cleaned while we wait.
23-
> Once ready, we're escorted to the room. This process exemplifies the Guarded Suspension pattern.
26+
> When we book a dining room online and arrive to find it not yet prepared, the manager arranges for it to be cleaned while we wait. Once the room is ready, we are then escorted to it. This scenario illustrates the Guarded Suspension pattern, where our access to the room is contingent upon a specific condition being met—namely, the room being cleaned.
2427
2528
In plain words
2629

2730
> Guarded Suspension pattern is used when one thread waits for the result of another thread's execution.
2831
2932
Wikipedia says
3033

31-
> In concurrent programming, Guarded Suspension manages operations requiring a lock
32-
> and a precondition, delaying execution until the precondition is met.
34+
> In concurrent programming, Guarded Suspension manages operations requiring a lock and a precondition, delaying execution until the precondition is met.
3335
3436
**Programmatic Example**
3537

36-
The `GuardedQueue` class encapsulates a queue, and provides two synchronized methods, `get` and `put`.
37-
The `get` method waits if the queue is empty, and the `put` method adds an item to the queue and notifies waiting threads:
38+
The `GuardedQueue` class encapsulates a queue, and provides two synchronized methods, `get` and `put`. The `get` method waits if the queue is empty, and the `put` method adds an item to the queue and notifies waiting threads:
3839

3940
```java
41+
@Slf4j
4042
public class GuardedQueue {
41-
private final Queue<Integer> sourceList = new LinkedList<>();
43+
private final Queue<Integer> sourceList = new LinkedList<>();
4244

4345
public synchronized Integer get() {
4446
while (sourceList.isEmpty()) {
4547
try {
4648
wait();
4749
} catch (InterruptedException e) {
48-
e.printStackTrace();
50+
LOGGER.error("Error occurred: ", e);
4951
}
5052
}
5153
return sourceList.peek();
@@ -56,19 +58,23 @@ private final Queue<Integer> sourceList = new LinkedList<>();
5658
notify();
5759
}
5860
}
61+
```
5962

63+
Here is the `App` class driving the example.
64+
65+
```java
6066
public class App {
61-
public static void main(String[] args) {
62-
GuardedQueue guardedQueue = new GuardedQueue();
63-
ExecutorService executorService = Executors.newFixedThreadPool(3);
67+
public static void main(String[] args) {
68+
GuardedQueue guardedQueue = new GuardedQueue();
69+
ExecutorService executorService = Executors.newFixedThreadPool(3);
6470

6571
// Here we create the first thread which is supposed to get from guardedQueue
6672
executorService.execute(guardedQueue::get);
6773

6874
try {
6975
Thread.sleep(2000);
7076
} catch (InterruptedException e) {
71-
e.printStackTrace();
77+
LOGGER.error("Error occurred: ", e);
7278
}
7379

7480
// Here we create the second thread which is supposed to put to guardedQueue
@@ -80,13 +86,54 @@ ExecutorService executorService = Executors.newFixedThreadPool(3);
8086
try {
8187
executorService.awaitTermination(30, TimeUnit.SECONDS);
8288
} catch (InterruptedException e) {
83-
e.printStackTrace();
89+
LOGGER.error("Error occurred: ", e);
8490
}
8591
}
8692
}
8793
```
8894

95+
Executing the example yields:
96+
97+
```
98+
19:22:58.984 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- waiting
99+
19:23:00.993 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- putting
100+
19:23:00.994 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- notifying
101+
19:23:00.994 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- getting
102+
```
103+
104+
## Class diagram
105+
106+
![Guarded Suspension diagram](./etc/guarded-suspension.png)
107+
108+
## Applicability
109+
110+
This pattern is used in scenarios where a thread needs to wait for certain conditions to be met before it can proceed, ensuring that resources are utilized only when necessary and reducing the overhead of busy waiting.
111+
112+
## Known Uses
113+
114+
* Network servers waiting for client requests.
115+
* Producer-consumer scenarios where the consumer must wait for the producer to provide data.
116+
* Event-driven applications where actions are triggered only after specific events have occurred.
117+
118+
## Consequences
119+
120+
Benefits:
121+
122+
* Reduces CPU consumption by preventing busy waiting.
123+
* Increases system responsiveness by synchronizing actions to the availability of necessary conditions or resources.
124+
125+
Trade-offs:
126+
127+
* Complexity in implementation, especially when multiple conditions need to be managed.
128+
* Potential for deadlocks if not carefully managed.
129+
130+
## Related Patterns
131+
132+
* Monitor Object: Both patterns manage the synchronization of threads based on conditions. Guarded Suspension specifically deals with suspending threads until conditions are met, while Monitor Object encapsulates condition and mutual exclusion handling.
133+
* Producer-Consumer: Often implemented using Guarded Suspension to handle waiting consumers and producers efficiently.
134+
* Balking: Similar to Guarded Suspension, Balking is used when a thread checks a condition and only proceeds if the condition is favorable; if not, it immediately returns or bails out. This pattern complements Guarded Suspension by managing actions based on immediate condition checks without waiting.
89135

90-
## Related patterns
136+
## Credits
91137

92-
* Balking
138+
* [Java Concurrency in Practice](https://amzn.to/3JxnXek)
139+
* [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/49Ke1c9)

guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/App.java

+12-11
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,20 @@
2626

2727
import java.util.concurrent.Executors;
2828
import java.util.concurrent.TimeUnit;
29+
import lombok.extern.slf4j.Slf4j;
2930

3031
/**
31-
* Created by robertt240 on 1/26/17.
32-
*
33-
* <p>Guarded-suspension is a concurrent design pattern for handling situation when to execute some
32+
* Guarded-suspension is a concurrent design pattern for handling situation when to execute some
3433
* action we need condition to be satisfied.
35-
*
36-
* <p>Implementation is based on GuardedQueue, which has two methods: get and put, the condition is
37-
* that we cannot get from empty queue so when thread attempt to break the condition we invoke
38-
* Object's wait method on him and when other thread put an element to the queue he notify the
39-
* waiting one that now he can get from queue.
34+
* The implementation utilizes a GuardedQueue, which features two primary methods: `get` and `put`.
35+
* The key condition governing these operations is that elements cannot be retrieved (`get`) from
36+
* an empty queue. When a thread attempts to retrieve an element under this condition, it triggers
37+
* the invocation of the `wait` method from the Object class, causing the thread to pause.
38+
* Conversely, when an element is added (`put`) to the queue by another thread, it invokes the
39+
* `notify` method. This notifies the waiting thread that it can now successfully retrieve an
40+
* element from the queue.
4041
*/
42+
@Slf4j
4143
public class App {
4244
/**
4345
* Example pattern execution.
@@ -56,7 +58,7 @@ public static void main(String[] args) {
5658
try {
5759
Thread.sleep(2000);
5860
} catch (InterruptedException e) {
59-
e.printStackTrace();
61+
LOGGER.error("Error occurred: ", e);
6062
}
6163
// now we execute second thread which will put number to guardedQueue
6264
// and notify first thread that it could get
@@ -65,8 +67,7 @@ public static void main(String[] args) {
6567
try {
6668
executorService.awaitTermination(30, TimeUnit.SECONDS);
6769
} catch (InterruptedException e) {
68-
e.printStackTrace();
70+
LOGGER.error("Error occurred: ", e);
6971
}
7072
}
71-
7273
}

guarded-suspension/src/main/java/com/iluwatar/guarded/suspension/GuardedQueue.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public GuardedQueue() {
4444
}
4545

4646
/**
47-
* Get the last element of the queue is exists.
47+
* Get the last element of the queue if exists.
4848
*
4949
* @return last element of a queue if queue is not empty
5050
*/
@@ -54,7 +54,7 @@ public synchronized Integer get() {
5454
LOGGER.info("waiting");
5555
wait();
5656
} catch (InterruptedException e) {
57-
e.printStackTrace();
57+
LOGGER.error("Error occurred: ", e);
5858
}
5959
}
6060
LOGGER.info("getting");

0 commit comments

Comments
 (0)