Compare commits
127 Commits
all-contri
...
all-contri
Author | SHA1 | Date | |
---|---|---|---|
|
6c7715ace6 | ||
|
ef43af3b23 | ||
|
95e513b6ec | ||
|
194040543e | ||
|
846a174ade | ||
|
7f60f7be25 | ||
|
cfb58191ea | ||
|
82bf9fdd61 | ||
|
be552d0ece | ||
|
d584404df6 | ||
|
353a2d9fcf | ||
|
8c5740563d | ||
|
89bda692f8 | ||
|
241f93f3cc | ||
|
79a6af703e | ||
|
00d06871f4 | ||
|
7afb065a10 | ||
|
af9f8fe4e1 | ||
|
a1c96ede13 | ||
|
0d2c4abe5a | ||
|
e7e3ace01f | ||
|
41dacc2e2e | ||
|
dc7bf6190d | ||
|
98d2dc0104 | ||
|
870d44b127 | ||
|
834f20911b | ||
|
2b7949ce6a | ||
|
4ffab7da85 | ||
|
1683fbdf9c | ||
|
d091e369ec | ||
|
b91bbc773d | ||
|
3c07a42e9d | ||
|
e99bcf772b | ||
|
2d16e5afbf | ||
|
2c6f1832b0 | ||
|
04a2be0c99 | ||
|
10815b6469 | ||
|
75b10ed657 | ||
|
108532d8dd | ||
|
5527cf4234 | ||
|
4008ae41b5 | ||
|
8166a1835d | ||
|
4c9cad5475 | ||
|
24126edd86 | ||
|
c0edac0046 | ||
|
f5c337981b | ||
|
5441db6582 | ||
|
87f3a4d956 | ||
|
31d753e59d | ||
|
6cef98d41e | ||
|
7450456dae | ||
|
45e416928d | ||
|
94c131f7e9 | ||
|
5eb9b98e78 | ||
|
8305e9365d | ||
|
04e3368a81 | ||
|
d219a104c7 | ||
|
700f5c6d27 | ||
|
f4fa73cd48 | ||
|
e09de2fb36 | ||
|
a59c9bba97 | ||
|
7acc5fbf95 | ||
|
bdf2145b3f | ||
|
1e90d0d645 | ||
|
b8c0985b97 | ||
|
c40d6ae9d7 | ||
|
76bfc68cd6 | ||
|
d0ed10a619 | ||
|
5bfaeffecf | ||
|
c0acaf073b | ||
|
9f190c59c4 | ||
|
50ed5ca699 | ||
|
08cec0e254 | ||
|
1f6e6f34ea | ||
|
134ccdb5a1 | ||
|
fa68789cd5 | ||
|
8b92bc6bb6 | ||
|
8e060ad0ad | ||
|
a5038c4329 | ||
|
b0ac4c1ca3 | ||
|
0ead283f55 | ||
|
888af23219 | ||
|
0c83ccc2fe | ||
|
a7095602d6 | ||
|
4b38746ce9 | ||
|
cd20e7a3f4 | ||
|
7f29c2455f | ||
|
51e8900d31 | ||
|
20a5dde8a4 | ||
|
bf4706addf | ||
|
97285d3724 | ||
|
f234baf258 | ||
|
ca58fa3f21 | ||
|
ca7192889d | ||
|
fa3b93bf8d | ||
|
a7b4194a71 | ||
|
054b1eaac6 | ||
|
44a654a2e3 | ||
|
10988526a2 | ||
|
b9f17824fa | ||
|
3ae7466647 | ||
|
9ff5b9e7c0 | ||
|
4941e8ebc4 | ||
|
12d392931e | ||
|
4017c37b6f | ||
|
9d191324ff | ||
|
75ab3b5245 | ||
|
e0fb2d014a | ||
|
c4b1b89f1f | ||
|
52e6ea2b68 | ||
|
112973482d | ||
|
58e3fbfc6a | ||
|
bf01f3e68b | ||
|
58b98c54e5 | ||
|
daf53225d8 | ||
|
d733122e7a | ||
|
2fa938c02d | ||
|
9b105d770d | ||
|
109d33c710 | ||
|
a142c06048 | ||
|
f1b27ef5c7 | ||
|
99c70af16a | ||
|
edcb520d08 | ||
|
a00622c656 | ||
|
93e5570778 | ||
|
59e050b20b | ||
|
e6c74a5fb9 |
@@ -1075,6 +1075,70 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ravening",
|
||||
"name": "Rakesh",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10645273?v=4",
|
||||
"profile": "https://github.com/ravening",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "vINCENT8888801",
|
||||
"name": "Wei Seng",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/8037883?v=4",
|
||||
"profile": "https://github.com/vINCENT8888801",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ashishtrivedi16",
|
||||
"name": "Ashish Trivedi",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/23194128?v=4",
|
||||
"profile": "https://www.linkedin.com/in/ashish-trivedi-218379135/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "RayYH",
|
||||
"name": "洪月阳",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/41055099?v=4",
|
||||
"profile": "https://rayyounghong.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "xdvrx1",
|
||||
"name": "xdvrx1",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/47092464?v=4",
|
||||
"profile": "https://xdvrx1.github.io/",
|
||||
"contributions": [
|
||||
"review",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ohbus",
|
||||
"name": "Subhrodip Mohanta",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/13291222?v=4",
|
||||
"profile": "http://subho.xyz",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nahteb",
|
||||
"name": "Bethan Palmer",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/13121570?v=4",
|
||||
"profile": "https://github.com/nahteb",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
@@ -24,13 +24,11 @@
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Java CI with Maven
|
||||
name: Java CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -43,6 +41,12 @@ jobs:
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
# Some tests need screen access
|
||||
- name: Install xvfb
|
||||
run: sudo apt-get install xvfb
|
57
.github/workflows/maven-pr-builder.yml
vendored
Normal file
57
.github/workflows/maven-pr-builder.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# The MIT License
|
||||
# Copyright © 2014-2019 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.
|
||||
#
|
||||
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
|
||||
name: Java PR Builder
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-18.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-maven-
|
||||
# Some tests need screen access
|
||||
- name: Install xvfb
|
||||
run: sudo apt-get install xvfb
|
||||
# SonarQube scan does not work for forked repositories
|
||||
# See https://jira.sonarsource.com/browse/MMF-1371
|
||||
- name: Build with Maven
|
||||
if: github.ref != 'refs/heads/master'
|
||||
run: xvfb-run mvn clean verify
|
16
README.md
16
README.md
@@ -9,7 +9,7 @@
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
# Introduction
|
||||
@@ -239,13 +239,23 @@ This project is licensed under the terms of the MIT license.
|
||||
<tr>
|
||||
<td align="center"><a href="https://webpro.nl"><img src="https://avatars1.githubusercontent.com/u/456426?v=4" width="100px;" alt=""/><br /><sub><b>Lars Kappert</b></sub></a><br /><a href="#content-webpro" title="Content">🖋</a></td>
|
||||
<td align="center"><a href="https://xiaod.info"><img src="https://avatars2.githubusercontent.com/u/21277644?v=4" width="100px;" alt=""/><br /><sub><b>Mike Liu</b></sub></a><br /><a href="#translation-xiaod-dev" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/MananS77"><img src="https://avatars3.githubusercontent.com/u/21033516?v=4" width="100px;" alt=""/><br /><sub><b>Manan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3AMananS77" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nishant"><img src="https://avatars2.githubusercontent.com/u/15331971?v=4" width="100px;" alt=""/><br /><sub><b>Nishant Arora</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nishant" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/raja-peeyush-kumar-singh"><img src="https://avatars0.githubusercontent.com/u/5496024?v=4" width="100px;" alt=""/><br /><sub><b>Peeyush</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=raja-peeyush-kumar-singh" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/charlesfinley"><img src="https://avatars1.githubusercontent.com/u/6307904?v=4" width="100px;" alt=""/><br /><sub><b>Matt Dolan</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=charlesfinley" title="Code">💻</a> <a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Acharlesfinley" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center"><a href="https://github.com/ravening"><img src="https://avatars1.githubusercontent.com/u/10645273?v=4" width="100px;" alt=""/><br /><sub><b>Rakesh</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ravening" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/vINCENT8888801"><img src="https://avatars0.githubusercontent.com/u/8037883?v=4" width="100px;" alt=""/><br /><sub><b>Wei Seng</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=vINCENT8888801" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/ashish-trivedi-218379135/"><img src="https://avatars3.githubusercontent.com/u/23194128?v=4" width="100px;" alt=""/><br /><sub><b>Ashish Trivedi</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ashishtrivedi16" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://rayyounghong.com"><img src="https://avatars1.githubusercontent.com/u/41055099?v=4" width="100px;" alt=""/><br /><sub><b>洪月阳</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=RayYH" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://xdvrx1.github.io/"><img src="https://avatars0.githubusercontent.com/u/47092464?v=4" width="100px;" alt=""/><br /><sub><b>xdvrx1</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/pulls?q=is%3Apr+reviewed-by%3Axdvrx1" title="Reviewed Pull Requests">👀</a> <a href="#ideas-xdvrx1" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="http://subho.xyz"><img src="https://avatars0.githubusercontent.com/u/13291222?v=4" width="100px;" alt=""/><br /><sub><b>Subhrodip Mohanta</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=ohbus" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/nahteb"><img src="https://avatars3.githubusercontent.com/u/13121570?v=4" width="100px;" alt=""/><br /><sub><b>Bethan Palmer</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=nahteb" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@@ -21,7 +21,7 @@ objects without specifying their concrete classes.
|
||||
|
||||
Real world example
|
||||
|
||||
> To create a kingdom we need objects with common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
||||
> To create a kingdom we need objects with a common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom.
|
||||
|
||||
In plain words
|
||||
|
||||
@@ -33,7 +33,8 @@ Wikipedia says
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the kingdom
|
||||
Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the
|
||||
kingdom.
|
||||
|
||||
```java
|
||||
public interface Castle {
|
||||
@@ -188,9 +189,9 @@ Use the Abstract Factory pattern when
|
||||
* When you need consistency among products
|
||||
* You don’t want to change existing code when adding new products or families of products to the program.
|
||||
|
||||
## Use Cases:
|
||||
Example use cases
|
||||
|
||||
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
||||
* Selecting to call to the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime.
|
||||
* Unit test case writing becomes much easier
|
||||
* UI tools for different OS
|
||||
|
||||
@@ -204,13 +205,17 @@ Use the Abstract Factory pattern when
|
||||
|
||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
||||
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
||||
|
||||
## Related patterns
|
||||
|
||||
[Factory Method](https://java-design-patterns.com/patterns/factory-method/)
|
||||
[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
|
||||
|
@@ -101,7 +101,7 @@ public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
}
|
||||
```
|
||||
|
||||
Finally here are the visitors in action.
|
||||
Finally, here are the visitors in action.
|
||||
|
||||
```java
|
||||
var conUnix = new ConfigureForUnixVisitor();
|
||||
|
@@ -12,9 +12,8 @@ tags:
|
||||
Wrapper
|
||||
|
||||
## Intent
|
||||
Convert the interface of a class into another interface the clients
|
||||
expect. Adapter lets classes work together that couldn't otherwise because of
|
||||
incompatible interfaces.
|
||||
Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that
|
||||
couldn't otherwise because of incompatible interfaces.
|
||||
|
||||
## Explanation
|
||||
|
||||
|
@@ -6,20 +6,97 @@ permalink: /patterns/aggregator-microservices/
|
||||
categories: Architectural
|
||||
tags:
|
||||
- Cloud distributed
|
||||
- Decoupling
|
||||
- Microservices
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
The user makes a single call to the Aggregator, and the aggregator then calls each relevant microservice and collects
|
||||
the data, apply business logic to it, and further publish is as a REST Endpoint.
|
||||
More variations of the aggregator are:
|
||||
- Proxy Microservice Design Pattern: A different microservice is called upon the business need.
|
||||
- Chained Microservice Design Pattern: In this case each microservice is dependent/ chained to a series
|
||||
of other microservices.
|
||||
The user makes a single call to the aggregator service, and the aggregator then calls each relevant microservice.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> Our web marketplace needs information about products and their current inventory. It makes a call to an aggregator
|
||||
> service which in turn calls the product information microservice and product inventory microservice returning the
|
||||
> combined information.
|
||||
|
||||
In plain words
|
||||
|
||||
> Aggregator Microservice collects pieces of data from various microservices and returns an aggregate for processing.
|
||||
|
||||
Stack Overflow says
|
||||
|
||||
> Aggregator Microservice invokes multiple services to achieve the functionality required by the application.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Let's start from the data model. Here's our `Product`.
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String title;
|
||||
private int productInventories;
|
||||
// getters and setters ->
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Next we can introduce our `Aggregator` microservice. It contains clients `ProductInformationClient` and
|
||||
`ProductInventoryClient` for calling respective microservices.
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class Aggregator {
|
||||
|
||||
@Resource
|
||||
private ProductInformationClient informationClient;
|
||||
|
||||
@Resource
|
||||
private ProductInventoryClient inventoryClient;
|
||||
|
||||
@RequestMapping(path = "/product", method = RequestMethod.GET)
|
||||
public Product getProduct() {
|
||||
|
||||
var product = new Product();
|
||||
var productTitle = informationClient.getProductTitle();
|
||||
var productInventory = inventoryClient.getProductInventories();
|
||||
|
||||
//Fallback to error message
|
||||
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
|
||||
|
||||
//Fallback to default error inventory
|
||||
product.setProductInventories(requireNonNullElse(productInventory, -1));
|
||||
|
||||
return product;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here's the essence of information microservice implementation. Inventory microservice is similar, it just returns
|
||||
inventory counts.
|
||||
|
||||
```java
|
||||
@RestController
|
||||
public class InformationController {
|
||||
@RequestMapping(value = "/information", method = RequestMethod.GET)
|
||||
public String getProductTitle() {
|
||||
return "The Product Title.";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now calling our `Aggregator` REST API returns the product information.
|
||||
|
||||
```bash
|
||||
curl http://localhost:50004/product
|
||||
{"title":"The Product Title.","productInventories":5}
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||

|
||||
|
||||
## Applicability
|
||||
|
||||
@@ -28,3 +105,5 @@ Use the Aggregator Microservices pattern when you need a unified API for various
|
||||
## Credits
|
||||
|
||||
* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/)
|
||||
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60)
|
||||
* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4)
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
Before Width: | Height: | Size: 40 KiB |
@@ -10,28 +10,37 @@ tags:
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Provide a helper service instance on a client and offload common functionality away from a shared resource.
|
||||
|
||||
## Explanation
|
||||
|
||||
Real world example
|
||||
|
||||
> A remote service has many clients accessing a function it provides. The service is a legacy application and is impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request frequency should be implemented along with latency checks and client-side logging.
|
||||
> A remote service has many clients accessing a function it provides. The service is a legacy application and is
|
||||
> impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request
|
||||
> frequency should be implemented along with latency checks and client-side logging.
|
||||
|
||||
In plain words
|
||||
|
||||
> Using the ambassador pattern, we can implement less-frequent polling from clients along with latency checks and logging.
|
||||
> With the Ambassador pattern, we can implement less-frequent polling from clients along with latency checks and
|
||||
> logging.
|
||||
|
||||
Microsoft documentation states
|
||||
|
||||
> An ambassador service can be thought of as an out-of-process proxy that is co-located with the client. This pattern can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, or other applications that are difficult to modify, in order to extend their networking capabilities. It can also enable a specialized team to implement those features.
|
||||
> An ambassador service can be thought of as an out-of-process proxy which is co-located with the client. This pattern
|
||||
> can be useful for offloading common client connectivity tasks such as monitoring, logging, routing,
|
||||
> security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications,
|
||||
> or other applications that are difficult to modify, in order to extend their networking capabilities. It can also
|
||||
> enable a specialized team to implement those features.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
With the above example in mind we will imitate the functionality in a simple manner. We have an interface implemented by the remote service as well as the ambassador service:
|
||||
With the above introduction in mind we will imitate the functionality in this example. We have an interface implemented
|
||||
by the remote service as well as the ambassador service:
|
||||
|
||||
```java
|
||||
interface RemoteServiceInterface {
|
||||
|
||||
long doRemoteFunction(int value) throws Exception;
|
||||
}
|
||||
```
|
||||
@@ -136,7 +145,7 @@ public class Client {
|
||||
}
|
||||
```
|
||||
|
||||
And here are two clients using the service.
|
||||
Here are two clients using the service.
|
||||
|
||||
```java
|
||||
public class App {
|
||||
@@ -149,13 +158,29 @@ public class App {
|
||||
}
|
||||
```
|
||||
|
||||
Here's the output for running the example:
|
||||
|
||||
```java
|
||||
Time taken (ms): 111
|
||||
Service result: 120
|
||||
Time taken (ms): 931
|
||||
Failed to reach remote: (1)
|
||||
Time taken (ms): 665
|
||||
Failed to reach remote: (2)
|
||||
Time taken (ms): 538
|
||||
Failed to reach remote: (3)
|
||||
Service result: -1
|
||||
```
|
||||
|
||||
## Class diagram
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
Ambassador is applicable when working with a legacy remote service that cannot
|
||||
be modified or would be extremely difficult to modify. Connectivity features can
|
||||
be implemented on the client avoiding the need for changes on the remote service.
|
||||
|
||||
Ambassador is applicable when working with a legacy remote service which cannot be modified or would be extremely
|
||||
difficult to modify. Connectivity features can be implemented on the client avoiding the need for changes on the remote
|
||||
service.
|
||||
|
||||
* Ambassador provides a local interface for a remote service.
|
||||
* Ambassador provides logging, circuit breaking, retries and security on the client.
|
||||
@@ -168,10 +193,14 @@ be implemented on the client avoiding the need for changes on the remote service
|
||||
* Offload remote service tasks
|
||||
* Facilitate network connection
|
||||
|
||||
## Real world examples
|
||||
## Known uses
|
||||
|
||||
* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador)
|
||||
|
||||
## Related patterns
|
||||
|
||||
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador)
|
||||
|
@@ -29,5 +29,5 @@ package com.iluwatar.ambassador;
|
||||
interface RemoteServiceInterface {
|
||||
int FAILURE = -1;
|
||||
|
||||
long doRemoteFunction(int value) throws Exception;
|
||||
long doRemoteFunction(int value);
|
||||
}
|
||||
|
@@ -12,49 +12,53 @@ tags:
|
||||
|
||||
## Intent
|
||||
|
||||
Aggregate calls to microservices in a single location: the API Gateway. The user makes a single call to the API Gateway,
|
||||
and the API Gateway then calls each relevant microservice.
|
||||
Aggregate calls to microservices in a single location, the API Gateway. The user makes a single call
|
||||
to the API Gateway, and the API Gateway then calls each relevant microservice.
|
||||
|
||||
## Explanation
|
||||
|
||||
With the Microservices pattern, a client may need data from multiple different microservices. If the client called each
|
||||
microservice directly, that could contribute to longer load times, since the client would have to make a network request
|
||||
for each microservice called. Moreover, having the client call each microservice directly ties the client to that
|
||||
microservice - if the internal implementations of the microservices change (for example, if two microservices are
|
||||
combined sometime in the future) or if the location (host and port) of a microservice changes, then every client that
|
||||
With the Microservices pattern, a client may need data from multiple different microservices. If the
|
||||
client called each microservice directly, that could contribute to longer load times, since the
|
||||
client would have to make a network request for each microservice called. Moreover, having the
|
||||
client call each microservice directly ties the client to that microservice - if the internal
|
||||
implementations of the microservices change (for example, if two microservices are combined sometime
|
||||
in the future) or if the location (host and port) of a microservice changes, then every client that
|
||||
makes use of those microservices must be updated.
|
||||
|
||||
The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway pattern, an additional
|
||||
entity (the API Gateway) is placed between the client and the microservices. The job of the API Gateway is to aggregate
|
||||
the calls to the microservices. Rather than the client calling each microservice individually, the client calls the
|
||||
API Gateway a single time. The API Gateway then calls each of the microservices that the client needs.
|
||||
The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway
|
||||
pattern, an additional entity (the API Gateway) is placed between the client and the microservices.
|
||||
The job of the API Gateway is to aggregate the calls to the microservices. Rather than the client
|
||||
calling each microservice individually, the client calls the API Gateway a single time. The API
|
||||
Gateway then calls each of the microservices that the client needs.
|
||||
|
||||
Real world example
|
||||
|
||||
> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system the API Gateway makes
|
||||
calls to the Image and Price microservices.
|
||||
> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system
|
||||
> the API Gateway makes calls to the Image and Price microservices.
|
||||
|
||||
In plain words
|
||||
|
||||
> For a system implemented using microservices architecture, API Gateway is the single entry point that aggregates the
|
||||
calls to the individual microservices.
|
||||
> For a system implemented using microservices architecture, API Gateway is the single entry point
|
||||
> that aggregates the calls to the individual microservices.
|
||||
|
||||
Wikipedia says
|
||||
|
||||
> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling and security
|
||||
policies, passes requests to the back-end service and then passes the response back to the requester. A gateway often
|
||||
includes a transformation engine to orchestrate and modify the requests and responses on the fly. A gateway can also
|
||||
provide functionality such as collecting analytics data and providing caching. The gateway can provide functionality to
|
||||
support authentication, authorization, security, audit and regulatory compliance.
|
||||
> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling
|
||||
> and security policies, passes requests to the back-end service and then passes the response back
|
||||
> to the requester. A gateway often includes a transformation engine to orchestrate and modify the
|
||||
> requests and responses on the fly. A gateway can also provide functionality such as collecting
|
||||
> analytics data and providing caching. The gateway can provide functionality to support
|
||||
> authentication, authorization, security, audit and regulatory compliance.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
This implementation shows what the API Gateway pattern could look like for an e-commerce site. The `ApiGateway` makes
|
||||
calls to the Image and Price microservices using the `ImageClientImpl` and `PriceClientImpl` respectively. Customers
|
||||
viewing the site on a desktop device can see both price information and an image of a product, so the `ApiGateway` calls
|
||||
both of the microservices and aggregates the data in the `DesktopProduct` model. However, mobile users only see price
|
||||
information; they do not see a product image. For mobile users, the `ApiGateway` only retrieves price information, which
|
||||
it uses to populate the `MobileProduct`.
|
||||
This implementation shows what the API Gateway pattern could look like for an e-commerce site. The
|
||||
`ApiGateway` makes calls to the Image and Price microservices using the `ImageClientImpl` and
|
||||
`PriceClientImpl` respectively. Customers viewing the site on a desktop device can see both price
|
||||
information and an image of a product, so the `ApiGateway` calls both of the microservices and
|
||||
aggregates the data in the `DesktopProduct` model. However, mobile users only see price information;
|
||||
they do not see a product image. For mobile users, the `ApiGateway` only retrieves price
|
||||
information, which it uses to populate the `MobileProduct`.
|
||||
|
||||
Here's the Image microservice implementation.
|
||||
|
||||
@@ -64,7 +68,6 @@ public interface ImageClient {
|
||||
}
|
||||
|
||||
public class ImageClientImpl implements ImageClient {
|
||||
|
||||
@Override
|
||||
public String getImagePath() {
|
||||
var httpClient = HttpClient.newHttpClient();
|
||||
@@ -114,7 +117,7 @@ public class PriceClientImpl implements PriceClient {
|
||||
}
|
||||
```
|
||||
|
||||
And here we can see how API Gateway maps the requests to the microservices.
|
||||
Here we can see how API Gateway maps the requests to the microservices.
|
||||
|
||||
```java
|
||||
public class ApiGateway {
|
||||
|
@@ -23,11 +23,16 @@
|
||||
|
||||
package com.iluwatar.api.gateway;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
@@ -35,6 +40,8 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
public class ImageClientImpl implements ImageClient {
|
||||
private static final Logger LOGGER = getLogger(ImageClientImpl.class);
|
||||
|
||||
/**
|
||||
* Makes a simple HTTP Get request to the Image microservice.
|
||||
*
|
||||
@@ -49,12 +56,26 @@ public class ImageClientImpl implements ImageClient {
|
||||
.build();
|
||||
|
||||
try {
|
||||
LOGGER.info("Sending request to fetch image path");
|
||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
||||
logResponse(httpResponse);
|
||||
return httpResponse.body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failure occurred while getting image path", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void logResponse(HttpResponse<String> httpResponse) {
|
||||
if (isSuccessResponse(httpResponse.statusCode())) {
|
||||
LOGGER.info("Image path received successfully");
|
||||
} else {
|
||||
LOGGER.warn("Image path request failed");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSuccessResponse(int responseCode) {
|
||||
return responseCode >= 200 && responseCode <= 299;
|
||||
}
|
||||
}
|
||||
|
@@ -23,18 +23,26 @@
|
||||
|
||||
package com.iluwatar.api.gateway;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* An adapter to communicate with the Price microservice.
|
||||
*/
|
||||
@Component
|
||||
public class PriceClientImpl implements PriceClient {
|
||||
private static final Logger LOGGER = getLogger(PriceClientImpl.class);
|
||||
|
||||
/**
|
||||
* Makes a simple HTTP Get request to the Price microservice.
|
||||
*
|
||||
@@ -49,12 +57,26 @@ public class PriceClientImpl implements PriceClient {
|
||||
.build();
|
||||
|
||||
try {
|
||||
LOGGER.info("Sending request to fetch price info");
|
||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
||||
logResponse(httpResponse);
|
||||
return httpResponse.body();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
LOGGER.error("Failure occurred while getting price info", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void logResponse(HttpResponse<String> httpResponse) {
|
||||
if (isSuccessResponse(httpResponse.statusCode())) {
|
||||
LOGGER.info("Price info received successfully");
|
||||
} else {
|
||||
LOGGER.warn("Price info request failed");
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSuccessResponse(int responseCode) {
|
||||
return responseCode >= 200 && responseCode <= 299;
|
||||
}
|
||||
}
|
||||
|
@@ -23,15 +23,20 @@
|
||||
|
||||
package com.iluwatar.image.microservice;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
/**
|
||||
* Exposes the Image microservice's endpoints.
|
||||
*/
|
||||
@RestController
|
||||
public class ImageController {
|
||||
private static final Logger LOGGER = getLogger(ImageController.class);
|
||||
|
||||
/**
|
||||
* An endpoint for a user to retrieve an image path.
|
||||
@@ -40,6 +45,7 @@ public class ImageController {
|
||||
*/
|
||||
@RequestMapping(value = "/image-path", method = RequestMethod.GET)
|
||||
public String getImagePath() {
|
||||
LOGGER.info("Successfully found image path");
|
||||
return "/product-image.png";
|
||||
}
|
||||
}
|
||||
|
@@ -23,15 +23,20 @@
|
||||
|
||||
package com.iluwatar.price.microservice;
|
||||
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
|
||||
/**
|
||||
* Exposes the Price microservice's endpoints.
|
||||
*/
|
||||
@RestController
|
||||
public class PriceController {
|
||||
private static final Logger LOGGER = getLogger(PriceController.class);
|
||||
|
||||
/**
|
||||
* An endpoint for a user to retrieve a product's price.
|
||||
@@ -40,6 +45,7 @@ public class PriceController {
|
||||
*/
|
||||
@RequestMapping(value = "/price", method = RequestMethod.GET)
|
||||
public String getPrice() {
|
||||
LOGGER.info("Successfully found price info");
|
||||
return "20";
|
||||
}
|
||||
}
|
||||
|
@@ -9,22 +9,137 @@ tags:
|
||||
---
|
||||
|
||||
## Also known as
|
||||
|
||||
Given/When/Then
|
||||
|
||||
## Intent
|
||||
The Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
|
||||
|
||||
Arrange/Act/Assert (AAA) is a pattern for organizing unit tests.
|
||||
It breaks tests down into three clear and distinct steps:
|
||||
|
||||
1. Arrange: Perform the setup and initialization required for the test.
|
||||
2. Act: Take action(s) required for the test.
|
||||
3. Assert: Verify the outcome(s) of the test.
|
||||
|
||||
## Explanation
|
||||
|
||||
This pattern has several significant benefits. It creates a clear separation between a test's
|
||||
setup, operations, and results. This structure makes the code easier to read and understand. If
|
||||
you place the steps in order and format your code to separate them, you can scan a test and
|
||||
quickly comprehend what it does.
|
||||
|
||||
It also enforces a certain degree of discipline when you write your tests. You have to think
|
||||
clearly about the three steps your test will perform. It makes tests more natural to write at
|
||||
the same time since you already have an outline.
|
||||
|
||||
Real world example
|
||||
|
||||
> We need to write comprehensive and clear unit test suite for a class.
|
||||
|
||||
In plain words
|
||||
|
||||
> Arrange/Act/Assert is a testing pattern that organizes tests into three clear steps for easy
|
||||
> maintenance.
|
||||
|
||||
WikiWikiWeb says
|
||||
|
||||
> Arrange/Act/Assert is a pattern for arranging and formatting code in UnitTest methods.
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Let's first introduce our `Cash` class to be unit tested.
|
||||
|
||||
```java
|
||||
public class Cash {
|
||||
|
||||
private int amount;
|
||||
|
||||
Cash(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
void plus(int addend) {
|
||||
amount += addend;
|
||||
}
|
||||
|
||||
boolean minus(int subtrahend) {
|
||||
if (amount >= subtrahend) {
|
||||
amount -= subtrahend;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int count() {
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly
|
||||
separated steps for each unit test.
|
||||
|
||||
```java
|
||||
public class CashAAATest {
|
||||
|
||||
@Test
|
||||
public void testPlus() {
|
||||
//Arrange
|
||||
var cash = new Cash(3);
|
||||
//Act
|
||||
cash.plus(4);
|
||||
//Assert
|
||||
assertEquals(7, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(8);
|
||||
//Act
|
||||
var result = cash.minus(5);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(3, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsufficientMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(1);
|
||||
//Act
|
||||
var result = cash.minus(6);
|
||||
//Assert
|
||||
assertFalse(result);
|
||||
assertEquals(1, cash.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
//Arrange
|
||||
var cash = new Cash(5);
|
||||
//Act
|
||||
cash.plus(6);
|
||||
var result = cash.minus(3);
|
||||
//Assert
|
||||
assertTrue(result);
|
||||
assertEquals(8, cash.count());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Applicability
|
||||
|
||||
Use Arrange/Act/Assert pattern when
|
||||
|
||||
* you need to structure your unit tests so they're easier to read, maintain, and enhance.
|
||||
* You need to structure your unit tests so that they're easier to read, maintain, and enhance.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx)
|
||||
* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
|
||||
* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html)
|
||||
* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf)
|
||||
* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35)
|
||||
* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05)
|
||||
|
@@ -75,19 +75,18 @@ public class Wizard {
|
||||
Next we present the spell hierarchy.
|
||||
|
||||
```java
|
||||
public abstract class Command {
|
||||
public interface Command {
|
||||
|
||||
public abstract void execute(Target target);
|
||||
void execute(Target target);
|
||||
|
||||
public abstract void undo();
|
||||
void undo();
|
||||
|
||||
public abstract void redo();
|
||||
void redo();
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
String toString();
|
||||
}
|
||||
|
||||
public class InvisibilitySpell extends Command {
|
||||
public class InvisibilitySpell implements Command {
|
||||
|
||||
private Target target;
|
||||
|
||||
@@ -117,7 +116,7 @@ public class InvisibilitySpell extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
public class ShrinkSpell extends Command {
|
||||
public class ShrinkSpell implements Command {
|
||||
|
||||
private Size oldSize;
|
||||
private Target target;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 75 KiB |
@@ -4,7 +4,7 @@ package com.iluwatar.command {
|
||||
+ App()
|
||||
+ main(args : String[]) {static}
|
||||
}
|
||||
abstract class Command {
|
||||
interface Command {
|
||||
+ Command()
|
||||
+ execute(Target) {abstract}
|
||||
+ redo() {abstract}
|
||||
@@ -77,7 +77,7 @@ ShrinkSpell --> "-oldSize" Size
|
||||
InvisibilitySpell --> "-target" Target
|
||||
ShrinkSpell --> "-target" Target
|
||||
Target --> "-visibility" Visibility
|
||||
Goblin --|> Target
|
||||
InvisibilitySpell --|> Command
|
||||
ShrinkSpell --|> Command
|
||||
@enduml
|
||||
Goblin --|> Target
|
||||
InvisibilitySpell ..|> Command
|
||||
ShrinkSpell ..|> Command
|
||||
@enduml
|
||||
|
@@ -26,15 +26,12 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* Interface for Commands.
|
||||
*/
|
||||
public abstract class Command {
|
||||
public interface Command {
|
||||
void execute(Target target);
|
||||
|
||||
public abstract void execute(Target target);
|
||||
void undo();
|
||||
|
||||
public abstract void undo();
|
||||
|
||||
public abstract void redo();
|
||||
|
||||
@Override
|
||||
public abstract String toString();
|
||||
void redo();
|
||||
|
||||
String toString();
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* InvisibilitySpell is a concrete command.
|
||||
*/
|
||||
public class InvisibilitySpell extends Command {
|
||||
public class InvisibilitySpell implements Command {
|
||||
|
||||
private Target target;
|
||||
|
||||
|
@@ -26,7 +26,7 @@ package com.iluwatar.command;
|
||||
/**
|
||||
* ShrinkSpell is a concrete command.
|
||||
*/
|
||||
public class ShrinkSpell extends Command {
|
||||
public class ShrinkSpell implements Command {
|
||||
|
||||
private Size oldSize;
|
||||
private Target target;
|
||||
|
@@ -46,17 +46,18 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
final var logger = LoggerFactory.getLogger(App.class);
|
||||
var guard = new Guard();
|
||||
var thief = new Thief();
|
||||
|
||||
final Logger logger = LoggerFactory.getLogger(App.class);
|
||||
Guard guard = new Guard();
|
||||
Thief thief = new Thief();
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (guard instanceof Permission) {
|
||||
guard.enter();
|
||||
} else {
|
||||
logger.info("You have no permission to enter, please leave this area");
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (thief instanceof Permission) {
|
||||
thief.steal();
|
||||
} else {
|
||||
|
@@ -28,11 +28,9 @@ import org.slf4j.LoggerFactory;
|
||||
* Class defining Guard.
|
||||
*/
|
||||
public class Guard implements Permission {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Guard.class);
|
||||
|
||||
protected static void enter() {
|
||||
|
||||
protected void enter() {
|
||||
LOGGER.info("You can enter");
|
||||
}
|
||||
}
|
||||
|
@@ -28,14 +28,13 @@ import org.slf4j.LoggerFactory;
|
||||
* Class defining Thief.
|
||||
*/
|
||||
public class Thief {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Thief.class);
|
||||
|
||||
protected static void steal() {
|
||||
protected void steal() {
|
||||
LOGGER.info("Steal valuable items");
|
||||
}
|
||||
|
||||
protected static void doNothing() {
|
||||
protected void doNothing() {
|
||||
LOGGER.info("Pretend nothing happened and just leave");
|
||||
}
|
||||
}
|
||||
|
@@ -30,7 +30,6 @@ public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@ public class GuardTest {
|
||||
|
||||
@Test
|
||||
public void testGuard() {
|
||||
Guard guard = new Guard();
|
||||
var guard = new Guard();
|
||||
assertThat(guard, instanceOf(Permission.class));
|
||||
}
|
||||
}
|
@@ -21,9 +21,11 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Thief test
|
||||
@@ -31,7 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
public class ThiefTest {
|
||||
@Test
|
||||
public void testThief() {
|
||||
Thief thief = new Thief();
|
||||
assertFalse(thief instanceof Permission);
|
||||
var thief = new Thief();
|
||||
assertThat(thief, not(instanceOf(Permission.class)));
|
||||
}
|
||||
}
|
@@ -22,38 +22,39 @@
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>master-worker-pattern</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>master-worker-pattern</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.masterworker.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>com.iluwatar.masterworker.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@@ -34,27 +34,25 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>The <b><em>Master-Worker</em></b> pattern is used when the problem at hand can be solved by
|
||||
* dividing into
|
||||
* multiple parts which need to go through the same computation and may need to be aggregated to get
|
||||
* final result. Parallel processing is performed using a system consisting of a master and some
|
||||
* number of workers, where a master divides the work among the workers, gets the result back from
|
||||
* them and assimilates all the results to give final result. The only communication is between the
|
||||
* master and the worker - none of the workers communicate among one another and the user only
|
||||
* communicates with the master to get required job done.</p>
|
||||
* dividing into multiple parts which need to go through the same computation and may need to be
|
||||
* aggregated to get final result. Parallel processing is performed using a system consisting of a
|
||||
* master and some number of workers, where a master divides the work among the workers, gets the
|
||||
* result back from them and assimilates all the results to give final result. The only
|
||||
* communication is between the master and the worker - none of the workers communicate among one
|
||||
* another and the user only communicates with the master to get required job done.</p>
|
||||
* <p>In our example, we have generic abstract classes {@link MasterWorker}, {@link Master} and
|
||||
* {@link Worker} which
|
||||
* have to be extended by the classes which will perform the specific job at hand (in this case
|
||||
* finding transpose of matrix, done by {@link ArrayTransposeMasterWorker}, {@link
|
||||
* ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work into
|
||||
* parts to be given to the workers, collects the results from the workers and aggregates it when
|
||||
* all workers have responded before returning the solution. The Worker class extends the Thread
|
||||
* class to enable parallel processing, and does the work once the data has been received from the
|
||||
* Master. The MasterWorker contains a reference to the Master class, gets the input from the App
|
||||
* and passes it on to the Master. These 3 classes define the system which computes the result. We
|
||||
* also have 2 abstract classes {@link Input} and {@link Result}, which contain the input data and
|
||||
* result data respectively. The Input class also has an abstract method divideData which defines
|
||||
* how the data is to be divided into segments. These classes are extended by {@link ArrayInput} and
|
||||
* {@link ArrayResult}.</p>
|
||||
* {@link Worker} which have to be extended by the classes which will perform the specific job at
|
||||
* hand (in this case finding transpose of matrix, done by {@link ArrayTransposeMasterWorker},
|
||||
* {@link ArrayTransposeMaster} and {@link ArrayTransposeWorker}). The Master class divides the work
|
||||
* into parts to be given to the workers, collects the results from the workers and aggregates it
|
||||
* when all workers have responded before returning the solution. The Worker class extends the
|
||||
* Thread class to enable parallel processing, and does the work once the data has been received
|
||||
* from the Master. The MasterWorker contains a reference to the Master class, gets the input from
|
||||
* the App and passes it on to the Master. These 3 classes define the system which computes the
|
||||
* result. We also have 2 abstract classes {@link Input} and {@link Result}, which contain the input
|
||||
* data and result data respectively. The Input class also has an abstract method divideData which
|
||||
* defines how the data is to be divided into segments. These classes are extended by {@link
|
||||
* ArrayInput} and {@link ArrayResult}.</p>
|
||||
*/
|
||||
|
||||
public class App {
|
||||
@@ -68,12 +66,12 @@ public class App {
|
||||
*/
|
||||
|
||||
public static void main(String[] args) {
|
||||
ArrayTransposeMasterWorker mw = new ArrayTransposeMasterWorker();
|
||||
int rows = 10;
|
||||
int columns = 20;
|
||||
int[][] inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
|
||||
ArrayInput input = new ArrayInput(inputMatrix);
|
||||
ArrayResult result = (ArrayResult) mw.getResult(input);
|
||||
var mw = new ArrayTransposeMasterWorker();
|
||||
var rows = 10;
|
||||
var columns = 20;
|
||||
var inputMatrix = ArrayUtilityMethods.createRandomIntMatrix(rows, columns);
|
||||
var input = new ArrayInput(inputMatrix);
|
||||
var result = (ArrayResult) mw.getResult(input);
|
||||
if (result != null) {
|
||||
ArrayUtilityMethods.printMatrix(inputMatrix);
|
||||
ArrayUtilityMethods.printMatrix(result.data);
|
||||
|
@@ -25,6 +25,7 @@ package com.iluwatar.masterworker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Class ArrayInput extends abstract class {@link Input} and contains data of type int[][].
|
||||
@@ -37,12 +38,12 @@ public class ArrayInput extends Input<int[][]> {
|
||||
}
|
||||
|
||||
static int[] makeDivisions(int[][] data, int num) {
|
||||
int initialDivision = data.length / num; //equally dividing
|
||||
int[] divisions = new int[num];
|
||||
var initialDivision = data.length / num; //equally dividing
|
||||
var divisions = new int[num];
|
||||
Arrays.fill(divisions, initialDivision);
|
||||
if (initialDivision * num != data.length) {
|
||||
int extra = data.length - initialDivision * num;
|
||||
int l = 0;
|
||||
var extra = data.length - initialDivision * num;
|
||||
var l = 0;
|
||||
//equally dividing extra among all parts
|
||||
while (extra > 0) {
|
||||
divisions[l] = divisions[l] + 1;
|
||||
@@ -58,22 +59,20 @@ public class ArrayInput extends Input<int[][]> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<Input> divideData(int num) {
|
||||
public List<Input<int[][]>> divideData(int num) {
|
||||
if (this.data == null) {
|
||||
return null;
|
||||
} else {
|
||||
int[] divisions = makeDivisions(this.data, num);
|
||||
ArrayList<Input> result = new ArrayList<Input>(num);
|
||||
int rowsDone = 0; //number of rows divided so far
|
||||
for (int i = 0; i < num; i++) {
|
||||
int rows = divisions[i];
|
||||
var divisions = makeDivisions(this.data, num);
|
||||
var result = new ArrayList<Input<int[][]>>(num);
|
||||
var rowsDone = 0; //number of rows divided so far
|
||||
for (var i = 0; i < num; i++) {
|
||||
var rows = divisions[i];
|
||||
if (rows != 0) {
|
||||
int[][] divided = new int[rows][this.data[0].length];
|
||||
for (int j = 0; j < rows; j++) {
|
||||
divided[j] = this.data[rowsDone + j];
|
||||
}
|
||||
var divided = new int[rows][this.data[0].length];
|
||||
System.arraycopy(this.data, rowsDone, divided, 0, rows);
|
||||
rowsDone += rows;
|
||||
ArrayInput dividedInput = new ArrayInput(divided);
|
||||
var dividedInput = new ArrayInput(divided);
|
||||
result.add(dividedInput);
|
||||
} else {
|
||||
break; //rest of divisions will also be 0
|
||||
|
@@ -47,8 +47,8 @@ public class ArrayUtilityMethods {
|
||||
if (a1.length != a2.length) {
|
||||
return false;
|
||||
} else {
|
||||
boolean answer = false;
|
||||
for (int i = 0; i < a1.length; i++) {
|
||||
var answer = false;
|
||||
for (var i = 0; i < a1.length; i++) {
|
||||
if (a1[i] == a2[i]) {
|
||||
answer = true;
|
||||
} else {
|
||||
@@ -69,8 +69,8 @@ public class ArrayUtilityMethods {
|
||||
if (m1.length != m2.length) {
|
||||
return false;
|
||||
} else {
|
||||
boolean answer = false;
|
||||
for (int i = 0; i < m1.length; i++) {
|
||||
var answer = false;
|
||||
for (var i = 0; i < m1.length; i++) {
|
||||
if (arraysSame(m1[i], m2[i])) {
|
||||
answer = true;
|
||||
} else {
|
||||
@@ -88,9 +88,9 @@ public class ArrayUtilityMethods {
|
||||
* @return it (int[][]).
|
||||
*/
|
||||
public static int[][] createRandomIntMatrix(int rows, int columns) {
|
||||
int[][] matrix = new int[rows][columns];
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
var matrix = new int[rows][columns];
|
||||
for (var i = 0; i < rows; i++) {
|
||||
for (var j = 0; j < columns; j++) {
|
||||
//filling cells in matrix
|
||||
matrix[i][j] = RANDOM.nextInt(10);
|
||||
}
|
||||
@@ -104,9 +104,9 @@ public class ArrayUtilityMethods {
|
||||
|
||||
public static void printMatrix(int[][] matrix) {
|
||||
//prints out int[][]
|
||||
for (int i = 0; i < matrix.length; i++) {
|
||||
for (int j = 0; j < matrix[0].length; j++) {
|
||||
LOGGER.info(matrix[i][j] + " ");
|
||||
for (var ints : matrix) {
|
||||
for (var j = 0; j < matrix[0].length; j++) {
|
||||
LOGGER.info(ints[j] + " ");
|
||||
}
|
||||
LOGGER.info("");
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The abstract Input class, having 1 public field which contains input data, and abstract method
|
||||
@@ -40,5 +40,5 @@ public abstract class Input<T> {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public abstract ArrayList<Input> divideData(int num);
|
||||
public abstract List<Input<T>> divideData(int num);
|
||||
}
|
||||
|
@@ -40,7 +40,7 @@ public abstract class MasterWorker {
|
||||
|
||||
abstract Master setMaster(int numOfWorkers);
|
||||
|
||||
public Result getResult(Input input) {
|
||||
public Result<?> getResult(Input<?> input) {
|
||||
this.master.doWork(input);
|
||||
return this.master.getFinalResult();
|
||||
}
|
||||
|
@@ -27,7 +27,8 @@ import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.system.systemworkers.ArrayTransposeWorker;
|
||||
import com.iluwatar.masterworker.system.systemworkers.Worker;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
* Class ArrayTransposeMaster extends abstract class {@link Master} and contains definition of
|
||||
@@ -41,35 +42,33 @@ public class ArrayTransposeMaster extends Master {
|
||||
|
||||
@Override
|
||||
ArrayList<Worker> setWorkers(int num) {
|
||||
ArrayList<Worker> ws = new ArrayList<Worker>(num);
|
||||
for (int i = 0; i < num; i++) {
|
||||
ws.add(new ArrayTransposeWorker(this, i + 1));
|
||||
//i+1 will be id
|
||||
}
|
||||
return ws;
|
||||
//i+1 will be id
|
||||
return IntStream.range(0, num)
|
||||
.mapToObj(i -> new ArrayTransposeWorker(this, i + 1))
|
||||
.collect(Collectors.toCollection(() -> new ArrayList<>(num)));
|
||||
}
|
||||
|
||||
@Override
|
||||
ArrayResult aggregateData() {
|
||||
// number of rows in final result is number of rows in any of obtained results from workers
|
||||
int rows = ((ArrayResult) this.getAllResultData()
|
||||
.get(this.getAllResultData().keys().nextElement())).data.length;
|
||||
int columns =
|
||||
0; //number of columns is sum of number of columns in all results obtained from workers
|
||||
for (Enumeration<Integer> e = this.getAllResultData().keys(); e.hasMoreElements(); ) {
|
||||
columns += ((ArrayResult) this.getAllResultData().get(e.nextElement())).data[0].length;
|
||||
var allResultData = this.getAllResultData();
|
||||
var rows = ((ArrayResult) allResultData.elements().nextElement()).data.length;
|
||||
var elements = allResultData.elements();
|
||||
var columns = 0; // columns = sum of number of columns in all results obtained from workers
|
||||
while (elements.hasMoreElements()) {
|
||||
columns += ((ArrayResult) elements.nextElement()).data[0].length;
|
||||
}
|
||||
int[][] resultData = new int[rows][columns];
|
||||
int columnsDone = 0; //columns aggregated so far
|
||||
for (int i = 0; i < this.getExpectedNumResults(); i++) {
|
||||
var resultData = new int[rows][columns];
|
||||
var columnsDone = 0; //columns aggregated so far
|
||||
var workers = this.getWorkers();
|
||||
for (var i = 0; i < this.getExpectedNumResults(); i++) {
|
||||
//result obtained from ith worker
|
||||
int[][] work =
|
||||
((ArrayResult) this.getAllResultData().get(this.getWorkers().get(i).getWorkerId())).data;
|
||||
for (int m = 0; m < work.length; m++) {
|
||||
var worker = workers.get(i);
|
||||
var workerId = worker.getWorkerId();
|
||||
var work = ((ArrayResult) allResultData.get(workerId)).data;
|
||||
for (var m = 0; m < work.length; m++) {
|
||||
//m = row number, n = columns number
|
||||
for (int n = 0; n < work[0].length; n++) {
|
||||
resultData[m][columnsDone + n] = work[m][n];
|
||||
}
|
||||
System.arraycopy(work[m], 0, resultData[m], columnsDone, work[0].length);
|
||||
}
|
||||
columnsDone += work[0].length;
|
||||
}
|
||||
|
@@ -26,8 +26,8 @@ package com.iluwatar.masterworker.system.systemmaster;
|
||||
import com.iluwatar.masterworker.Input;
|
||||
import com.iluwatar.masterworker.Result;
|
||||
import com.iluwatar.masterworker.system.systemworkers.Worker;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The abstract Master class which contains private fields numOfWorkers (number of workers), workers
|
||||
@@ -38,24 +38,24 @@ import java.util.Hashtable;
|
||||
|
||||
public abstract class Master {
|
||||
private final int numOfWorkers;
|
||||
private final ArrayList<Worker> workers;
|
||||
private final List<Worker> workers;
|
||||
private final Hashtable<Integer, Result<?>> allResultData;
|
||||
private int expectedNumResults;
|
||||
private final Hashtable<Integer, Result> allResultData;
|
||||
private Result finalResult;
|
||||
private Result<?> finalResult;
|
||||
|
||||
Master(int numOfWorkers) {
|
||||
this.numOfWorkers = numOfWorkers;
|
||||
this.workers = setWorkers(numOfWorkers);
|
||||
this.expectedNumResults = 0;
|
||||
this.allResultData = new Hashtable<Integer, Result>(numOfWorkers);
|
||||
this.allResultData = new Hashtable<>(numOfWorkers);
|
||||
this.finalResult = null;
|
||||
}
|
||||
|
||||
public Result getFinalResult() {
|
||||
public Result<?> getFinalResult() {
|
||||
return this.finalResult;
|
||||
}
|
||||
|
||||
Hashtable<Integer, Result> getAllResultData() {
|
||||
Hashtable<Integer, Result<?>> getAllResultData() {
|
||||
return this.allResultData;
|
||||
}
|
||||
|
||||
@@ -63,34 +63,41 @@ public abstract class Master {
|
||||
return this.expectedNumResults;
|
||||
}
|
||||
|
||||
ArrayList<Worker> getWorkers() {
|
||||
List<Worker> getWorkers() {
|
||||
return this.workers;
|
||||
}
|
||||
|
||||
abstract ArrayList<Worker> setWorkers(int num);
|
||||
abstract List<Worker> setWorkers(int num);
|
||||
|
||||
public void doWork(Input input) {
|
||||
public void doWork(Input<?> input) {
|
||||
divideWork(input);
|
||||
}
|
||||
|
||||
private void divideWork(Input input) {
|
||||
ArrayList<Input> dividedInput = input.divideData(numOfWorkers);
|
||||
private void divideWork(Input<?> input) {
|
||||
var dividedInput = input.divideData(numOfWorkers);
|
||||
if (dividedInput != null) {
|
||||
this.expectedNumResults = dividedInput.size();
|
||||
for (int i = 0; i < this.expectedNumResults; i++) {
|
||||
for (var i = 0; i < this.expectedNumResults; i++) {
|
||||
//ith division given to ith worker in this.workers
|
||||
this.workers.get(i).setReceivedData(this, dividedInput.get(i));
|
||||
this.workers.get(i).run();
|
||||
this.workers.get(i).start();
|
||||
}
|
||||
for (var i = 0; i < this.expectedNumResults; i++) {
|
||||
try {
|
||||
this.workers.get(i).join();
|
||||
} catch (InterruptedException e) {
|
||||
System.err.println("Error while executing thread");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveData(Result data, Worker w) {
|
||||
public void receiveData(Result<?> data, Worker w) {
|
||||
//check if can receive..if yes:
|
||||
collectResult(data, w.getWorkerId());
|
||||
}
|
||||
|
||||
private void collectResult(Result data, int workerId) {
|
||||
private void collectResult(Result<?> data, int workerId) {
|
||||
this.allResultData.put(workerId, data);
|
||||
if (this.allResultData.size() == this.expectedNumResults) {
|
||||
//all data received
|
||||
@@ -98,5 +105,5 @@ public abstract class Master {
|
||||
}
|
||||
}
|
||||
|
||||
abstract Result aggregateData();
|
||||
abstract Result<?> aggregateData();
|
||||
}
|
||||
|
@@ -41,12 +41,12 @@ public class ArrayTransposeWorker extends Worker {
|
||||
@Override
|
||||
ArrayResult executeOperation() {
|
||||
//number of rows in result matrix is equal to number of columns in input matrix and vice versa
|
||||
ArrayInput arrayInput = (ArrayInput) this.getReceivedData();
|
||||
final int rows = arrayInput.data[0].length;
|
||||
final int cols = arrayInput.data.length;
|
||||
int[][] resultData = new int[rows][cols];
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
var arrayInput = (ArrayInput) this.getReceivedData();
|
||||
final var rows = arrayInput.data[0].length;
|
||||
final var cols = arrayInput.data.length;
|
||||
var resultData = new int[rows][cols];
|
||||
for (var i = 0; i < cols; i++) {
|
||||
for (var j = 0; j < rows; j++) {
|
||||
//flipping element positions along diagonal
|
||||
resultData[j][i] = arrayInput.data[i][j];
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ import com.iluwatar.masterworker.system.systemmaster.Master;
|
||||
public abstract class Worker extends Thread {
|
||||
private final Master master;
|
||||
private final int workerId;
|
||||
private Input receivedData;
|
||||
private Input<?> receivedData;
|
||||
|
||||
Worker(Master master, int id) {
|
||||
this.master = master;
|
||||
@@ -47,23 +47,23 @@ public abstract class Worker extends Thread {
|
||||
return this.workerId;
|
||||
}
|
||||
|
||||
Input getReceivedData() {
|
||||
Input<?> getReceivedData() {
|
||||
return this.receivedData;
|
||||
}
|
||||
|
||||
public void setReceivedData(Master m, Input i) {
|
||||
public void setReceivedData(Master m, Input<?> i) {
|
||||
//check if ready to receive..if yes:
|
||||
this.receivedData = i;
|
||||
}
|
||||
|
||||
abstract Result executeOperation();
|
||||
abstract Result<?> executeOperation();
|
||||
|
||||
private void sendToMaster(Result data) {
|
||||
private void sendToMaster(Result<?> data) {
|
||||
this.master.receiveData(data, this);
|
||||
}
|
||||
|
||||
public void run() { //from Thread class
|
||||
Result work = executeOperation();
|
||||
var work = executeOperation();
|
||||
sendToMaster(work);
|
||||
}
|
||||
}
|
||||
|
@@ -23,38 +23,39 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import java.util.ArrayList;
|
||||
import static com.iluwatar.masterworker.ArrayUtilityMethods.matricesSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.Random;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing divideData method in {@link ArrayInput} class.
|
||||
*/
|
||||
* Testing divideData method in {@link ArrayInput} class.
|
||||
*/
|
||||
|
||||
class ArrayInputTest {
|
||||
|
||||
@Test
|
||||
void divideDataTest() {
|
||||
int rows = 10;
|
||||
int columns = 10;
|
||||
int[][] inputMatrix = new int[rows][columns];
|
||||
Random rand = new Random();
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < columns; j++) {
|
||||
var rows = 10;
|
||||
var columns = 10;
|
||||
var inputMatrix = new int[rows][columns];
|
||||
var rand = new Random();
|
||||
for (var i = 0; i < rows; i++) {
|
||||
for (var j = 0; j < columns; j++) {
|
||||
inputMatrix[i][j] = rand.nextInt(10);
|
||||
}
|
||||
}
|
||||
ArrayInput i = new ArrayInput(inputMatrix);
|
||||
ArrayList<Input> table = i.divideData(4);
|
||||
int[][] division1 = new int[][] {inputMatrix[0], inputMatrix[1], inputMatrix[2]};
|
||||
int[][] division2 = new int[][] {inputMatrix[3], inputMatrix[4], inputMatrix[5]};
|
||||
int[][] division3 = new int[][] {inputMatrix[6], inputMatrix[7]};
|
||||
int[][] division4 = new int[][] {inputMatrix[8], inputMatrix[9]};
|
||||
assertTrue(ArrayUtilityMethods.matricesSame((int[][]) table.get(0).data, division1)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(1).data, division2)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(2).data, division3)
|
||||
&& ArrayUtilityMethods.matricesSame((int[][]) table.get(3).data, division4));
|
||||
var i = new ArrayInput(inputMatrix);
|
||||
var table = i.divideData(4);
|
||||
var division1 = new int[][]{inputMatrix[0], inputMatrix[1], inputMatrix[2]};
|
||||
var division2 = new int[][]{inputMatrix[3], inputMatrix[4], inputMatrix[5]};
|
||||
var division3 = new int[][]{inputMatrix[6], inputMatrix[7]};
|
||||
var division4 = new int[][]{inputMatrix[8], inputMatrix[9]};
|
||||
assertTrue(matricesSame(table.get(0).data, division1)
|
||||
&& matricesSame(table.get(1).data, division2)
|
||||
&& matricesSame(table.get(2).data, division3)
|
||||
&& matricesSame(table.get(3).data, division4));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,27 +23,27 @@
|
||||
|
||||
package com.iluwatar.masterworker;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing utility methods in {@link ArrayUtilityMethods} class.
|
||||
*/
|
||||
* Testing utility methods in {@link ArrayUtilityMethods} class.
|
||||
*/
|
||||
|
||||
class ArrayUtilityMethodsTest {
|
||||
|
||||
@Test
|
||||
void arraysSameTest() {
|
||||
int[] arr1 = new int[] {1,4,2,6};
|
||||
int[] arr2 = new int[] {1,4,2,6};
|
||||
var arr1 = new int[]{1, 4, 2, 6};
|
||||
var arr2 = new int[]{1, 4, 2, 6};
|
||||
assertTrue(ArrayUtilityMethods.arraysSame(arr1, arr2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void matricesSameTest() {
|
||||
int[][] matrix1 = new int[][] {{1,4,2,6},{5,8,6,7}};
|
||||
int[][] matrix2 = new int[][] {{1,4,2,6},{5,8,6,7}};
|
||||
var matrix1 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
|
||||
var matrix2 = new int[][]{{1, 4, 2, 6}, {5, 8, 6, 7}};
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(matrix1, matrix2));
|
||||
}
|
||||
|
||||
|
@@ -23,25 +23,38 @@
|
||||
|
||||
package com.iluwatar.masterworker.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.iluwatar.masterworker.ArrayInput;
|
||||
import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
|
||||
*/
|
||||
* Testing getResult method in {@link ArrayTransposeMasterWorker} class.
|
||||
*/
|
||||
|
||||
class ArrayTransposeMasterWorkerTest {
|
||||
|
||||
@Test
|
||||
void getResultTest() {
|
||||
ArrayTransposeMasterWorker atmw = new ArrayTransposeMasterWorker();
|
||||
int[][] matrix = new int[][] {{1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}, {1,2,3,4,5}};
|
||||
int[][] matrixTranspose = new int[][] {{1,1,1,1,1}, {2,2,2,2,2}, {3,3,3,3,3}, {4,4,4,4,4}, {5,5,5,5,5}};
|
||||
ArrayInput i = new ArrayInput(matrix);
|
||||
ArrayResult r = (ArrayResult) atmw.getResult(i);
|
||||
var atmw = new ArrayTransposeMasterWorker();
|
||||
var matrix = new int[][]{
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5},
|
||||
{1, 2, 3, 4, 5}
|
||||
};
|
||||
var matrixTranspose = new int[][]{
|
||||
{1, 1, 1, 1, 1},
|
||||
{2, 2, 2, 2, 2},
|
||||
{3, 3, 3, 3, 3},
|
||||
{4, 4, 4, 4, 4},
|
||||
{5, 5, 5, 5, 5}
|
||||
};
|
||||
var i = new ArrayInput(matrix);
|
||||
var r = (ArrayResult) atmw.getResult(i);
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -23,29 +23,29 @@
|
||||
|
||||
package com.iluwatar.masterworker.system.systemworkers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import com.iluwatar.masterworker.ArrayInput;
|
||||
import com.iluwatar.masterworker.ArrayResult;
|
||||
import com.iluwatar.masterworker.ArrayUtilityMethods;
|
||||
import com.iluwatar.masterworker.system.systemmaster.ArrayTransposeMaster;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Testing executeOperation method in {@link ArrayTransposeWorker} class.
|
||||
*/
|
||||
* Testing executeOperation method in {@link ArrayTransposeWorker} class.
|
||||
*/
|
||||
|
||||
class ArrayTransposeWorkerTest {
|
||||
|
||||
@Test
|
||||
void executeOperationTest() {
|
||||
ArrayTransposeMaster atm = new ArrayTransposeMaster(1);
|
||||
ArrayTransposeWorker atw = new ArrayTransposeWorker(atm, 1);
|
||||
int[][] matrix = new int[][] {{2,4}, {3,5}};
|
||||
int[][] matrixTranspose = new int[][] {{2,3}, {4,5}};
|
||||
ArrayInput i = new ArrayInput(matrix);
|
||||
var atm = new ArrayTransposeMaster(1);
|
||||
var atw = new ArrayTransposeWorker(atm, 1);
|
||||
var matrix = new int[][]{{2, 4}, {3, 5}};
|
||||
var matrixTranspose = new int[][]{{2, 3}, {4, 5}};
|
||||
var i = new ArrayInput(matrix);
|
||||
atw.setReceivedData(atm, i);
|
||||
ArrayResult r = atw.executeOperation();
|
||||
var r = atw.executeOperation();
|
||||
assertTrue(ArrayUtilityMethods.matricesSame(r.data, matrixTranspose));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -27,7 +27,6 @@ package com.iluwatar.mediator;
|
||||
* Action enumeration.
|
||||
*/
|
||||
public enum Action {
|
||||
|
||||
HUNT("hunted a rabbit", "arrives for dinner"),
|
||||
TALE("tells a tale", "comes to listen"),
|
||||
GOLD("found gold", "takes his share of the gold"),
|
||||
|
@@ -55,10 +55,10 @@ public class App {
|
||||
|
||||
// create party and members
|
||||
Party party = new PartyImpl();
|
||||
Hobbit hobbit = new Hobbit();
|
||||
Wizard wizard = new Wizard();
|
||||
Rogue rogue = new Rogue();
|
||||
Hunter hunter = new Hunter();
|
||||
var hobbit = new Hobbit();
|
||||
var wizard = new Wizard();
|
||||
var rogue = new Rogue();
|
||||
var hunter = new Hunter();
|
||||
|
||||
// add party members
|
||||
party.addMember(hobbit);
|
||||
|
@@ -39,7 +39,7 @@ public class PartyImpl implements Party {
|
||||
|
||||
@Override
|
||||
public void act(PartyMember actor, Action action) {
|
||||
for (PartyMember member : members) {
|
||||
for (var member : members) {
|
||||
if (!member.equals(actor)) {
|
||||
member.partyAction(action);
|
||||
}
|
||||
|
@@ -26,15 +26,12 @@ package com.iluwatar.mediator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -43,10 +43,10 @@ public class PartyImplTest {
|
||||
*/
|
||||
@Test
|
||||
public void testPartyAction() {
|
||||
final PartyMember partyMember1 = mock(PartyMember.class);
|
||||
final PartyMember partyMember2 = mock(PartyMember.class);
|
||||
final var partyMember1 = mock(PartyMember.class);
|
||||
final var partyMember2 = mock(PartyMember.class);
|
||||
|
||||
final PartyImpl party = new PartyImpl();
|
||||
final var party = new PartyImpl();
|
||||
party.addMember(partyMember1);
|
||||
party.addMember(partyMember2);
|
||||
|
||||
@@ -58,7 +58,6 @@ public class PartyImplTest {
|
||||
verify(partyMember2).partyAction(Action.GOLD);
|
||||
|
||||
verifyNoMoreInteractions(partyMember1, partyMember2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,24 +23,24 @@
|
||||
|
||||
package com.iluwatar.mediator;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Date: 12/19/15 - 10:13 PM
|
||||
*
|
||||
@@ -48,12 +48,12 @@ import static org.mockito.Mockito.verify;
|
||||
*/
|
||||
public class PartyMemberTest {
|
||||
|
||||
static Collection<Supplier<PartyMember>[]> dataProvider() {
|
||||
return List.of(
|
||||
new Supplier[]{Hobbit::new},
|
||||
new Supplier[]{Hunter::new},
|
||||
new Supplier[]{Rogue::new},
|
||||
new Supplier[]{Wizard::new}
|
||||
static Stream<Arguments> dataProvider() {
|
||||
return Stream.of(
|
||||
Arguments.of((Supplier<PartyMember>) Hobbit::new),
|
||||
Arguments.of((Supplier<PartyMember>) Hunter::new),
|
||||
Arguments.of((Supplier<PartyMember>) Rogue::new),
|
||||
Arguments.of((Supplier<PartyMember>) Wizard::new)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,9 +75,9 @@ public class PartyMemberTest {
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testPartyAction(Supplier<PartyMember> memberSupplier) {
|
||||
final PartyMember member = memberSupplier.get();
|
||||
final var member = memberSupplier.get();
|
||||
|
||||
for (final Action action : Action.values()) {
|
||||
for (final var action : Action.values()) {
|
||||
member.partyAction(action);
|
||||
assertEquals(member.toString() + " " + action.getDescription(), appender.getLastMessage());
|
||||
}
|
||||
@@ -91,16 +91,16 @@ public class PartyMemberTest {
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testAct(Supplier<PartyMember> memberSupplier) {
|
||||
final PartyMember member = memberSupplier.get();
|
||||
final var member = memberSupplier.get();
|
||||
|
||||
member.act(Action.GOLD);
|
||||
assertEquals(0, appender.getLogSize());
|
||||
|
||||
final Party party = mock(Party.class);
|
||||
final var party = mock(Party.class);
|
||||
member.joinedParty(party);
|
||||
assertEquals(member.toString() + " joins the party", appender.getLastMessage());
|
||||
|
||||
for (final Action action : Action.values()) {
|
||||
for (final var action : Action.values()) {
|
||||
member.act(action);
|
||||
assertEquals(member.toString() + " " + action.toString(), appender.getLastMessage());
|
||||
verify(party).act(member, action);
|
||||
@@ -114,16 +114,16 @@ public class PartyMemberTest {
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("dataProvider")
|
||||
public void testToString(Supplier<PartyMember> memberSupplier) throws Exception {
|
||||
final PartyMember member = memberSupplier.get();
|
||||
final Class<? extends PartyMember> memberClass = member.getClass();
|
||||
public void testToString(Supplier<PartyMember> memberSupplier) {
|
||||
final var member = memberSupplier.get();
|
||||
final var memberClass = member.getClass();
|
||||
assertEquals(memberClass.getSimpleName(), member.toString());
|
||||
}
|
||||
|
||||
private class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private static class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
||||
|
||||
public InMemoryAppender(Class clazz) {
|
||||
public InMemoryAppender(Class<?> clazz) {
|
||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||
start();
|
||||
}
|
||||
|
@@ -34,9 +34,12 @@ Let's first define the types of stars we are capable to handle.
|
||||
|
||||
```java
|
||||
public enum StarType {
|
||||
|
||||
SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
|
||||
"dead star"), UNDEFINED("");
|
||||
SUN("sun"),
|
||||
RED_GIANT("red giant"),
|
||||
WHITE_DWARF("white dwarf"),
|
||||
SUPERNOVA("supernova"),
|
||||
DEAD("dead star"),
|
||||
UNDEFINED("");
|
||||
|
||||
private final String title;
|
||||
|
||||
@@ -95,8 +98,7 @@ public class Star {
|
||||
}
|
||||
|
||||
StarMemento getMemento() {
|
||||
|
||||
StarMementoInternal state = new StarMementoInternal();
|
||||
var state = new StarMementoInternal();
|
||||
state.setAgeYears(ageYears);
|
||||
state.setMassTons(massTons);
|
||||
state.setType(type);
|
||||
@@ -104,8 +106,7 @@ public class Star {
|
||||
}
|
||||
|
||||
void setMemento(StarMemento memento) {
|
||||
|
||||
StarMementoInternal state = (StarMementoInternal) memento;
|
||||
var state = (StarMementoInternal) memento;
|
||||
this.type = state.getType();
|
||||
this.ageYears = state.getAgeYears();
|
||||
this.massTons = state.getMassTons();
|
||||
@@ -152,8 +153,8 @@ public class Star {
|
||||
And finally here's how we use the mementos to store and restore star states.
|
||||
|
||||
```java
|
||||
Stack<StarMemento> states = new Stack<>();
|
||||
Star star = new Star(StarType.SUN, 10000000, 500000);
|
||||
var states = new Stack<>();
|
||||
var star = new Star(StarType.SUN, 10000000, 500000);
|
||||
LOGGER.info(star.toString());
|
||||
states.add(star.getMemento());
|
||||
star.timePasses();
|
||||
|
@@ -52,9 +52,9 @@ public class App {
|
||||
* Program entry point.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Stack<StarMemento> states = new Stack<>();
|
||||
var states = new Stack<StarMemento>();
|
||||
|
||||
Star star = new Star(StarType.SUN, 10000000, 500000);
|
||||
var star = new Star(StarType.SUN, 10000000, 500000);
|
||||
LOGGER.info(star.toString());
|
||||
states.add(star.getMemento());
|
||||
star.timePasses();
|
||||
|
@@ -70,22 +70,18 @@ public class Star {
|
||||
}
|
||||
|
||||
StarMemento getMemento() {
|
||||
|
||||
StarMementoInternal state = new StarMementoInternal();
|
||||
var state = new StarMementoInternal();
|
||||
state.setAgeYears(ageYears);
|
||||
state.setMassTons(massTons);
|
||||
state.setType(type);
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
void setMemento(StarMemento memento) {
|
||||
|
||||
StarMementoInternal state = (StarMementoInternal) memento;
|
||||
var state = (StarMementoInternal) memento;
|
||||
this.type = state.getType();
|
||||
this.ageYears = state.getAgeYears();
|
||||
this.massTons = state.getMassTons();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -27,9 +27,12 @@ package com.iluwatar.memento;
|
||||
* StarType enumeration.
|
||||
*/
|
||||
public enum StarType {
|
||||
|
||||
SUN("sun"), RED_GIANT("red giant"), WHITE_DWARF("white dwarf"), SUPERNOVA("supernova"), DEAD(
|
||||
"dead star"), UNDEFINED("");
|
||||
SUN("sun"),
|
||||
RED_GIANT("red giant"),
|
||||
WHITE_DWARF("white dwarf"),
|
||||
SUPERNOVA("supernova"),
|
||||
DEAD("dead star"),
|
||||
UNDEFINED("");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@@ -26,15 +26,12 @@ package com.iluwatar.memento;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -23,10 +23,10 @@
|
||||
|
||||
package com.iluwatar.memento;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 10:08 AM
|
||||
*
|
||||
@@ -39,7 +39,7 @@ public class StarTest {
|
||||
*/
|
||||
@Test
|
||||
public void testTimePasses() {
|
||||
final Star star = new Star(StarType.SUN, 1, 2);
|
||||
final var star = new Star(StarType.SUN, 1, 2);
|
||||
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
@@ -66,16 +66,16 @@ public class StarTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetMemento() {
|
||||
final Star star = new Star(StarType.SUN, 1, 2);
|
||||
final StarMemento firstMemento = star.getMemento();
|
||||
final var star = new Star(StarType.SUN, 1, 2);
|
||||
final var firstMemento = star.getMemento();
|
||||
assertEquals("sun age: 1 years mass: 2 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
final StarMemento secondMemento = star.getMemento();
|
||||
final var secondMemento = star.getMemento();
|
||||
assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
final StarMemento thirdMemento = star.getMemento();
|
||||
final var thirdMemento = star.getMemento();
|
||||
assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
|
||||
|
||||
star.timePasses();
|
||||
|
@@ -47,9 +47,9 @@ public class App {
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// create model, view and controller
|
||||
GiantModel giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
GiantView view = new GiantView();
|
||||
GiantController controller = new GiantController(giant, view);
|
||||
var giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
var view = new GiantView();
|
||||
var controller = new GiantController(giant, view);
|
||||
// initial display
|
||||
controller.updateView();
|
||||
// controller receives some interactions that affect the giant
|
||||
|
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
|
||||
* Fatigue enumeration.
|
||||
*/
|
||||
public enum Fatigue {
|
||||
|
||||
ALERT("alert"), TIRED("tired"), SLEEPING("sleeping");
|
||||
ALERT("alert"),
|
||||
TIRED("tired"),
|
||||
SLEEPING("sleeping");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@@ -36,6 +36,7 @@ public class GiantController {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Health getHealth() {
|
||||
return giant.getHealth();
|
||||
}
|
||||
@@ -44,6 +45,7 @@ public class GiantController {
|
||||
this.giant.setHealth(health);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Fatigue getFatigue() {
|
||||
return giant.getFatigue();
|
||||
}
|
||||
@@ -52,6 +54,7 @@ public class GiantController {
|
||||
this.giant.setFatigue(fatigue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
public Nourishment getNourishment() {
|
||||
return giant.getNourishment();
|
||||
}
|
||||
|
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
|
||||
* Health enumeration.
|
||||
*/
|
||||
public enum Health {
|
||||
|
||||
HEALTHY("healthy"), WOUNDED("wounded"), DEAD("dead");
|
||||
HEALTHY("healthy"),
|
||||
WOUNDED("wounded"),
|
||||
DEAD("dead");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@@ -27,8 +27,9 @@ package com.iluwatar.model.view.controller;
|
||||
* Nourishment enumeration.
|
||||
*/
|
||||
public enum Nourishment {
|
||||
|
||||
SATURATED("saturated"), HUNGRY("hungry"), STARVING("starving");
|
||||
SATURATED("saturated"),
|
||||
HUNGRY("hungry"),
|
||||
STARVING("starving");
|
||||
|
||||
private final String title;
|
||||
|
||||
|
@@ -26,15 +26,12 @@ package com.iluwatar.model.view.controller;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -23,13 +23,13 @@
|
||||
|
||||
package com.iluwatar.model.view.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 2:19 PM
|
||||
*
|
||||
@@ -42,19 +42,20 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetHealth() {
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final Health health : Health.values()) {
|
||||
for (final var health : Health.values()) {
|
||||
controller.setHealth(health);
|
||||
verify(model).setHealth(health);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getHealth();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getHealth();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@@ -65,19 +66,20 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetFatigue() {
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final Fatigue fatigue : Fatigue.values()) {
|
||||
for (final var fatigue : Fatigue.values()) {
|
||||
controller.setFatigue(fatigue);
|
||||
verify(model).setFatigue(fatigue);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getFatigue();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getFatigue();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@@ -88,19 +90,20 @@ public class GiantControllerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetNourishment() {
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
for (final Nourishment nourishment : Nourishment.values()) {
|
||||
for (final var nourishment : Nourishment.values()) {
|
||||
controller.setNourishment(nourishment);
|
||||
verify(model).setNourishment(nourishment);
|
||||
verifyZeroInteractions(view);
|
||||
}
|
||||
|
||||
controller.getNourishment();
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
verify(model).getNourishment();
|
||||
|
||||
verifyNoMoreInteractions(model, view);
|
||||
@@ -108,9 +111,9 @@ public class GiantControllerTest {
|
||||
|
||||
@Test
|
||||
public void testUpdateView() {
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final GiantView view = mock(GiantView.class);
|
||||
final GiantController controller = new GiantController(model, view);
|
||||
final var model = mock(GiantModel.class);
|
||||
final var view = mock(GiantView.class);
|
||||
final var controller = new GiantController(model, view);
|
||||
|
||||
verifyZeroInteractions(model, view);
|
||||
|
||||
|
@@ -23,10 +23,10 @@
|
||||
|
||||
package com.iluwatar.model.view.controller;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Date: 12/20/15 - 2:10 PM
|
||||
*
|
||||
@@ -39,12 +39,13 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetHealth() {
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Health.HEALTHY, model.getHealth());
|
||||
for (final Health health : Health.values()) {
|
||||
var messageFormat = "The giant looks %s, alert and saturated.";
|
||||
for (final var health : Health.values()) {
|
||||
model.setHealth(health);
|
||||
assertEquals(health, model.getHealth());
|
||||
assertEquals("The giant looks " + health.toString() + ", alert and saturated.", model.toString());
|
||||
assertEquals(String.format(messageFormat, health), model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,12 +54,13 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetFatigue() {
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Fatigue.ALERT, model.getFatigue());
|
||||
for (final Fatigue fatigue : Fatigue.values()) {
|
||||
var messageFormat = "The giant looks healthy, %s and saturated.";
|
||||
for (final var fatigue : Fatigue.values()) {
|
||||
model.setFatigue(fatigue);
|
||||
assertEquals(fatigue, model.getFatigue());
|
||||
assertEquals("The giant looks healthy, " + fatigue.toString() + " and saturated.", model.toString());
|
||||
assertEquals(String.format(messageFormat, fatigue), model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,12 +69,13 @@ public class GiantModelTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSetNourishment() {
|
||||
final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
final var model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
|
||||
assertEquals(Nourishment.SATURATED, model.getNourishment());
|
||||
for (final Nourishment nourishment : Nourishment.values()) {
|
||||
var messageFormat = "The giant looks healthy, alert and %s.";
|
||||
for (final var nourishment : Nourishment.values()) {
|
||||
model.setNourishment(nourishment);
|
||||
assertEquals(nourishment, model.getNourishment());
|
||||
assertEquals("The giant looks healthy, alert and " + nourishment.toString() + ".", model.toString());
|
||||
assertEquals(String.format(messageFormat, nourishment), model.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,6 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||
import ch.qos.logback.core.AppenderBase;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -62,9 +61,9 @@ public class GiantViewTest {
|
||||
*/
|
||||
@Test
|
||||
public void testDisplayGiant() {
|
||||
final GiantView view = new GiantView();
|
||||
final var view = new GiantView();
|
||||
|
||||
final GiantModel model = mock(GiantModel.class);
|
||||
final var model = mock(GiantModel.class);
|
||||
view.displayGiant(model);
|
||||
|
||||
assertEquals(model.toString(), appender.getLastMessage());
|
||||
@@ -74,10 +73,10 @@ public class GiantViewTest {
|
||||
/**
|
||||
* Logging Appender Implementation
|
||||
*/
|
||||
public class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
public static class InMemoryAppender extends AppenderBase<ILoggingEvent> {
|
||||
private final List<ILoggingEvent> log = new LinkedList<>();
|
||||
|
||||
public InMemoryAppender(Class clazz) {
|
||||
public InMemoryAppender(Class<?> clazz) {
|
||||
((Logger) LoggerFactory.getLogger(clazz)).addAppender(this);
|
||||
start();
|
||||
}
|
||||
|
@@ -44,9 +44,9 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
FileLoader loader = new FileLoader();
|
||||
FileSelectorJFrame frame = new FileSelectorJFrame();
|
||||
FileSelectorPresenter presenter = new FileSelectorPresenter(frame);
|
||||
var loader = new FileLoader();
|
||||
var frame = new FileSelectorJFrame();
|
||||
var presenter = new FileSelectorPresenter(frame);
|
||||
presenter.setLoader(loader);
|
||||
presenter.start();
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.Serializable;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -59,18 +60,11 @@ public class FileLoader implements Serializable {
|
||||
* Loads the data of the file specified.
|
||||
*/
|
||||
public String loadData() {
|
||||
String dataFileName = this.fileName;
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(new File(dataFileName)))) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
String line;
|
||||
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(line).append('\n');
|
||||
}
|
||||
|
||||
var dataFileName = this.fileName;
|
||||
try (var br = new BufferedReader(new FileReader(new File(dataFileName)))) {
|
||||
var result = br.lines().collect(Collectors.joining("\n"));
|
||||
this.loaded = true;
|
||||
|
||||
return sb.toString();
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("File {} does not exist", dataFileName);
|
||||
}
|
||||
|
@@ -55,16 +55,6 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
*/
|
||||
private final JButton cancel;
|
||||
|
||||
/**
|
||||
* The information label.
|
||||
*/
|
||||
private final JLabel info;
|
||||
|
||||
/**
|
||||
* The contents label.
|
||||
*/
|
||||
private final JLabel contents;
|
||||
|
||||
/**
|
||||
* The text field for giving the name of the file that we want to open.
|
||||
*/
|
||||
@@ -75,11 +65,6 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
*/
|
||||
private final JTextArea area;
|
||||
|
||||
/**
|
||||
* The panel that will hold our widgets.
|
||||
*/
|
||||
private final JPanel panel;
|
||||
|
||||
/**
|
||||
* The Presenter component that the frame will interact with.
|
||||
*/
|
||||
@@ -102,7 +87,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/*
|
||||
* Add the panel.
|
||||
*/
|
||||
this.panel = new JPanel();
|
||||
var panel = new JPanel();
|
||||
panel.setLayout(null);
|
||||
this.add(panel);
|
||||
panel.setBounds(0, 0, 500, 200);
|
||||
@@ -111,32 +96,32 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/*
|
||||
* Add the info label.
|
||||
*/
|
||||
this.info = new JLabel("File Name :");
|
||||
this.panel.add(info);
|
||||
var info = new JLabel("File Name :");
|
||||
panel.add(info);
|
||||
info.setBounds(30, 10, 100, 30);
|
||||
|
||||
/*
|
||||
* Add the contents label.
|
||||
*/
|
||||
this.contents = new JLabel("File contents :");
|
||||
this.panel.add(contents);
|
||||
this.contents.setBounds(30, 100, 120, 30);
|
||||
var contents = new JLabel("File contents :");
|
||||
panel.add(contents);
|
||||
contents.setBounds(30, 100, 120, 30);
|
||||
|
||||
/*
|
||||
* Add the text field.
|
||||
*/
|
||||
this.input = new JTextField(100);
|
||||
this.panel.add(input);
|
||||
panel.add(input);
|
||||
this.input.setBounds(150, 15, 200, 20);
|
||||
|
||||
/*
|
||||
* Add the text area.
|
||||
*/
|
||||
this.area = new JTextArea(100, 100);
|
||||
JScrollPane pane = new JScrollPane(area);
|
||||
var pane = new JScrollPane(area);
|
||||
pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
this.panel.add(pane);
|
||||
panel.add(pane);
|
||||
this.area.setEditable(false);
|
||||
pane.setBounds(150, 100, 250, 80);
|
||||
|
||||
@@ -144,7 +129,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
* Add the OK button.
|
||||
*/
|
||||
this.ok = new JButton("OK");
|
||||
this.panel.add(ok);
|
||||
panel.add(ok);
|
||||
this.ok.setBounds(250, 50, 100, 25);
|
||||
this.ok.addActionListener(this);
|
||||
|
||||
@@ -152,7 +137,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
* Add the cancel button.
|
||||
*/
|
||||
this.cancel = new JButton("Cancel");
|
||||
this.panel.add(this.cancel);
|
||||
panel.add(this.cancel);
|
||||
this.cancel.setBounds(380, 50, 100, 25);
|
||||
this.cancel.addActionListener(this);
|
||||
|
||||
|
@@ -91,7 +91,7 @@ public class FileSelectorPresenter implements Serializable {
|
||||
}
|
||||
|
||||
if (loader.fileExists()) {
|
||||
String data = loader.loadData();
|
||||
var data = loader.loadData();
|
||||
view.displayData(data);
|
||||
} else {
|
||||
view.showMessage("The file specified does not exist.");
|
||||
|
@@ -26,16 +26,13 @@ package com.iluwatar.model.view.presenter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,10 +23,10 @@
|
||||
|
||||
package com.iluwatar.model.view.presenter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Date: 12/21/15 - 12:12 PM
|
||||
*
|
||||
@@ -35,8 +35,8 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
public class FileLoaderTest {
|
||||
|
||||
@Test
|
||||
public void testLoadData() throws Exception {
|
||||
final FileLoader fileLoader = new FileLoader();
|
||||
public void testLoadData() {
|
||||
final var fileLoader = new FileLoader();
|
||||
fileLoader.setFileName("non-existing-file");
|
||||
assertNull(fileLoader.loadData());
|
||||
}
|
||||
|
@@ -23,14 +23,14 @@
|
||||
|
||||
package com.iluwatar.model.view.presenter;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* This test case is responsible for testing our application by taking advantage of the
|
||||
* Model-View-Controller architectural pattern.
|
||||
@@ -79,7 +79,7 @@ public class FileSelectorPresenterTest {
|
||||
*/
|
||||
@Test
|
||||
public void updateFileNameToLoader() {
|
||||
String expectedFile = "Stamatis";
|
||||
var expectedFile = "Stamatis";
|
||||
stub.setFileName(expectedFile);
|
||||
|
||||
presenter.start();
|
||||
|
@@ -23,38 +23,39 @@
|
||||
THE SOFTWARE.
|
||||
|
||||
-->
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>module</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.module.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.23.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>module</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.module.App</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@@ -67,10 +67,8 @@ public class App {
|
||||
|
||||
/**
|
||||
* Following method is main executor.
|
||||
*
|
||||
* @param args for providing default program arguments
|
||||
*/
|
||||
public static void execute(final String... args) {
|
||||
public static void execute() {
|
||||
|
||||
/* Send logs on file system */
|
||||
fileLoggerModule.printString(MESSAGE);
|
||||
@@ -90,7 +88,7 @@ public class App {
|
||||
*/
|
||||
public static void main(final String... args) throws FileNotFoundException {
|
||||
prepare();
|
||||
execute(args);
|
||||
execute();
|
||||
unprepare();
|
||||
}
|
||||
}
|
||||
|
@@ -23,9 +23,8 @@
|
||||
|
||||
package com.iluwatar.module;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests that Module example runs without errors.
|
||||
@@ -34,7 +33,6 @@ public final class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() throws FileNotFoundException {
|
||||
final String[] args = {};
|
||||
App.main(args);
|
||||
App.main();
|
||||
}
|
||||
}
|
||||
|
@@ -23,17 +23,16 @@
|
||||
|
||||
package com.iluwatar.module;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Module pattern can be considered a Creational pattern and a Structural pattern. It manages
|
||||
@@ -58,13 +57,13 @@ public final class FileLoggerModuleTest {
|
||||
|
||||
/**
|
||||
* This test verify that 'MESSAGE' is perfectly printed in output file
|
||||
*
|
||||
*
|
||||
* @throws IOException if program is not able to find log files (output.txt and error.txt)
|
||||
*/
|
||||
@Test
|
||||
public void testFileMessage() throws IOException {
|
||||
|
||||
/* Get singletong instance of File Logger Module */
|
||||
/* Get singleton instance of File Logger Module */
|
||||
final var fileLoggerModule = FileLoggerModule.getSingleton();
|
||||
|
||||
/* Prepare the essential sub modules, to perform the sequence of jobs */
|
||||
@@ -82,13 +81,13 @@ public final class FileLoggerModuleTest {
|
||||
|
||||
/**
|
||||
* This test verify that nothing is printed in output file
|
||||
*
|
||||
*
|
||||
* @throws IOException if program is not able to find log files (output.txt and error.txt)
|
||||
*/
|
||||
@Test
|
||||
public void testNoFileMessage() throws IOException {
|
||||
|
||||
/* Get singletong instance of File Logger Module */
|
||||
/* Get singleton instance of File Logger Module */
|
||||
final var fileLoggerModule = FileLoggerModule.getSingleton();
|
||||
|
||||
/* Prepare the essential sub modules, to perform the sequence of jobs */
|
||||
@@ -103,14 +102,14 @@ public final class FileLoggerModuleTest {
|
||||
|
||||
/**
|
||||
* This test verify that 'ERROR' is perfectly printed in error file
|
||||
*
|
||||
*
|
||||
* @throws FileNotFoundException if program is not able to find log files (output.txt and
|
||||
* error.txt)
|
||||
* error.txt)
|
||||
*/
|
||||
@Test
|
||||
public void testFileErrorMessage() throws FileNotFoundException {
|
||||
|
||||
/* Get singletong instance of File Logger Module */
|
||||
/* Get singleton instance of File Logger Module */
|
||||
final var fileLoggerModule = FileLoggerModule.getSingleton();
|
||||
|
||||
/* Prepare the essential sub modules, to perform the sequence of jobs */
|
||||
@@ -122,20 +121,20 @@ public final class FileLoggerModuleTest {
|
||||
/* Test if 'Message' is printed in file */
|
||||
assertEquals(ERROR, readFirstLine(ERROR_FILE));
|
||||
|
||||
/* Unprepare to cleanup the modules */
|
||||
/* Un-prepare to cleanup the modules */
|
||||
fileLoggerModule.unprepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* This test verify that nothing is printed in error file
|
||||
*
|
||||
*
|
||||
* @throws FileNotFoundException if program is not able to find log files (output.txt and
|
||||
* error.txt)
|
||||
* error.txt)
|
||||
*/
|
||||
@Test
|
||||
public void testNoFileErrorMessage() throws FileNotFoundException {
|
||||
|
||||
/* Get singletong instance of File Logger Module */
|
||||
/* Get singleton instance of File Logger Module */
|
||||
final var fileLoggerModule = FileLoggerModule.getSingleton();
|
||||
|
||||
/* Prepare the essential sub modules, to perform the sequence of jobs */
|
||||
@@ -150,11 +149,11 @@ public final class FileLoggerModuleTest {
|
||||
|
||||
/**
|
||||
* Utility method to read first line of a file
|
||||
*
|
||||
*
|
||||
* @param file as file name to be read
|
||||
* @return a string value as first line in file
|
||||
*/
|
||||
private static final String readFirstLine(final String file) {
|
||||
private static String readFirstLine(final String file) {
|
||||
|
||||
String firstLine = null;
|
||||
try (var bufferedReader = new BufferedReader(new FileReader(file))) {
|
||||
|
@@ -41,9 +41,8 @@ import org.slf4j.LoggerFactory;
|
||||
* instance of a plain object with {@link Validator#of(Object)} and validates it {@link
|
||||
* Validator#validate(Function, Predicate, String)} against given predicates.
|
||||
*
|
||||
* <p>As a validation result {@link Validator#get()} it either returns valid object {@link
|
||||
* Validator#t} or throws a list of exceptions {@link Validator#exceptions} collected during
|
||||
* validation.
|
||||
* <p>As a validation result {@link Validator#get()} either returns valid object
|
||||
* or throws {@link IllegalStateException} with list of exceptions collected during validation.
|
||||
*/
|
||||
public class App {
|
||||
|
||||
@@ -55,10 +54,10 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
User user = new User("user", 24, Sex.FEMALE, "foobar.com");
|
||||
var user = new User("user", 24, Sex.FEMALE, "foobar.com");
|
||||
LOGGER.info(Validator.of(user).validate(User::getName, Objects::nonNull, "name is null")
|
||||
.validate(User::getName, name -> !name.isEmpty(), "name is empty")
|
||||
.validate(User::getEmail, email -> !email.contains("@"), "email doesn't containt '@'")
|
||||
.validate(User::getEmail, email -> !email.contains("@"), "email doesn't contains '@'")
|
||||
.validate(User::getAge, age -> age > 20 && age < 30, "age isn't between...").get()
|
||||
.toString());
|
||||
}
|
||||
|
@@ -85,18 +85,21 @@ public class Validator<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for the {@link Validator#validate(Function, Predicate, String)} method, dedicated for
|
||||
* objects, that need to be projected before requested validation.
|
||||
* Extension for the {@link Validator#validate(Predicate, String)} method, dedicated for objects,
|
||||
* that need to be projected before requested validation.
|
||||
*
|
||||
* @param projection function that gets an objects, and returns projection representing element to
|
||||
* be validated.
|
||||
* @param validation see {@link Validator#validate(Function, Predicate, String)}
|
||||
* @param message see {@link Validator#validate(Function, Predicate, String)}
|
||||
* @param <U> see {@link Validator#validate(Function, Predicate, String)}
|
||||
* @param validation see {@link Validator#validate(Predicate, String)}
|
||||
* @param message see {@link Validator#validate(Predicate, String)}
|
||||
* @param <U> see {@link Validator#validate(Predicate, String)}
|
||||
* @return this
|
||||
*/
|
||||
public <U> Validator<T> validate(Function<T, U> projection, Predicate<U> validation,
|
||||
String message) {
|
||||
public <U> Validator<T> validate(
|
||||
Function<T, U> projection,
|
||||
Predicate<U> validation,
|
||||
String message
|
||||
) {
|
||||
return validate(projection.andThen(validation::test)::apply, message);
|
||||
}
|
||||
|
||||
@@ -110,7 +113,7 @@ public class Validator<T> {
|
||||
if (exceptions.isEmpty()) {
|
||||
return obj;
|
||||
}
|
||||
IllegalStateException e = new IllegalStateException();
|
||||
var e = new IllegalStateException();
|
||||
exceptions.forEach(e::addSuppressed);
|
||||
throw e;
|
||||
}
|
||||
|
@@ -32,8 +32,7 @@ public class AppTest {
|
||||
|
||||
@Test
|
||||
public void testMain() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,13 +23,12 @@
|
||||
|
||||
package com.iluwatar.monad;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.util.Objects;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for Monad Pattern
|
||||
*/
|
||||
@@ -37,27 +36,33 @@ public class MonadTest {
|
||||
|
||||
@Test
|
||||
public void testForInvalidName() {
|
||||
User tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Validator.of(tom).validate(User::getName, Objects::nonNull, "name cannot be null").get();
|
||||
});
|
||||
var tom = new User(null, 21, Sex.MALE, "tom@foo.bar");
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> Validator.of(tom)
|
||||
.validate(User::getName, Objects::nonNull, "name cannot be null")
|
||||
.get()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForInvalidAge() {
|
||||
User john = new User("John", 17, Sex.MALE, "john@qwe.bar");
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
Validator.of(john).validate(User::getName, Objects::nonNull, "name cannot be null")
|
||||
.validate(User::getAge, age -> age > 21, "user is underaged")
|
||||
.get();
|
||||
});
|
||||
var john = new User("John", 17, Sex.MALE, "john@qwe.bar");
|
||||
assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> Validator.of(john)
|
||||
.validate(User::getName, Objects::nonNull, "name cannot be null")
|
||||
.validate(User::getAge, age -> age > 21, "user is underage")
|
||||
.get()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForValid() {
|
||||
User sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
|
||||
User validated = Validator.of(sarah).validate(User::getName, Objects::nonNull, "name cannot be null")
|
||||
.validate(User::getAge, age -> age > 21, "user is underaged")
|
||||
var sarah = new User("Sarah", 42, Sex.FEMALE, "sarah@det.org");
|
||||
var validated = Validator.of(sarah)
|
||||
.validate(User::getName, Objects::nonNull, "name cannot be null")
|
||||
.validate(User::getAge, age -> age > 21, "user is underage")
|
||||
.validate(User::getSex, sex -> sex == Sex.FEMALE, "user is not female")
|
||||
.validate(User::getEmail, email -> email.contains("@"), "email does not contain @ sign")
|
||||
.get();
|
||||
|
@@ -30,7 +30,7 @@ package com.iluwatar.monostate;
|
||||
*
|
||||
* <p>In the following example, The {@link LoadBalancer} class represents the app's logic. It
|
||||
* contains a series of Servers, which can handle requests of type {@link Request}. Two instances of
|
||||
* LoadBalacer are created. When a request is made to a server via the first LoadBalancer the state
|
||||
* LoadBalancer are created. When a request is made to a server via the first LoadBalancer the state
|
||||
* change in the first load balancer affects the second. So if the first LoadBalancer selects the
|
||||
* Server 1, the second LoadBalancer on a new request will select the Second server. If a third
|
||||
* LoadBalancer is created and a new request is made to it, then it will select the third server as
|
||||
@@ -43,8 +43,8 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
LoadBalancer loadBalancer1 = new LoadBalancer();
|
||||
LoadBalancer loadBalancer2 = new LoadBalancer();
|
||||
var loadBalancer1 = new LoadBalancer();
|
||||
var loadBalancer2 = new LoadBalancer();
|
||||
loadBalancer1.serverRequest(new Request("Hello"));
|
||||
loadBalancer2.serverRequest(new Request("Hello World"));
|
||||
}
|
||||
|
@@ -38,8 +38,8 @@ public class LoadBalancer {
|
||||
private static int lastServedId;
|
||||
|
||||
static {
|
||||
int id = 0;
|
||||
for (int port : new int[]{8080, 8081, 8082, 8083, 8084}) {
|
||||
var id = 0;
|
||||
for (var port : new int[]{8080, 8081, 8082, 8083, 8084}) {
|
||||
SERVERS.add(new Server("localhost", port, ++id));
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public class LoadBalancer {
|
||||
if (lastServedId >= SERVERS.size()) {
|
||||
lastServedId = 0;
|
||||
}
|
||||
Server server = SERVERS.get(lastServedId++);
|
||||
var server = SERVERS.get(lastServedId++);
|
||||
server.serve(request);
|
||||
}
|
||||
|
||||
|
@@ -32,8 +32,7 @@ public class AppTest {
|
||||
|
||||
@Test
|
||||
public void testMain() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -44,8 +44,8 @@ public class LoadBalancerTest {
|
||||
|
||||
@Test
|
||||
public void testSameStateAmongstAllInstances() {
|
||||
final LoadBalancer firstBalancer = new LoadBalancer();
|
||||
final LoadBalancer secondBalancer = new LoadBalancer();
|
||||
final var firstBalancer = new LoadBalancer();
|
||||
final var secondBalancer = new LoadBalancer();
|
||||
firstBalancer.addServer(new Server("localhost", 8085, 6));
|
||||
// Both should have the same number of servers.
|
||||
assertEquals(firstBalancer.getNoOfServers(), secondBalancer.getNoOfServers());
|
||||
@@ -55,18 +55,18 @@ public class LoadBalancerTest {
|
||||
|
||||
@Test
|
||||
public void testServe() {
|
||||
final Server server = mock(Server.class);
|
||||
final var server = mock(Server.class);
|
||||
when(server.getHost()).thenReturn("testhost");
|
||||
when(server.getPort()).thenReturn(1234);
|
||||
doNothing().when(server).serve(any(Request.class));
|
||||
|
||||
final LoadBalancer loadBalancer = new LoadBalancer();
|
||||
final var loadBalancer = new LoadBalancer();
|
||||
loadBalancer.addServer(server);
|
||||
|
||||
verifyZeroInteractions(server);
|
||||
|
||||
final Request request = new Request("test");
|
||||
for (int i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
|
||||
final var request = new Request("test");
|
||||
for (var i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
|
||||
loadBalancer.serverRequest(request);
|
||||
}
|
||||
|
||||
|
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
|
||||
* enum based multiton implementation.
|
||||
*/
|
||||
public enum NazgulEnum {
|
||||
|
||||
KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
|
||||
|
||||
KHAMUL,
|
||||
MURAZOR,
|
||||
DWAR,
|
||||
JI_INDUR,
|
||||
AKHORAHIL,
|
||||
HOARMURATH,
|
||||
ADUNAPHEL,
|
||||
REN,
|
||||
UVATHA
|
||||
}
|
||||
|
@@ -27,7 +27,13 @@ package com.iluwatar.multiton;
|
||||
* Each Nazgul has different {@link NazgulName}.
|
||||
*/
|
||||
public enum NazgulName {
|
||||
|
||||
KHAMUL, MURAZOR, DWAR, JI_INDUR, AKHORAHIL, HOARMURATH, ADUNAPHEL, REN, UVATHA
|
||||
|
||||
KHAMUL,
|
||||
MURAZOR,
|
||||
DWAR,
|
||||
JI_INDUR,
|
||||
AKHORAHIL,
|
||||
HOARMURATH,
|
||||
ADUNAPHEL,
|
||||
REN,
|
||||
UVATHA
|
||||
}
|
||||
|
@@ -26,15 +26,12 @@ package com.iluwatar.multiton;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -39,10 +39,10 @@ class NazgulEnumTest {
|
||||
*/
|
||||
@Test
|
||||
public void testTheSameObjectIsReturnedWithMultipleCalls() {
|
||||
for (int i = 0; i < NazgulEnum.values().length; i++) {
|
||||
NazgulEnum instance1 = NazgulEnum.values()[i];
|
||||
NazgulEnum instance2 = NazgulEnum.values()[i];
|
||||
NazgulEnum instance3 = NazgulEnum.values()[i];
|
||||
for (var i = 0; i < NazgulEnum.values().length; i++) {
|
||||
var instance1 = NazgulEnum.values()[i];
|
||||
var instance2 = NazgulEnum.values()[i];
|
||||
var instance3 = NazgulEnum.values()[i];
|
||||
assertSame(instance1, instance2);
|
||||
assertSame(instance1, instance3);
|
||||
assertSame(instance2, instance3);
|
||||
|
@@ -41,8 +41,8 @@ public class NazgulTest {
|
||||
*/
|
||||
@Test
|
||||
public void testGetInstance() {
|
||||
for (final NazgulName name : NazgulName.values()) {
|
||||
final Nazgul nazgul = Nazgul.getInstance(name);
|
||||
for (final var name : NazgulName.values()) {
|
||||
final var nazgul = Nazgul.getInstance(name);
|
||||
assertNotNull(nazgul);
|
||||
assertSame(nazgul, Nazgul.getInstance(name));
|
||||
assertEquals(name, nazgul.getName());
|
||||
|
@@ -25,7 +25,7 @@ package com.iluwatar.mute;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Optional;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -52,9 +52,8 @@ public class App {
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args.
|
||||
* @throws Exception if any exception occurs
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
public static void main(String[] args) {
|
||||
|
||||
useOfLoggedMute();
|
||||
|
||||
@@ -68,17 +67,17 @@ public class App {
|
||||
* exception occurs.
|
||||
*/
|
||||
private static void useOfMute() {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
var out = new ByteArrayOutputStream();
|
||||
Mute.mute(() -> out.write("Hello".getBytes()));
|
||||
}
|
||||
|
||||
private static void useOfLoggedMute() throws SQLException {
|
||||
Resource resource = null;
|
||||
private static void useOfLoggedMute() {
|
||||
Optional<Resource> resource = Optional.empty();
|
||||
try {
|
||||
resource = acquireResource();
|
||||
utilizeResource(resource);
|
||||
resource = Optional.of(acquireResource());
|
||||
utilizeResource(resource.get());
|
||||
} finally {
|
||||
closeResource(resource);
|
||||
resource.ifPresent(App::closeResource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +85,14 @@ public class App {
|
||||
* All we can do while failed close of a resource is to log it.
|
||||
*/
|
||||
private static void closeResource(Resource resource) {
|
||||
Mute.loggedMute(() -> resource.close());
|
||||
Mute.loggedMute(resource::close);
|
||||
}
|
||||
|
||||
private static void utilizeResource(Resource resource) throws SQLException {
|
||||
private static void utilizeResource(Resource resource) {
|
||||
LOGGER.info("Utilizing acquired resource: {}", resource);
|
||||
}
|
||||
|
||||
private static Resource acquireResource() throws SQLException {
|
||||
private static Resource acquireResource() {
|
||||
return new Resource() {
|
||||
|
||||
@Override
|
||||
|
@@ -27,12 +27,11 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests that Mute idiom example runs without errors.
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
App.main(null);
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -23,17 +23,15 @@
|
||||
|
||||
package com.iluwatar.mute;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test for the mute-idiom pattern
|
||||
*/
|
||||
@@ -50,9 +48,7 @@ public class MuteTest {
|
||||
|
||||
@Test
|
||||
public void muteShouldRethrowUnexpectedExceptionAsAssertionError() {
|
||||
assertThrows(AssertionError.class, () -> {
|
||||
Mute.mute(this::methodThrowingException);
|
||||
});
|
||||
assertThrows(AssertionError.class, () -> Mute.mute(this::methodThrowingException));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -62,7 +58,7 @@ public class MuteTest {
|
||||
|
||||
@Test
|
||||
public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
var stream = new ByteArrayOutputStream();
|
||||
System.setErr(new PrintStream(stream));
|
||||
|
||||
Mute.loggedMute(this::methodThrowingException);
|
||||
|
@@ -38,10 +38,10 @@ public class App {
|
||||
* main method.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Mutex mutex = new Mutex();
|
||||
Jar jar = new Jar(1000, mutex);
|
||||
Thief peter = new Thief("Peter", jar);
|
||||
Thief john = new Thief("John", jar);
|
||||
var mutex = new Mutex();
|
||||
var jar = new Jar(1000, mutex);
|
||||
var peter = new Thief("Peter", jar);
|
||||
var john = new Thief("John", jar);
|
||||
peter.start();
|
||||
john.start();
|
||||
}
|
||||
|
@@ -48,7 +48,7 @@ public class Jar {
|
||||
* Method for a thief to take a bean.
|
||||
*/
|
||||
public boolean takeBean() {
|
||||
boolean success = false;
|
||||
var success = false;
|
||||
try {
|
||||
lock.acquire();
|
||||
success = beans > 0;
|
||||
|
@@ -54,7 +54,7 @@ public class Thief extends Thread {
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
int beans = 0;
|
||||
var beans = 0;
|
||||
|
||||
while (jar.takeBean()) {
|
||||
beans = beans + 1;
|
||||
|
@@ -25,15 +25,12 @@ package com.iluwatar.mutex;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Application Test Entrypoint
|
||||
*/
|
||||
public class AppTest {
|
||||
@Test
|
||||
public void test() throws IOException {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
public void test() {
|
||||
App.main(new String[]{});
|
||||
}
|
||||
}
|
||||
|
@@ -23,10 +23,11 @@
|
||||
|
||||
package com.iluwatar.mutex;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.stream.IntStream;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for taking beans from a Jar
|
||||
@@ -35,12 +36,10 @@ public class JarTest {
|
||||
|
||||
@Test
|
||||
public void testTakeBeans() {
|
||||
Mutex mutex = new Mutex();
|
||||
Jar jar = new Jar(10, mutex);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
assertTrue(jar.takeBean());
|
||||
}
|
||||
var mutex = new Mutex();
|
||||
var jar = new Jar(10, mutex);
|
||||
IntStream.range(0, 10).mapToObj(i -> jar.takeBean()).forEach(Assertions::assertTrue);
|
||||
assertFalse(jar.takeBean());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -23,12 +23,12 @@
|
||||
|
||||
package com.iluwatar.mutex;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test case for acquiring and releasing a Mutex
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ public class MutexTest {
|
||||
|
||||
@Test
|
||||
public void acquireReleaseTest() {
|
||||
Mutex mutex = new Mutex();
|
||||
var mutex = new Mutex();
|
||||
assertNull(mutex.getOwner());
|
||||
try {
|
||||
mutex.acquire();
|
||||
|
@@ -127,7 +127,7 @@
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore></ignore>
|
||||
<ignore/>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
|
@@ -1,19 +1,3 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"columns": [
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user