Compare commits
8 Commits
adapter-gr
...
all-contri
Author | SHA1 | Date | |
---|---|---|---|
f1ae059826 | |||
475df8867a | |||
be25c0b433 | |||
be59e50205 | |||
ec90320eda | |||
3126ad3106 | |||
e2ebb59fe7 | |||
d87e8cf10d |
@ -1568,6 +1568,33 @@
|
|||||||
"contributions": [
|
"contributions": [
|
||||||
"code"
|
"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,
|
"contributorsPerLine": 4,
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
[](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)
|
[](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 -->
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||||
[](#contributors-)
|
[](#contributors-)
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
|
|
||||||
<br/>
|
<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/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>
|
<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>
|
||||||
|
<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>
|
</table>
|
||||||
|
|
||||||
<!-- markdownlint-restore -->
|
<!-- markdownlint-restore -->
|
||||||
|
@ -48,7 +48,7 @@ class AggregatorTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -48,7 +48,7 @@ class ApiGatewayTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +68,7 @@ class ThreadAsyncExecutorTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +46,7 @@ class DataBusTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.openMocks(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
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
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
Version 3, 29 June 2007
|
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
|
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/)
|
[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.
|
- 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).
|
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>
|
<slf4j.version>1.7.30</slf4j.version>
|
||||||
<logback.version>1.2.3</logback.version>
|
<logback.version>1.2.3</logback.version>
|
||||||
<aws-lambda-core.version>1.1.0</aws-lambda-core.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>
|
<aws-lambda-java-events.version>2.0.1</aws-lambda-java-events.version>
|
||||||
<jackson.version>2.12.3</jackson.version>
|
<jackson.version>2.12.3</jackson.version>
|
||||||
<jaxb-api.version>2.3.1</jaxb-api.version>
|
<jaxb-api.version>2.3.1</jaxb-api.version>
|
||||||
@ -72,7 +72,7 @@
|
|||||||
<urm.version>2.0.0</urm.version>
|
<urm.version>2.0.0</urm.version>
|
||||||
<mockito-junit-jupiter.version>3.5.0</mockito-junit-jupiter.version>
|
<mockito-junit-jupiter.version>3.5.0</mockito-junit-jupiter.version>
|
||||||
<lombok.version>1.18.14</lombok.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>
|
<javassist.version>3.27.0-GA</javassist.version>
|
||||||
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
<maven-surefire-plugin.version>3.0.0-M5</maven-surefire-plugin.version>
|
||||||
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
|
<maven-checkstyle-plugin.version>3.1.0</maven-checkstyle-plugin.version>
|
||||||
@ -232,6 +232,7 @@
|
|||||||
<module>table-module</module>
|
<module>table-module</module>
|
||||||
<module>presentation</module>
|
<module>presentation</module>
|
||||||
<module>lockable-object</module>
|
<module>lockable-object</module>
|
||||||
|
<module>fanout-fanin</module>
|
||||||
<module>domain-model</module>
|
<module>domain-model</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
|
@ -44,16 +44,6 @@
|
|||||||
<groupId>com.amazonaws</groupId>
|
<groupId>com.amazonaws</groupId>
|
||||||
<artifactId>aws-java-sdk-dynamodb</artifactId>
|
<artifactId>aws-java-sdk-dynamodb</artifactId>
|
||||||
<version>${aws-java-sdk-dynamodb.version}</version>
|
<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>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.amazonaws</groupId>
|
<groupId>com.amazonaws</groupId>
|
||||||
@ -80,15 +70,15 @@
|
|||||||
<artifactId>junit-jupiter-engine</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.hamcrest</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>hamcrest-core</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
|
|
||||||
package com.iluwatar.serverless.baas.api;
|
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.mock;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
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.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent;
|
||||||
import com.iluwatar.serverless.baas.model.Person;
|
import com.iluwatar.serverless.baas.model.Person;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for FindPersonApiHandler Created by dheeraj.mummar on 3/5/18.
|
* Unit tests for FindPersonApiHandler Created by dheeraj.mummar on 3/5/18.
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
class FindPersonApiHandlerTest {
|
||||||
public class FindPersonApiHandlerTest {
|
|
||||||
|
|
||||||
private FindPersonApiHandler findPersonApiHandler;
|
private FindPersonApiHandler findPersonApiHandler;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DynamoDBMapper dynamoDbMapper;
|
private DynamoDBMapper dynamoDbMapper;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.openMocks(this);
|
||||||
this.findPersonApiHandler = new FindPersonApiHandler();
|
this.findPersonApiHandler = new FindPersonApiHandler();
|
||||||
this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
this.findPersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleRequest() {
|
void handleRequest() {
|
||||||
findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class));
|
findPersonApiHandler.handleRequest(apiGatewayProxyRequestEvent(), mock(Context.class));
|
||||||
verify(dynamoDbMapper, times(1)).load(Person.class, "37e7a1fe-3544-473d-b764-18128f02d72d");
|
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.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.iluwatar.serverless.baas.model.Address;
|
import com.iluwatar.serverless.baas.model.Address;
|
||||||
import com.iluwatar.serverless.baas.model.Person;
|
import com.iluwatar.serverless.baas.model.Person;
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
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.
|
* Unit tests for SavePersonApiHandler Created by dheeraj.mummar on 3/4/18.
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
class SavePersonApiHandlerTest {
|
||||||
public class SavePersonApiHandlerTest {
|
|
||||||
|
|
||||||
private SavePersonApiHandler savePersonApiHandler;
|
private SavePersonApiHandler savePersonApiHandler;
|
||||||
|
|
||||||
@ -54,31 +54,32 @@ public class SavePersonApiHandlerTest {
|
|||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
|
MockitoAnnotations.openMocks(this);
|
||||||
this.savePersonApiHandler = new SavePersonApiHandler();
|
this.savePersonApiHandler = new SavePersonApiHandler();
|
||||||
this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
this.savePersonApiHandler.setDynamoDbMapper(dynamoDbMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleRequestSavePersonSuccessful() throws JsonProcessingException {
|
void handleRequestSavePersonSuccessful() throws JsonProcessingException {
|
||||||
var person = newPerson();
|
var person = newPerson();
|
||||||
var body = objectMapper.writeValueAsString(person);
|
var body = objectMapper.writeValueAsString(person);
|
||||||
var request = apiGatewayProxyRequestEvent(body);
|
var request = apiGatewayProxyRequestEvent(body);
|
||||||
var ctx = mock(Context.class);
|
var ctx = mock(Context.class);
|
||||||
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
||||||
verify(dynamoDbMapper, times(1)).save(person);
|
verify(dynamoDbMapper, times(1)).save(person);
|
||||||
Assert.assertNotNull(apiGatewayProxyResponseEvent);
|
assertNotNull(apiGatewayProxyResponseEvent);
|
||||||
Assert.assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode());
|
assertEquals(Integer.valueOf(201), apiGatewayProxyResponseEvent.getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleRequestSavePersonException() {
|
void handleRequestSavePersonException() {
|
||||||
var request = apiGatewayProxyRequestEvent("invalid sample request");
|
var request = apiGatewayProxyRequestEvent("invalid sample request");
|
||||||
var ctx = mock(Context.class);
|
var ctx = mock(Context.class);
|
||||||
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
var apiGatewayProxyResponseEvent = this.savePersonApiHandler.handleRequest(request, ctx);
|
||||||
Assert.assertNotNull(apiGatewayProxyResponseEvent);
|
assertNotNull(apiGatewayProxyResponseEvent);
|
||||||
Assert.assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode());
|
assertEquals(Integer.valueOf(400), apiGatewayProxyResponseEvent.getStatusCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {
|
private APIGatewayProxyRequestEvent apiGatewayProxyRequestEvent(String body) {
|
||||||
|
@ -36,16 +36,12 @@ public final class ThreadSafeDoubleCheckLocking {
|
|||||||
|
|
||||||
private static volatile ThreadSafeDoubleCheckLocking instance;
|
private static volatile ThreadSafeDoubleCheckLocking instance;
|
||||||
|
|
||||||
private static boolean flag = true;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* private constructor to prevent client from instantiating.
|
* private constructor to prevent client from instantiating.
|
||||||
*/
|
*/
|
||||||
private ThreadSafeDoubleCheckLocking() {
|
private ThreadSafeDoubleCheckLocking() {
|
||||||
// to prevent instantiating by Reflection call
|
// to prevent instantiating by Reflection call
|
||||||
if (flag) {
|
if (instance != null) {
|
||||||
flag = false;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Already initialized.");
|
throw new IllegalStateException("Already initialized.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,9 +34,7 @@ public final class ThreadSafeLazyLoadedIvoryTower {
|
|||||||
|
|
||||||
private ThreadSafeLazyLoadedIvoryTower() {
|
private ThreadSafeLazyLoadedIvoryTower() {
|
||||||
// Protect against instantiation via reflection
|
// Protect against instantiation via reflection
|
||||||
if (instance == null) {
|
if (instance != null) {
|
||||||
instance = this;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Already initialized.");
|
throw new IllegalStateException("Already initialized.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user