Skip to content

Commit

Permalink
Merge branch 'iluwatar:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Ehspresso authored Apr 23, 2024
2 parents 43d2f79 + c0e20ec commit 35bd486
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 71 deletions.
65 changes: 43 additions & 22 deletions gateway/README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,35 @@
---
title: Gateway
category: Structural
category: Integration
language: en
tag:
- Decoupling

- API design
- Data access
- Decoupling
- Enterprise patterns
---

## Also known as

* Service Gateway

## 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.
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.

## 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.
> 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.
> 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**

Expand Down Expand Up @@ -117,33 +119,52 @@ interface Gateway {
Program output:

```java
Executing Service A
Executing Service B
Executing Service C
Executing Service A
Executing Service B
Executing Service C
```

## Class diagram

![alt text](./etc/gateway.urm.png "gateway")
![Gateway](./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.
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.

## 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/)
* API Gateways in Microservices: Acts as an intermediary that processes incoming requests from clients, directing them to appropriate services within a microservices architecture.
* Database Gateways: Provides a unified interface to access data from various database systems, hiding the specifics of database querying and data retrieval.

## Consequences

Benefits:

* Reduces complexity by hiding the details of the external API or service behind a simpler interface.
* Promotes loose coupling between the application and its dependencies on external systems.
* Makes the system easier to test and maintain.

Trade-offs:

* Introduces an additional layer that could potentially impact performance.
* Requires careful design to avoid creating a monolithic gateway that becomes a bottleneck.

## Related Patterns

* [Facade](https://java-design-patterns.com/patterns/facade/): Similar to Gateway in abstracting complex subsystems, but Gateway specifically targets external or remote interfaces.
* [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.
* [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.
* [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.

## 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)
* [Gateway - Martin Fowler](https://martinfowler.com/articles/gateway-pattern.html)
* [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)
* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://amzn.to/3WcFVui)
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@


import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

/**
* ExternalServiceA is one of external services.
Expand All @@ -40,4 +39,3 @@ public void execute() throws Exception {
Thread.sleep(1000);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public void execute() throws Exception {
Thread.sleep(1000);
}

public void error() throws Exception {
public void error() {
// Simulate an exception
throw new RuntimeException("Service C encountered an error");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
package com.iluwatar.gateway;


import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

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;
import org.junit.Before;
import org.junit.Test;

public class ServiceFactoryTest {
private GatewayFactory gatewayFactory;
Expand Down Expand Up @@ -65,7 +65,7 @@ public void testGatewayFactoryRegistrationAndRetrieval() {
@Test
public void testGatewayFactoryRegistrationWithNonExistingKey() {
Gateway nonExistingService = gatewayFactory.getGateway("NonExistingService");
assertEquals(null, nonExistingService);
assertNull(nonExistingService);
}

@Test
Expand All @@ -88,6 +88,6 @@ public void testGatewayFactoryConcurrency() throws InterruptedException {
}

latch.await();
assertTrue("This should not fail", !failed.get());
assertFalse("This should not fail", failed.get());
}
}
91 changes: 69 additions & 22 deletions guarded-suspension/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,51 @@ title: Guarded Suspension
category: Concurrency
language: en
tag:
- Decoupling
- Asynchronous
- Decoupling
- Resource management
- Synchronization
- Thread management
---

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

## Class diagram
![Guarded Suspension diagram](./etc/guarded-suspension.png)
* Conditional Block
* Suspended Execution

## Applicability
Use Guarded Suspension pattern when the developer knows that the method execution will be blocked for a finite period of time
## Intent

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.

## Explanation

Real world example

> When we reserve a dining room online and arrive to find it unready, the manager has it cleaned while we wait.
> Once ready, we're escorted to the room. This process exemplifies the Guarded Suspension pattern.
> 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.
In plain words

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

> In concurrent programming, Guarded Suspension manages operations requiring a lock
> and a precondition, delaying execution until the precondition is met.
> In concurrent programming, Guarded Suspension manages operations requiring a lock and a precondition, delaying execution until the precondition is met.
**Programmatic Example**

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:
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:

```java
@Slf4j
public class GuardedQueue {
private final Queue<Integer> sourceList = new LinkedList<>();
private final Queue<Integer> sourceList = new LinkedList<>();

public synchronized Integer get() {
while (sourceList.isEmpty()) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
LOGGER.error("Error occurred: ", e);
}
}
return sourceList.peek();
Expand All @@ -56,19 +58,23 @@ private final Queue<Integer> sourceList = new LinkedList<>();
notify();
}
}
```

Here is the `App` class driving the example.

```java
public class App {
public static void main(String[] args) {
GuardedQueue guardedQueue = new GuardedQueue();
ExecutorService executorService = Executors.newFixedThreadPool(3);
public static void main(String[] args) {
GuardedQueue guardedQueue = new GuardedQueue();
ExecutorService executorService = Executors.newFixedThreadPool(3);

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

try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
LOGGER.error("Error occurred: ", e);
}

// Here we create the second thread which is supposed to put to guardedQueue
Expand All @@ -80,13 +86,54 @@ ExecutorService executorService = Executors.newFixedThreadPool(3);
try {
executorService.awaitTermination(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
LOGGER.error("Error occurred: ", e);
}
}
}
```

Executing the example yields:

```
19:22:58.984 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- waiting
19:23:00.993 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- putting
19:23:00.994 [pool-1-thread-2] INFO com.iluwatar.guarded.suspension.GuardedQueue -- notifying
19:23:00.994 [pool-1-thread-1] INFO com.iluwatar.guarded.suspension.GuardedQueue -- getting
```

## Class diagram

![Guarded Suspension diagram](./etc/guarded-suspension.png)

## Applicability

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.

## Known Uses

* Network servers waiting for client requests.
* Producer-consumer scenarios where the consumer must wait for the producer to provide data.
* Event-driven applications where actions are triggered only after specific events have occurred.

## Consequences

Benefits:

* Reduces CPU consumption by preventing busy waiting.
* Increases system responsiveness by synchronizing actions to the availability of necessary conditions or resources.

Trade-offs:

* Complexity in implementation, especially when multiple conditions need to be managed.
* Potential for deadlocks if not carefully managed.

## Related Patterns

* 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.
* Producer-Consumer: Often implemented using Guarded Suspension to handle waiting consumers and producers efficiently.
* 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.

## Related patterns
## Credits

* Balking
* [Java Concurrency in Practice](https://amzn.to/3JxnXek)
* [Pattern-Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://amzn.to/49Ke1c9)
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,20 @@

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

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

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public GuardedQueue() {
}

/**
* Get the last element of the queue is exists.
* Get the last element of the queue if exists.
*
* @return last element of a queue if queue is not empty
*/
Expand All @@ -54,7 +54,7 @@ public synchronized Integer get() {
LOGGER.info("waiting");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
LOGGER.error("Error occurred: ", e);
}
}
LOGGER.info("getting");
Expand Down
Loading

0 comments on commit 35bd486

Please sign in to comment.