Compare commits
8 Commits
adapter-gr
...
all-contri
Author | SHA1 | Date | |
---|---|---|---|
f1ae059826 | |||
475df8867a | |||
be25c0b433 | |||
be59e50205 | |||
ec90320eda | |||
3126ad3106 | |||
e2ebb59fe7 | |||
d87e8cf10d |
@ -1568,6 +1568,33 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "karthikbhat13",
|
||||
"name": "karthikbhat13",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/22431014?v=4",
|
||||
"profile": "https://github.com/karthikbhat13",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mortezaadi",
|
||||
"name": "Morteza Adigozalpour",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1329687?v=4",
|
||||
"profile": "https://github.com/mortezaadi",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tan31989",
|
||||
"name": "Nagaraj Tantri",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3784194?v=4",
|
||||
"profile": "https://stackoverflow.com/users/308565/nagaraj-tantri",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
@ -10,7 +10,7 @@
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<br/>
|
||||
@ -333,6 +333,11 @@ This project is licensed under the terms of the MIT license.
|
||||
<td align="center"><a href="https://github.com/marlo2222"><img src="https://avatars.githubusercontent.com/u/40809563?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marlo Henrique</b></sub></a><br /><a href="#translation-marlo2222" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/AndriyPyzh"><img src="https://avatars.githubusercontent.com/u/57706635?v=4?s=100" width="100px;" alt=""/><br /><sub><b>AndriyPyzh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=AndriyPyzh" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/karthikbhat13"><img src="https://avatars.githubusercontent.com/u/22431014?v=4?s=100" width="100px;" alt=""/><br /><sub><b>karthikbhat13</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=karthikbhat13" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mortezaadi"><img src="https://avatars.githubusercontent.com/u/1329687?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Morteza Adigozalpour</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=mortezaadi" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://stackoverflow.com/users/308565/nagaraj-tantri"><img src="https://avatars.githubusercontent.com/u/3784194?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nagaraj Tantri</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=tan31989" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
|
@ -48,7 +48,7 @@ class AggregatorTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -48,7 +48,7 @@ class ApiGatewayTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,7 +68,7 @@ class ThreadAsyncExecutorTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,7 +46,7 @@ class DataBusTest {
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
120
fanout-fanin/README.md
Normal file
120
fanout-fanin/README.md
Normal file
@ -0,0 +1,120 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Fan-Out/Fan-In
|
||||
folder: fanout-fanin
|
||||
permalink: /patterns/fanout-fanin/
|
||||
categories: Integration
|
||||
language: en
|
||||
tags:
|
||||
- Microservices
|
||||
---
|
||||
|
||||
## Intent
|
||||
The pattern is used when a source system needs to run one or more long-running processes that will fetch some data.
|
||||
The source will not block itself waiting for the reply. <br> The pattern will run the same function in multiple
|
||||
services or machines to fetch the data. This is equivalent to invoking the function multiple times on different chunks of data.
|
||||
|
||||
## Explanation
|
||||
The FanOut/FanIn service will take in a list of requests and a consumer. Each request might complete at a different time.
|
||||
FanOut/FanIn service will accept the input params and returns the initial system an ID to acknowledge that the pattern
|
||||
service has received the requests. Now the caller will not wait or expect the result in the same connection.
|
||||
|
||||
Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time.
|
||||
These requests will be processed in different instances of the same function in different machines or services. As the
|
||||
requests get completed, a callback service everytime is called that transforms the result into a common single object format
|
||||
that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
The implementation provided has a list of numbers and end goal is to square the numbers and add them to a single result.
|
||||
`FanOutFanIn` class receives the list of numbers in the form of list of `SquareNumberRequest` and a `Consumer` instance
|
||||
that collects the results as the requests get over. `SquareNumberRequest` will square the number with a random delay
|
||||
to give the impression of a long-running process that can complete at any time. `Consumer` instance will add the results from
|
||||
different `SquareNumberRequest` that will come random time instances.
|
||||
|
||||
Let's look at `FanOutFanIn` class that fans out the requests in async processes.
|
||||
|
||||
```java
|
||||
public class FanOutFanIn {
|
||||
public static Long fanOutFanIn(
|
||||
final List<SquareNumberRequest> requests, final Consumer consumer) {
|
||||
|
||||
ExecutorService service = Executors.newFixedThreadPool(requests.size());
|
||||
|
||||
// fanning out
|
||||
List<CompletableFuture<Void>> futures =
|
||||
requests.stream()
|
||||
.map(
|
||||
request ->
|
||||
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
||||
|
||||
return consumer.getSumOfSquaredNumbers().get();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`Consumer` is used a callback class that will be called when a request is completed. This will aggregate
|
||||
the result from all requests.
|
||||
|
||||
```java
|
||||
public class Consumer {
|
||||
|
||||
private final AtomicLong sumOfSquaredNumbers;
|
||||
|
||||
Consumer(Long init) {
|
||||
sumOfSquaredNumbers = new AtomicLong(init);
|
||||
}
|
||||
|
||||
public Long add(final Long num) {
|
||||
return sumOfSquaredNumbers.addAndGet(num);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Request is represented as a `SquareNumberRequest` that squares the number with random delay and calls the
|
||||
`Consumer` once it is squared.
|
||||
|
||||
```java
|
||||
public class SquareNumberRequest {
|
||||
|
||||
private final Long number;
|
||||
public void delayedSquaring(final Consumer consumer) {
|
||||
|
||||
var minTimeOut = 5000L;
|
||||
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
var randomTimeOut = secureRandom.nextInt(2000);
|
||||
|
||||
try {
|
||||
// this will make the thread sleep from 5-7s.
|
||||
Thread.sleep(minTimeOut + randomTimeOut);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Exception while sleep ", e);
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
consumer.add(number * number);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Class diagram
|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
Use this pattern when you can divide the workload into multiple chunks that can be dealt with separately.
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Aggregator Microservices](https://java-design-patterns.com/patterns/aggregator-microservices/)
|
||||
* [API Gateway](https://java-design-patterns.com/patterns/api-gateway/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Understanding Azure Durable Functions - Part 8: The Fan Out/Fan In Pattern](http://dontcodetired.com/blog/post/Understanding-Azure-Durable-Functions-Part-8-The-Fan-OutFan-In-Pattern)
|
||||
* [Fan-out/fan-in scenario in Durable Functions - Cloud backup example](https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-cloud-backup)
|
||||
* [Understanding the Fan-Out/Fan-In API Integration Pattern](https://dzone.com/articles/understanding-the-fan-out-fan-in-api-integration-p)
|
BIN
fanout-fanin/etc/fanout-fanin.png
Normal file
BIN
fanout-fanin/etc/fanout-fanin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
39
fanout-fanin/etc/fanout-fanin.urm.puml
Normal file
39
fanout-fanin/etc/fanout-fanin.urm.puml
Normal file
@ -0,0 +1,39 @@
|
||||
@startuml
|
||||
package com.iluwatar.fanout.fanin {
|
||||
class App {
|
||||
- LOGGER : Logger {static}
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
class Consumer {
|
||||
- sumOfSquaredNumbers : AtomicLong
|
||||
~ Consumer(init : Long)
|
||||
+ add(num : Long) : Long
|
||||
+ getSumOfSquaredNumbers() : AtomicLong
|
||||
}
|
||||
class FanOutFanIn {
|
||||
+ FanOutFanIn()
|
||||
+ fanOutFanIn(requests : List<SquareNumberRequest>, consumer : Consumer) : Long {static}
|
||||
}
|
||||
class SquareNumberRequest {
|
||||
- LOGGER : Logger {static}
|
||||
- number : Long
|
||||
+ SquareNumberRequest(number : Long)
|
||||
+ delayedSquaring(consumer : Consumer)
|
||||
}
|
||||
|
||||
object SquareNumberRequest1
|
||||
object SquareNumberRequest2
|
||||
object SquareNumberRequest3
|
||||
diamond dia
|
||||
}
|
||||
|
||||
App --> FanOutFanIn
|
||||
FanOutFanIn --> "fan out - running in parallel" SquareNumberRequest1
|
||||
FanOutFanIn --> "fan out" SquareNumberRequest2
|
||||
FanOutFanIn --> "fan out" SquareNumberRequest3
|
||||
SquareNumberRequest1 --> "fan in - aggregate using callback" dia
|
||||
SquareNumberRequest2 --> "fan in" dia
|
||||
SquareNumberRequest3 --> "fan in" dia
|
||||
dia --> Consumer
|
||||
@enduml
|
69
fanout-fanin/pom.xml
Normal file
69
fanout-fanin/pom.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2014-2021 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.
|
||||
|
||||
Module Model-view-viewmodel is using ZK framework
|
||||
ZK framework is licensed under LGPL and the license can be found at lgpl-3.0.txt
|
||||
|
||||
-->
|
||||
<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">
|
||||
<parent>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<version>1.25.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>fanout-fanin</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</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.fanout.fanin.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FanOut/FanIn pattern is a concurrency pattern that refers to executing multiple instances of the
|
||||
* activity function concurrently. The "fan out" part is essentially splitting the data into
|
||||
* multiple chunks and then calling the activity function multiple times, passing the chunks.
|
||||
*
|
||||
* <p>When each chunk has been processed, the "fan in" takes place that aggregates results from each
|
||||
* instance of function and forms a single final result.
|
||||
*
|
||||
* <p>This pattern is only really useful if you can “chunk” the workload in a meaningful way for
|
||||
* splitting up to be processed in parallel.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Entry point.
|
||||
*
|
||||
* <p>Implementation provided has a list of numbers that has to be squared and added. The list can
|
||||
* be chunked in any way and the "activity function" {@link
|
||||
* SquareNumberRequest#delayedSquaring(Consumer)} i.e. squaring the number ca be done
|
||||
* concurrently. The "fan in" part is handled by the {@link Consumer} that takes in the result
|
||||
* from each instance of activity and aggregates it whenever that particular activity function
|
||||
* gets over.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final List<Long> numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L);
|
||||
|
||||
LOGGER.info("Numbers to be squared and get sum --> {}", numbers);
|
||||
|
||||
final List<SquareNumberRequest> requests =
|
||||
numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList());
|
||||
|
||||
var consumer = new Consumer(0L);
|
||||
|
||||
// Pass the request and the consumer to fanOutFanIn or sometimes referred as Orchestrator
|
||||
// function
|
||||
final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer);
|
||||
|
||||
LOGGER.info("Sum of all squared numbers --> {}", sumOfSquaredNumbers);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Consumer or callback class that will be called everytime a request is complete This will
|
||||
* aggregate individual result to form a final result.
|
||||
*/
|
||||
@Getter
|
||||
public class Consumer {
|
||||
|
||||
private final AtomicLong sumOfSquaredNumbers;
|
||||
|
||||
Consumer(Long init) {
|
||||
sumOfSquaredNumbers = new AtomicLong(init);
|
||||
}
|
||||
|
||||
public Long add(final Long num) {
|
||||
return sumOfSquaredNumbers.addAndGet(num);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* FanOutFanIn class processes long running requests, when any of the processes gets over, result is
|
||||
* passed over to the consumer or the callback function. Consumer will aggregate the results as they
|
||||
* keep on completing.
|
||||
*/
|
||||
public class FanOutFanIn {
|
||||
|
||||
/**
|
||||
* the main fanOutFanIn function or orchestrator function.
|
||||
* @param requests List of numbers that need to be squared and summed up
|
||||
* @param consumer Takes in the squared number from {@link SquareNumberRequest} and sums it up
|
||||
* @return Aggregated sum of all squared numbers.
|
||||
*/
|
||||
public static Long fanOutFanIn(
|
||||
final List<SquareNumberRequest> requests, final Consumer consumer) {
|
||||
|
||||
ExecutorService service = Executors.newFixedThreadPool(requests.size());
|
||||
|
||||
// fanning out
|
||||
List<CompletableFuture<Void>> futures =
|
||||
requests.stream()
|
||||
.map(
|
||||
request ->
|
||||
CompletableFuture.runAsync(() -> request.delayedSquaring(consumer), service))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
|
||||
|
||||
return consumer.getSumOfSquaredNumbers().get();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* Squares the number with a little timeout to give impression of long running process that return
|
||||
* at different times.
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class SquareNumberRequest {
|
||||
|
||||
private final Long number;
|
||||
|
||||
/**
|
||||
* Squares the number with a little timeout to give impression of long running process that return
|
||||
* at different times.
|
||||
* @param consumer callback class that takes the result after the delay.
|
||||
* */
|
||||
public void delayedSquaring(final Consumer consumer) {
|
||||
|
||||
var minTimeOut = 5000L;
|
||||
|
||||
SecureRandom secureRandom = new SecureRandom();
|
||||
var randomTimeOut = secureRandom.nextInt(2000);
|
||||
|
||||
try {
|
||||
// this will make the thread sleep from 5-7s.
|
||||
Thread.sleep(minTimeOut + randomTimeOut);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Exception while sleep ", e);
|
||||
Thread.currentThread().interrupt();
|
||||
} finally {
|
||||
consumer.add(number * number);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
class AppTest {
|
||||
|
||||
@Test
|
||||
void shouldLaunchApp() {
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class FanOutFanInTest {
|
||||
|
||||
@Test
|
||||
void fanOutFanInTest() {
|
||||
final List<Long> numbers = Arrays.asList(1L, 3L, 4L, 7L, 8L);
|
||||
|
||||
final List<SquareNumberRequest> requests =
|
||||
numbers.stream().map(SquareNumberRequest::new).collect(Collectors.toList());
|
||||
|
||||
final Consumer consumer = new Consumer(0L);
|
||||
|
||||
final Long sumOfSquaredNumbers = FanOutFanIn.fanOutFanIn(requests, consumer);
|
||||
|
||||
Assertions.assertEquals(139, sumOfSquaredNumbers);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 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.fanout.fanin;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SquareNumberRequestTest {
|
||||
|
||||
@Test
|
||||
void delayedSquaringTest() {
|
||||
Consumer consumer = new Consumer(10L);
|
||||
|
||||
SquareNumberRequest squareNumberRequest = new SquareNumberRequest(5L);
|
||||
|
||||
squareNumberRequest.delayedSquaring(consumer);
|
||||
|
||||
Assertions.assertEquals(35, consumer.getSumOfSquaredNumbers().get());
|
||||
}
|
||||
}
|
23
gpl-3.0.txt
23
gpl-3.0.txt
@ -1,3 +1,26 @@
|
||||
====
|
||||
The MIT License
|
||||
Copyright © 2014-2021 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.
|
||||
====
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
|
23
lgpl-3.0.txt
23
lgpl-3.0.txt
@ -1,3 +1,26 @@
|
||||
====
|
||||
The MIT License
|
||||
Copyright © 2014-2021 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.
|
||||
====
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
|
@ -48,7 +48,7 @@ que lorsqu’ils sont nécessaires pour une extensibilité pratique.
|
||||
|
||||
Une fois que vous êtes familiarisé avec ces concepts, vous pouvez commencer à explorer les
|
||||
[modèles de conception disponibles](https://java-design-patterns.com/patterns/)
|
||||
par n’importe laquelle les approches suivantes :
|
||||
par n’importe laquelle des approches suivantes :
|
||||
|
||||
- Recherchez un modèle spécifique par son nom.
|
||||
Vous n’en trouvez pas ? Veuillez signaler un nouveau modèle [ici](https://github.com/iluwatar/java-design-patterns/issues).
|
||||
|
5
pom.xml
5
pom.xml
@ -62,7 +62,7 @@
|
||||
<slf4j.version>1.7.30</slf4j.version>
|
||||
<logback.version>1.2.3</logback.version>
|
||||
<aws-lambda-core.version>1.1.0</aws-lambda-core.version>
|
||||
<aws-java-sdk-dynamodb.version>1.11.289</aws-java-sdk-dynamodb.version>
|
||||
<aws-java-sdk-dynamodb.version>1.12.13</aws-java-sdk-dynamodb.version>
|
||||
<aws-lambda-java-events.version>2.0.1</aws-lambda-java-events.version>
|
||||
<jackson.version>2.12.3</jackson.version>
|
||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||
@ -72,7 +72,7 @@
|
||||
<urm.version>2.0.0</urm.version>
|
||||
<mockito-junit-jupiter.version>3.5.0</mockito-junit-jupiter.version>
|
||||
<lombok.version>1.18.14</lombok.version>
|
||||
<byte-buddy.version>1.10.21</byte-buddy.version>
|
||||
<byte-buddy.version>1.11.5</byte-buddy.version>
|
||||
<javassist.version>3.27.0-GA</javassist.version>
|
||||
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
|
||||
@ -232,6 +232,7 @@
|
||||
<module>table-module</module>
|
||||
<module>presentation</module>
|
||||
<module>lockable-object</module>
|
||||
<module>fanout-fanin</module>
|
||||
<module>domain-model</module>
|
||||
</modules>
|
||||
|
||||
|
@ -44,16 +44,6 @@
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-dynamodb</artifactId>
|
||||
<version>${aws-java-sdk-dynamodb.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-kms</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
@ -80,15 +70,15 @@
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
|
||||
package com.iluwatar.serverless.baas.api;
|
||||
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@ -32,31 +35,29 @@ import com.amazonaws.services.lambda.runtime.Context;
|
||||
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||
import com.iluwatar.serverless.baas.model.Person;
|
||||
import java.util.Map;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
/**
|
||||
* Unit tests for FindPersonApiHandler Created by dheeraj.mummar on 3/5/18.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class FindPersonApiHandlerTest {
|
||||
class FindPersonApiHandlerTest {
|
||||
|
||||
private FindPersonApiHandler findPersonApiHandler;
|
||||
|
||||
@Mock
|
||||
private DynamoDBMapper dynamoDbMapper;
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
this.findPersonApiHandler = new FindPersonApiHandler();
|
||||
this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequest() {
|
||||
void handleRequest() {
|
||||
findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class));
|
||||
verify(dynamoDbMapper, times(1)).load(Person.class, "37e7a1fe-3544-473d-b764-18128f02d72d");
|
||||
}
|
||||
|
@ -34,18 +34,18 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.iluwatar.serverless.baas.model.Address;
|
||||
import com.iluwatar.serverless.baas.model.Person;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
/**
|
||||
* Unit tests for SavePersonApiHandler Created by dheeraj.mummar on 3/4/18.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SavePersonApiHandlerTest {
|
||||
class SavePersonApiHandlerTest {
|
||||
|
||||
private SavePersonApiHandler savePersonApiHandler;
|
||||
|
||||
@ -54,31 +54,32 @@ public class SavePersonApiHandlerTest {
|
||||
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
@Before
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
this.savePersonApiHandler = new SavePersonApiHandler();
|
||||
this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestSavePersonSuccessful() throws JsonProcessingException {
|
||||
void handleRequestSavePersonSuccessful() throws JsonProcessingException {
|
||||
var person = newPerson();
|
||||
var body = objectMapper.writeValueAsString(person);
|
||||
var request = apiGatewayProxyRequestEvent(body);
|
||||
var ctx = mock(Context.class);
|
||||
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
||||
verify(dynamoDbMapper, times(1)).save(person);
|
||||
Assert.assertNotNull(apiGatewayProxyResponseEvent);
|
||||
Assert.assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode());
|
||||
assertNotNull(apiGatewayProxyResponseEvent);
|
||||
assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handleRequestSavePersonException() {
|
||||
void handleRequestSavePersonException() {
|
||||
var request = apiGatewayProxyRequestEvent("invalid sample request");
|
||||
var ctx = mock(Context.class);
|
||||
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
||||
Assert.assertNotNull(apiGatewayProxyResponseEvent);
|
||||
Assert.assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode());
|
||||
assertNotNull(apiGatewayProxyResponseEvent);
|
||||
assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode());
|
||||
}
|
||||
|
||||
private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {
|
||||
|
@ -36,16 +36,12 @@ public final class ThreadSafeDoubleCheckLocking {
|
||||
|
||||
private static volatile ThreadSafeDoubleCheckLocking instance;
|
||||
|
||||
private static boolean flag = true;
|
||||
|
||||
/**
|
||||
* private constructor to prevent client from instantiating.
|
||||
*/
|
||||
private ThreadSafeDoubleCheckLocking() {
|
||||
// to prevent instantiating by Reflection call
|
||||
if (flag) {
|
||||
flag = false;
|
||||
} else {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("Already initialized.");
|
||||
}
|
||||
}
|
||||
|
@ -34,9 +34,7 @@ public final class ThreadSafeLazyLoadedIvoryTower {
|
||||
|
||||
private ThreadSafeLazyLoadedIvoryTower() {
|
||||
// Protect against instantiation via reflection
|
||||
if (instance == null) {
|
||||
instance = this;
|
||||
} else {
|
||||
if (instance != null) {
|
||||
throw new IllegalStateException("Already initialized.");
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user