Compare commits
1 Commits
all-contri
...
kramdown-f
Author | SHA1 | Date | |
---|---|---|---|
bc801bae20 |
@ -1404,24 +1404,6 @@
|
||||
"contributions": [
|
||||
"translation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "richardmr36",
|
||||
"name": "Martel Richard",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19147333?v=4",
|
||||
"profile": "https://github.com/richardmr36",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "va1m",
|
||||
"name": "va1m",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17025445?v=4",
|
||||
"profile": "https://github.com/va1m",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 4,
|
||||
|
@ -1,52 +0,0 @@
|
||||
#
|
||||
# The MIT License
|
||||
# Copyright © 2014-2021 Ilkka Seppälä
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
sonar-pr:
|
||||
docker:
|
||||
- image: circleci/openjdk:11-node
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: jdp-sonar-pr-{{ checksum "pom.xml" }}
|
||||
- run: |
|
||||
if [ -n "${CIRCLE_PR_NUMBER}" ]; then
|
||||
MAVEN_OPTS="-Xmx3000m" xvfb-run ./mvnw -B clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
|
||||
-Dsonar.pullrequest.key=${CIRCLE_PR_NUMBER} \
|
||||
-Dsonar.pullrequest.branch=${CIRCLE_BRANCH} \
|
||||
-Dsonar.pullrequest.base=master
|
||||
else
|
||||
echo "No Sonar PR analysis as this is not a pull request"
|
||||
fi
|
||||
- save_cache:
|
||||
key: jdp-sonar-pr-{{ checksum "pom.xml" }}
|
||||
paths:
|
||||
- ~/.m2
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
all:
|
||||
jobs:
|
||||
- sonar-pr
|
13
.github/workflows/maven-ci.yml
vendored
13
.github/workflows/maven-ci.yml
vendored
@ -40,25 +40,25 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Disabling shallow clone for improving relevancy of SonarQube reporting
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@master
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache SonarCloud packages
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.sonar/cache
|
||||
key: ${{ runner.os }}-sonar
|
||||
restore-keys: ${{ runner.os }}-sonar
|
||||
|
||||
- name: Cache Maven dependencies
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@ -69,8 +69,11 @@ jobs:
|
||||
- name: Install xvfb
|
||||
run: sudo apt-get install -y xvfb
|
||||
|
||||
# The SonarQube analysis is only for the master branch of the main repository.
|
||||
# SonarQube scan does not work for forked repositories try changing it to xvfb-run mvn clean verify
|
||||
# See https://jira.sonarsource.com/browse/MMF-1371
|
||||
- name: Build with Maven and run SonarQube analysis
|
||||
run: xvfb-run ./mvnw clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||
run: xvfb-run mvn clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
|
||||
env:
|
||||
# These two env variables are needed for sonar analysis
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
13
.github/workflows/maven-pr-builder.yml
vendored
13
.github/workflows/maven-pr-builder.yml
vendored
@ -29,7 +29,7 @@ name: Java PR Builder
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
types: [ opened, reopened, synchronize ]
|
||||
types: [ opened, reopened, synchronize, labeled, unlabeled ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -38,15 +38,15 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@master
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@master
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
|
||||
- name: Cache Maven Dependecies
|
||||
uses: actions/cache@master
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.m2/repository
|
||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
||||
@ -57,5 +57,8 @@ jobs:
|
||||
- name: Install xvfb
|
||||
run: sudo apt-get install -y xvfb
|
||||
|
||||
# This worflow is only for building Pull Requests, the master branch runs Sonar analysis on the main repository.
|
||||
# SonarQube scan does not work for forked repositories.
|
||||
# See https://jira.sonarsource.com/browse/MMF-1371
|
||||
- name: Build with Maven
|
||||
run: xvfb-run ./mvnw clean verify
|
||||
run: xvfb-run mvn clean verify
|
||||
|
125
.mvn/wrapper/MavenWrapperDownloader.java
vendored
125
.mvn/wrapper/MavenWrapperDownloader.java
vendored
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* The MIT License
|
||||
* Copyright © 2014-2021 Ilkka Seppälä
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
private static final String WRAPPER_VERSION = "0.5.6";
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
|
||||
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
|
||||
String username = System.getenv("MVNW_USERNAME");
|
||||
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
|
||||
Authenticator.setDefault(new Authenticator() {
|
||||
@Override
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return new PasswordAuthentication(username, password);
|
||||
}
|
||||
});
|
||||
}
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
25
.mvn/wrapper/maven-wrapper.properties
vendored
25
.mvn/wrapper/maven-wrapper.properties
vendored
@ -1,25 +0,0 @@
|
||||
#
|
||||
# The MIT License
|
||||
# Copyright © 2014-2021 Ilkka Seppälä
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
|
||||
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
|
@ -4,18 +4,18 @@
|
||||
|
||||
# Design patterns implemented in Java
|
||||
|
||||

|
||||

|
||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)
|
||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
[](#contributors-)
|
||||
[](#contributors-)
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
|
||||
<br/>
|
||||
|
||||
Read in different language : [**CN**](/zh/README.md), [**KR**](/ko/README.md), [**FR**](/fr/README.md), [**TR**](/tr/README.md), [**AR**](/ar/README.md)
|
||||
Read in different language : [**CN**](/zh/README.md),[**KR**](/ko/README.md),[**FR**](/fr/README.md),[**TR**](/tr/README.md),[**AR**](/ar/README.md),
|
||||
|
||||
<br/>
|
||||
|
||||
@ -306,8 +306,6 @@ This project is licensed under the terms of the MIT license.
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/byoungju94"><img src="https://avatars.githubusercontent.com/u/42516378?v=4?s=100" width="100px;" alt=""/><br /><sub><b>byoungju94</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=byoungju94" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/moustafafarhat"><img src="https://avatars.githubusercontent.com/u/38836727?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moustafa Farhat</b></sub></a><br /><a href="#translation-moustafafarhat" title="Translation">🌍</a></td>
|
||||
<td align="center"><a href="https://github.com/richardmr36"><img src="https://avatars.githubusercontent.com/u/19147333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Martel Richard</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=richardmr36" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/va1m"><img src="https://avatars.githubusercontent.com/u/17025445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>va1m</b></sub></a><br /><a href="https://github.com/iluwatar/java-design-patterns/commits?author=va1m" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -27,7 +27,8 @@ import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Abstract Document pattern enables handling additional, non-static properties. This pattern
|
||||
@ -37,9 +38,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* <p>In Abstract Document pattern,({@link AbstractDocument}) fully implements {@link Document})
|
||||
* interface. Traits are then defined to enable access to properties in usual, static way.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
|
@ -23,18 +23,19 @@
|
||||
|
||||
package com.iluwatar.abstractdocument;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* AbstractDocument test class
|
||||
*/
|
||||
class AbstractDocumentTest {
|
||||
public class AbstractDocumentTest {
|
||||
|
||||
private static final String KEY = "key";
|
||||
private static final String VALUE = "value";
|
||||
@ -49,13 +50,13 @@ class AbstractDocumentTest {
|
||||
private final DocumentImplementation document = new DocumentImplementation(new HashMap<>());
|
||||
|
||||
@Test
|
||||
void shouldPutAndGetValue() {
|
||||
public void shouldPutAndGetValue() {
|
||||
document.put(KEY, VALUE);
|
||||
assertEquals(VALUE, document.get(KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRetrieveChildren() {
|
||||
public void shouldRetrieveChildren() {
|
||||
var children = List.of(Map.of(), Map.of());
|
||||
|
||||
document.put(KEY, children);
|
||||
@ -66,14 +67,14 @@ class AbstractDocumentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRetrieveEmptyStreamForNonExistingChildren() {
|
||||
public void shouldRetrieveEmptyStreamForNonExistingChildren() {
|
||||
var children = document.children(KEY, DocumentImplementation::new);
|
||||
assertNotNull(children);
|
||||
assertEquals(0, children.count());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldIncludePropsInToString() {
|
||||
public void shouldIncludePropsInToString() {
|
||||
var props = Map.of(KEY, (Object) VALUE);
|
||||
var document = new DocumentImplementation(props);
|
||||
assertTrue(document.toString().contains(KEY));
|
||||
|
@ -23,20 +23,19 @@
|
||||
|
||||
package com.iluwatar.abstractdocument;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import com.iluwatar.abstractdocument.domain.Car;
|
||||
import com.iluwatar.abstractdocument.domain.Part;
|
||||
import com.iluwatar.abstractdocument.domain.enums.Property;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for Part and Car
|
||||
*/
|
||||
class DomainTest {
|
||||
public class DomainTest {
|
||||
|
||||
private static final String TEST_PART_TYPE = "test-part-type";
|
||||
private static final String TEST_PART_MODEL = "test-part-model";
|
||||
@ -46,7 +45,7 @@ class DomainTest {
|
||||
private static final long TEST_CAR_PRICE = 1L;
|
||||
|
||||
@Test
|
||||
void shouldConstructPart() {
|
||||
public void shouldConstructPart() {
|
||||
var partProperties = Map.of(
|
||||
Property.TYPE.toString(), TEST_PART_TYPE,
|
||||
Property.MODEL.toString(), TEST_PART_MODEL,
|
||||
@ -59,7 +58,7 @@ class DomainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldConstructCar() {
|
||||
public void shouldConstructCar() {
|
||||
var carProperties = Map.of(
|
||||
Property.MODEL.toString(), TEST_CAR_MODEL,
|
||||
Property.PRICE.toString(), TEST_CAR_PRICE,
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.abstractfactory;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that
|
||||
@ -39,9 +40,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* and its implementations ( {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses
|
||||
* both concrete implementations to create a king, a castle and an army.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App implements Runnable {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(App.class);
|
||||
|
||||
private final Kingdom kingdom = new Kingdom();
|
||||
|
||||
public Kingdom getKingdom() {
|
||||
@ -60,17 +62,17 @@ public class App implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
LOGGER.info("Elf Kingdom");
|
||||
log.info("Elf Kingdom");
|
||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
LOGGER.info(kingdom.getArmy().getDescription());
|
||||
LOGGER.info(kingdom.getCastle().getDescription());
|
||||
LOGGER.info(kingdom.getKing().getDescription());
|
||||
log.info(kingdom.getArmy().getDescription());
|
||||
log.info(kingdom.getCastle().getDescription());
|
||||
log.info(kingdom.getKing().getDescription());
|
||||
|
||||
LOGGER.info("Orc Kingdom");
|
||||
log.info("Orc Kingdom");
|
||||
createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||
LOGGER.info(kingdom.getArmy().getDescription());
|
||||
LOGGER.info(kingdom.getCastle().getDescription());
|
||||
LOGGER.info(kingdom.getKing().getDescription());
|
||||
log.info(kingdom.getArmy().getDescription());
|
||||
log.info(kingdom.getCastle().getDescription());
|
||||
log.info(kingdom.getKing().getDescription());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,17 +23,36 @@
|
||||
|
||||
package com.iluwatar.abstractfactory;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class Kingdom {
|
||||
|
||||
private King king;
|
||||
private Castle castle;
|
||||
private Army army;
|
||||
|
||||
public King getKing() {
|
||||
return king;
|
||||
}
|
||||
|
||||
public Castle getCastle() {
|
||||
return castle;
|
||||
}
|
||||
|
||||
public Army getArmy() {
|
||||
return army;
|
||||
}
|
||||
|
||||
public void setKing(King king) {
|
||||
this.king = king;
|
||||
}
|
||||
|
||||
public void setCastle(Castle castle) {
|
||||
this.castle = castle;
|
||||
}
|
||||
|
||||
public void setArmy(Army army) {
|
||||
this.army = army;
|
||||
}
|
||||
|
||||
/**
|
||||
* The factory of kingdom factories.
|
||||
*/
|
||||
|
@ -31,12 +31,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
/**
|
||||
* Test for abstract factory.
|
||||
*/
|
||||
class AbstractFactoryTest {
|
||||
public class AbstractFactoryTest {
|
||||
|
||||
private final App app = new App();
|
||||
|
||||
@Test
|
||||
void king() {
|
||||
public void king() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -51,7 +51,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void castle() {
|
||||
public void castle() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -66,7 +66,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void army() {
|
||||
public void army() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -81,7 +81,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createElfKingdom() {
|
||||
public void createElfKingdom() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ELF);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
@ -97,7 +97,7 @@ class AbstractFactoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createOrcKingdom() {
|
||||
public void createOrcKingdom() {
|
||||
app.createKingdom(Kingdom.FactoryMaker.KingdomType.ORC);
|
||||
final var kingdom = app.getKingdom();
|
||||
|
||||
|
@ -23,15 +23,17 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ConfigureForDosVisitor class implements both zoom's and hayes' visit method for Dos
|
||||
* manufacturer.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConfigureForDosVisitor implements AllModemVisitor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(Hayes hayes) {
|
||||
LOGGER.info(hayes + " used with Dos configurator.");
|
||||
|
@ -23,15 +23,17 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ConfigureForUnixVisitor class implements zoom's visit method for Unix manufacturer, unlike
|
||||
* traditional visitor pattern, this class may selectively implement visit for other modems.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConfigureForUnixVisitor implements ZoomVisitor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForUnixVisitor.class);
|
||||
|
||||
@Override
|
||||
public void visit(Zoom zoom) {
|
||||
LOGGER.info(zoom + " used with Unix configurator.");
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Hayes class implements its accept method.
|
||||
*/
|
||||
@Slf4j
|
||||
public class Hayes extends Modem {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
||||
|
||||
/**
|
||||
* Accepts all visitors but honors only HayesVisitor.
|
||||
*/
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Zoom class implements its accept method.
|
||||
*/
|
||||
@Slf4j
|
||||
public class Zoom extends Modem {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigureForDosVisitor.class);
|
||||
|
||||
/**
|
||||
* Accepts all visitors but honors only ZoomVisitor.
|
||||
*/
|
||||
|
@ -35,34 +35,34 @@ import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||
/**
|
||||
* ConfigureForDosVisitor test class
|
||||
*/
|
||||
class ConfigureForDosVisitorTest {
|
||||
public class ConfigureForDosVisitorTest {
|
||||
|
||||
private final TestLogger logger = TestLoggerFactory.getTestLogger(ConfigureForDosVisitor.class);
|
||||
|
||||
|
||||
@Test
|
||||
void testVisitForZoom() {
|
||||
public void testVisitForZoom() {
|
||||
var conDos = new ConfigureForDosVisitor();
|
||||
var zoom = new Zoom();
|
||||
|
||||
|
||||
conDos.visit(zoom);
|
||||
|
||||
|
||||
assertThat(logger.getLoggingEvents())
|
||||
.extracting("level", "message")
|
||||
.contains(tuple(INFO, zoom + " used with Dos configurator."));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testVisitForHayes() {
|
||||
public void testVisitForHayes() {
|
||||
var conDos = new ConfigureForDosVisitor();
|
||||
var hayes = new Hayes();
|
||||
|
||||
|
||||
conDos.visit(hayes);
|
||||
|
||||
|
||||
assertThat(logger.getLoggingEvents())
|
||||
.extracting("level", "message")
|
||||
.contains(tuple(INFO, hayes + " used with Dos configurator."));
|
||||
}
|
||||
|
||||
|
||||
@AfterEach
|
||||
public void clearLoggers() {
|
||||
TestLoggerFactory.clear();
|
||||
|
@ -23,34 +23,35 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import uk.org.lidalia.slf4jtest.TestLogger;
|
||||
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.groups.Tuple.tuple;
|
||||
import static uk.org.lidalia.slf4jext.Level.INFO;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import uk.org.lidalia.slf4jtest.TestLogger;
|
||||
import uk.org.lidalia.slf4jtest.TestLoggerFactory;
|
||||
|
||||
/**
|
||||
* ConfigureForUnixVisitor test class
|
||||
*/
|
||||
class ConfigureForUnixVisitorTest {
|
||||
|
||||
public class ConfigureForUnixVisitorTest {
|
||||
|
||||
private static final TestLogger LOGGER = TestLoggerFactory.getTestLogger(ConfigureForUnixVisitor.class);
|
||||
|
||||
|
||||
@AfterEach
|
||||
public void clearLoggers() {
|
||||
TestLoggerFactory.clear();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testVisitForZoom() {
|
||||
public void testVisitForZoom() {
|
||||
var conUnix = new ConfigureForUnixVisitor();
|
||||
var zoom = new Zoom();
|
||||
|
||||
|
||||
conUnix.visit(zoom);
|
||||
|
||||
|
||||
assertThat(LOGGER.getLoggingEvents())
|
||||
.extracting("level", "message")
|
||||
.contains(tuple(INFO, zoom + " used with Unix configurator."));
|
||||
|
@ -23,32 +23,34 @@
|
||||
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Hayes test class
|
||||
*/
|
||||
class HayesTest {
|
||||
public class HayesTest {
|
||||
|
||||
@Test
|
||||
void testAcceptForDos() {
|
||||
public void testAcceptForDos() {
|
||||
var hayes = new Hayes();
|
||||
var mockVisitor = mock(ConfigureForDosVisitor.class);
|
||||
|
||||
|
||||
hayes.accept(mockVisitor);
|
||||
verify((HayesVisitor) mockVisitor).visit(eq(hayes));
|
||||
verify((HayesVisitor)mockVisitor).visit(eq(hayes));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testAcceptForUnix() {
|
||||
public void testAcceptForUnix() {
|
||||
var hayes = new Hayes();
|
||||
var mockVisitor = mock(ConfigureForUnixVisitor.class);
|
||||
|
||||
|
||||
hayes.accept(mockVisitor);
|
||||
|
||||
|
||||
verifyZeroInteractions(mockVisitor);
|
||||
}
|
||||
}
|
||||
|
@ -24,32 +24,32 @@
|
||||
package com.iluwatar.acyclicvisitor;
|
||||
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Zoom test class
|
||||
*/
|
||||
class ZoomTest {
|
||||
|
||||
public class ZoomTest {
|
||||
|
||||
@Test
|
||||
void testAcceptForDos() {
|
||||
public void testAcceptForDos() {
|
||||
var zoom = new Zoom();
|
||||
var mockVisitor = mock(ConfigureForDosVisitor.class);
|
||||
|
||||
|
||||
zoom.accept(mockVisitor);
|
||||
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
||||
verify((ZoomVisitor)mockVisitor).visit(eq(zoom));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testAcceptForUnix() {
|
||||
public void testAcceptForUnix() {
|
||||
var zoom = new Zoom();
|
||||
var mockVisitor = mock(ConfigureForUnixVisitor.class);
|
||||
|
||||
|
||||
zoom.accept(mockVisitor);
|
||||
verify((ZoomVisitor) mockVisitor).visit(eq(zoom));
|
||||
verify((ZoomVisitor)mockVisitor).visit(eq(zoom));
|
||||
}
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ public interface RowingBoat {
|
||||
void row();
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
public class FishingBoat {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class);
|
||||
public void sail() {
|
||||
LOGGER.info("The fishing boat is sailing");
|
||||
}
|
||||
@ -70,9 +70,10 @@ public class Captain {
|
||||
Now let's say the pirates are coming and our captain needs to escape but there is only fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class FishingBoatAdapter implements RowingBoat {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class);
|
||||
|
||||
private final FishingBoat boat;
|
||||
|
||||
public FishingBoatAdapter() {
|
||||
|
@ -23,20 +23,24 @@
|
||||
|
||||
package com.iluwatar.adapter;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* The Captain uses {@link RowingBoat} to sail. <br> This is the client in the pattern.
|
||||
*/
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public final class Captain {
|
||||
|
||||
private RowingBoat rowingBoat;
|
||||
|
||||
public Captain() {
|
||||
}
|
||||
|
||||
public Captain(final RowingBoat boat) {
|
||||
this.rowingBoat = boat;
|
||||
}
|
||||
|
||||
void setRowingBoat(final RowingBoat boat) {
|
||||
this.rowingBoat = boat;
|
||||
}
|
||||
|
||||
void row() {
|
||||
rowingBoat.row();
|
||||
}
|
||||
|
@ -23,15 +23,18 @@
|
||||
|
||||
package com.iluwatar.adapter;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Device class (adaptee in the pattern). We want to reuse this class. Fishing boat moves by
|
||||
* sailing.
|
||||
*/
|
||||
@Slf4j
|
||||
final class FishingBoat {
|
||||
|
||||
private static final Logger LOGGER = getLogger(FishingBoat.class);
|
||||
|
||||
void sail() {
|
||||
LOGGER.info("The fishing boat is sailing");
|
||||
}
|
||||
|
@ -29,7 +29,11 @@ package com.iluwatar.adapter;
|
||||
*/
|
||||
public class FishingBoatAdapter implements RowingBoat {
|
||||
|
||||
private final FishingBoat boat = new FishingBoat();
|
||||
private final FishingBoat boat;
|
||||
|
||||
public FishingBoatAdapter() {
|
||||
boat = new FishingBoat();
|
||||
}
|
||||
|
||||
public final void row() {
|
||||
boat.sail();
|
||||
|
@ -23,19 +23,18 @@
|
||||
|
||||
package com.iluwatar.adapter;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test class
|
||||
*/
|
||||
class AdapterPatternTest {
|
||||
public class AdapterPatternTest {
|
||||
|
||||
private Map<String, Object> beans;
|
||||
|
||||
@ -65,7 +64,7 @@ class AdapterPatternTest {
|
||||
* by the client ({@link Captain} ).
|
||||
*/
|
||||
@Test
|
||||
void testAdapter() {
|
||||
public void testAdapter() {
|
||||
var captain = (Captain) beans.get(ROWING_BEAN);
|
||||
|
||||
// when captain moves
|
||||
|
@ -26,7 +26,8 @@ package com.iluwatar.aggregator.microservices;
|
||||
import static java.util.Objects.requireNonNullElse;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
@ -36,18 +37,20 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
public class Aggregator {
|
||||
|
||||
|
||||
@Resource
|
||||
private ProductInformationClient informationClient;
|
||||
|
||||
@Resource
|
||||
private ProductInventoryClient inventoryClient;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves product data.
|
||||
*
|
||||
* @return a Product.
|
||||
*/
|
||||
@GetMapping("/product")
|
||||
@RequestMapping(path = "/product", method = RequestMethod.GET)
|
||||
public Product getProduct() {
|
||||
|
||||
var product = new Product();
|
||||
|
@ -23,14 +23,9 @@
|
||||
|
||||
package com.iluwatar.aggregator.microservices;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Encapsulates all the data for a Product that clients will request.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class Product {
|
||||
|
||||
/**
|
||||
@ -44,4 +39,20 @@ public class Product {
|
||||
*/
|
||||
private int productInventories;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public int getProductInventories() {
|
||||
return productInventories;
|
||||
}
|
||||
|
||||
public void setProductInventories(int productInventories) {
|
||||
this.productInventories = productInventories;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,16 +28,18 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An adapter to communicate with information micro-service.
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ProductInformationClientImpl implements ProductInformationClient {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ProductInformationClientImpl.class);
|
||||
|
||||
@Override
|
||||
public String getProductTitle() {
|
||||
var request = HttpRequest.newBuilder()
|
||||
@ -52,7 +54,6 @@ public class ProductInformationClientImpl implements ProductInformationClient {
|
||||
LOGGER.error("IOException Occurred", ioe);
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.error("InterruptedException Occurred", ie);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -28,16 +28,18 @@ import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An adapter to communicate with inventory micro-service.
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ProductInventoryClientImpl implements ProductInventoryClient {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ProductInventoryClientImpl.class);
|
||||
|
||||
@Override
|
||||
public Integer getProductInventories() {
|
||||
var response = "";
|
||||
@ -54,7 +56,6 @@ public class ProductInventoryClientImpl implements ProductInventoryClient {
|
||||
LOGGER.error("IOException Occurred", ioe);
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.error("InterruptedException Occurred", ie);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
if ("".equalsIgnoreCase(response)) {
|
||||
return null;
|
||||
|
@ -23,19 +23,19 @@
|
||||
|
||||
package com.iluwatar.aggregator.microservices;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Test Aggregation of domain objects
|
||||
*/
|
||||
class AggregatorTest {
|
||||
public class AggregatorTest {
|
||||
|
||||
@InjectMocks
|
||||
private Aggregator aggregator;
|
||||
@ -55,7 +55,7 @@ class AggregatorTest {
|
||||
* Tests getting the data for a desktop client
|
||||
*/
|
||||
@Test
|
||||
void testGetProduct() {
|
||||
public void testGetProduct() {
|
||||
var title = "The Product Title.";
|
||||
var inventories = 5;
|
||||
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.information.microservice;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
@ -37,7 +38,7 @@ public class InformationController {
|
||||
*
|
||||
* @return product inventory.
|
||||
*/
|
||||
@GetMapping("/information")
|
||||
@RequestMapping(value = "/information", method = RequestMethod.GET)
|
||||
public String getProductTitle() {
|
||||
return "The Product Title.";
|
||||
}
|
||||
|
@ -23,17 +23,17 @@
|
||||
|
||||
package com.iluwatar.information.microservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for Information Rest Controller
|
||||
*/
|
||||
class InformationControllerTest {
|
||||
public class InformationControllerTest {
|
||||
|
||||
@Test
|
||||
void shouldGetProductTitle() {
|
||||
public void shouldGetProductTitle() {
|
||||
var infoController = new InformationController();
|
||||
var title = infoController.getProductTitle();
|
||||
assertEquals("The Product Title.", title);
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.inventory.microservice;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
@ -37,7 +38,7 @@ public class InventoryController {
|
||||
*
|
||||
* @return product inventory.
|
||||
*/
|
||||
@GetMapping("/inventories")
|
||||
@RequestMapping(value = "/inventories", method = RequestMethod.GET)
|
||||
public int getProductInventories() {
|
||||
return 5;
|
||||
}
|
||||
|
@ -23,17 +23,16 @@
|
||||
|
||||
package com.iluwatar.inventory.microservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test Inventory Rest Controller
|
||||
*/
|
||||
class InventoryControllerTest {
|
||||
|
||||
public class InventoryControllerTest {
|
||||
@Test
|
||||
void testGetProductInventories() {
|
||||
public void testGetProductInventories() {
|
||||
var inventoryController = new InventoryController();
|
||||
var numberOfInventories = inventoryController.getProductInventories();
|
||||
assertEquals(5, numberOfInventories);
|
||||
|
@ -48,8 +48,9 @@ interface RemoteServiceInterface {
|
||||
A remote services represented as a singleton.
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class RemoteService implements RemoteServiceInterface {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
||||
private static RemoteService service = null;
|
||||
|
||||
static synchronized RemoteService getRemoteService() {
|
||||
@ -79,8 +80,9 @@ public class RemoteService implements RemoteServiceInterface {
|
||||
A service ambassador adding additional features such as logging, latency checks
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class);
|
||||
private static final int RETRIES = 3;
|
||||
private static final int DELAY_MS = 3000;
|
||||
|
||||
@ -130,8 +132,9 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
A client has a local service ambassador used to interact with the remote service:
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class Client {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
|
||||
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
|
||||
|
||||
long useService(int value) {
|
||||
|
@ -23,19 +23,20 @@
|
||||
|
||||
package com.iluwatar.ambassador;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple Client.
|
||||
*/
|
||||
@Slf4j
|
||||
public class Client {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
|
||||
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
|
||||
|
||||
long useService(int value) {
|
||||
var result = serviceAmbassador.doRemoteFunction(value);
|
||||
LOGGER.info("Service result: {}", result);
|
||||
LOGGER.info("Service result: " + result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -26,14 +26,15 @@ package com.iluwatar.ambassador;
|
||||
import static java.lang.Thread.sleep;
|
||||
|
||||
import com.iluwatar.ambassador.util.RandomProvider;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A remote legacy application represented by a Singleton implementation.
|
||||
*/
|
||||
@Slf4j
|
||||
public class RemoteService implements RemoteServiceInterface {
|
||||
private static final int THRESHOLD = 200;
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
|
||||
private static RemoteService service = null;
|
||||
private final RandomProvider randomProvider;
|
||||
|
||||
@ -72,9 +73,8 @@ public class RemoteService implements RemoteServiceInterface {
|
||||
sleep(waitTime);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Thread sleep state interrupted", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return waitTime <= THRESHOLD ? value * 10
|
||||
: RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue();
|
||||
: RemoteServiceStatus.FAILURE.getRemoteServiceStatusValue();
|
||||
}
|
||||
}
|
||||
|
@ -33,7 +33,8 @@ package com.iluwatar.ambassador;
|
||||
*/
|
||||
|
||||
public enum RemoteServiceStatus {
|
||||
FAILURE(-1);
|
||||
FAILURE(-1)
|
||||
;
|
||||
|
||||
private final long remoteServiceStatusValue;
|
||||
|
||||
|
@ -26,16 +26,17 @@ package com.iluwatar.ambassador;
|
||||
import static com.iluwatar.ambassador.RemoteServiceStatus.FAILURE;
|
||||
import static java.lang.Thread.sleep;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* ServiceAmbassador provides an interface for a ({@link Client}) to access ({@link RemoteService}).
|
||||
* The interface adds logging, latency testing and usage of the service in a safe way that will not
|
||||
* add stress to the remote service when connectivity issues occur.
|
||||
*/
|
||||
@Slf4j
|
||||
public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class);
|
||||
private static final int RETRIES = 3;
|
||||
private static final int DELAY_MS = 3000;
|
||||
|
||||
@ -52,7 +53,7 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
var result = RemoteService.getRemoteService().doRemoteFunction(value);
|
||||
var timeTaken = System.currentTimeMillis() - startTime;
|
||||
|
||||
LOGGER.info("Time taken (ms): {}", timeTaken);
|
||||
LOGGER.info("Time taken (ms): " + timeTaken);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -66,13 +67,12 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
||||
}
|
||||
|
||||
if ((result = checkLatency(value)) == FAILURE.getRemoteServiceStatusValue()) {
|
||||
LOGGER.info("Failed to reach remote: ({})", i + 1);
|
||||
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
|
||||
retries++;
|
||||
try {
|
||||
sleep(DELAY_MS);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Thread sleep state interrupted", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
|
@ -24,7 +24,8 @@
|
||||
package com.iluwatar.api.gateway;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
@ -44,7 +45,7 @@ public class ApiGateway {
|
||||
*
|
||||
* @return Product information for clients on a desktop
|
||||
*/
|
||||
@GetMapping("/desktop")
|
||||
@RequestMapping(path = "/desktop", method = RequestMethod.GET)
|
||||
public DesktopProduct getProductDesktop() {
|
||||
var desktopProduct = new DesktopProduct();
|
||||
desktopProduct.setImagePath(imageClient.getImagePath());
|
||||
@ -57,7 +58,7 @@ public class ApiGateway {
|
||||
*
|
||||
* @return Product information for clients on a mobile device
|
||||
*/
|
||||
@GetMapping("/mobile")
|
||||
@RequestMapping(path = "/mobile", method = RequestMethod.GET)
|
||||
public MobileProduct getProductMobile() {
|
||||
var mobileProduct = new MobileProduct();
|
||||
mobileProduct.setPrice(priceClient.getPrice());
|
||||
|
@ -23,16 +23,10 @@
|
||||
|
||||
package com.iluwatar.api.gateway;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Encapsulates all of the information that a desktop client needs to display a product.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class DesktopProduct {
|
||||
|
||||
/**
|
||||
* The price of the product.
|
||||
*/
|
||||
@ -43,4 +37,19 @@ public class DesktopProduct {
|
||||
*/
|
||||
private String imagePath;
|
||||
|
||||
public String getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(String price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
public String getImagePath() {
|
||||
return imagePath;
|
||||
}
|
||||
|
||||
public void setImagePath(String imagePath) {
|
||||
this.imagePath = imagePath;
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +23,24 @@
|
||||
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* An adapter to communicate with the Image microservice.
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class ImageClientImpl implements ImageClient {
|
||||
private static final Logger LOGGER = getLogger(ImageClientImpl.class);
|
||||
|
||||
/**
|
||||
* Makes a simple HTTP Get request to the Image microservice.
|
||||
@ -57,11 +60,8 @@ public class ImageClientImpl implements ImageClient {
|
||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
||||
logResponse(httpResponse);
|
||||
return httpResponse.body();
|
||||
} catch (IOException ioe) {
|
||||
LOGGER.error("Failure occurred while getting image path", ioe);
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.error("Failure occurred while getting image path", ie);
|
||||
Thread.currentThread().interrupt();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOGGER.error("Failure occurred while getting image path", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -23,17 +23,20 @@
|
||||
|
||||
package com.iluwatar.api.gateway;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Encapsulates all of the information that mobile client needs to display a product.
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class MobileProduct {
|
||||
/**
|
||||
* The price of the product.
|
||||
*/
|
||||
private String price;
|
||||
|
||||
public String getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(String price) {
|
||||
this.price = price;
|
||||
}
|
||||
}
|
||||
|
@ -23,22 +23,25 @@
|
||||
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
/**
|
||||
* An adapter to communicate with the Price microservice.
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class PriceClientImpl implements PriceClient {
|
||||
private static final Logger LOGGER = getLogger(PriceClientImpl.class);
|
||||
|
||||
/**
|
||||
* Makes a simple HTTP Get request to the Price microservice.
|
||||
@ -58,11 +61,8 @@ public class PriceClientImpl implements PriceClient {
|
||||
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
|
||||
logResponse(httpResponse);
|
||||
return httpResponse.body();
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | InterruptedException e) {
|
||||
LOGGER.error("Failure occurred while getting price info", e);
|
||||
} catch (InterruptedException e) {
|
||||
LOGGER.error("Failure occurred while getting price info", e);
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -35,7 +35,7 @@ import org.mockito.MockitoAnnotations;
|
||||
/**
|
||||
* Test API Gateway Pattern
|
||||
*/
|
||||
class ApiGatewayTest {
|
||||
public class ApiGatewayTest {
|
||||
|
||||
@InjectMocks
|
||||
private ApiGateway apiGateway;
|
||||
@ -55,7 +55,7 @@ class ApiGatewayTest {
|
||||
* Tests getting the data for a desktop client
|
||||
*/
|
||||
@Test
|
||||
void testGetProductDesktop() {
|
||||
public void testGetProductDesktop() {
|
||||
var imagePath = "/product-image.png";
|
||||
var price = "20";
|
||||
when(imageClient.getImagePath()).thenReturn(imagePath);
|
||||
@ -71,7 +71,7 @@ class ApiGatewayTest {
|
||||
* Tests getting the data for a mobile client
|
||||
*/
|
||||
@Test
|
||||
void testGetProductMobile() {
|
||||
public void testGetProductMobile() {
|
||||
var price = "20";
|
||||
when(priceClient.getPrice()).thenReturn(price);
|
||||
|
||||
|
@ -23,24 +23,27 @@
|
||||
|
||||
package com.iluwatar.image.microservice;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class ImageController {
|
||||
private static final Logger LOGGER = getLogger(ImageController.class);
|
||||
|
||||
/**
|
||||
* An endpoint for a user to retrieve an image path.
|
||||
*
|
||||
* @return An image path
|
||||
*/
|
||||
@GetMapping("/image-path")
|
||||
@RequestMapping(value = "/image-path", method = RequestMethod.GET)
|
||||
public String getImagePath() {
|
||||
LOGGER.info("Successfully found image path");
|
||||
return "/product-image.png";
|
||||
|
@ -23,17 +23,16 @@
|
||||
|
||||
package com.iluwatar.image.microservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for Image Rest Controller
|
||||
*/
|
||||
class ImageControllerTest {
|
||||
|
||||
public class ImageControllerTest {
|
||||
@Test
|
||||
void testGetImagePath() {
|
||||
public void testGetImagePath() {
|
||||
var imageController = new ImageController();
|
||||
var imagePath = imageController.getImagePath();
|
||||
assertEquals("/product-image.png", imagePath);
|
||||
|
@ -23,24 +23,27 @@
|
||||
|
||||
package com.iluwatar.price.microservice;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class PriceController {
|
||||
private static final Logger LOGGER = getLogger(PriceController.class);
|
||||
|
||||
/**
|
||||
* An endpoint for a user to retrieve a product's price.
|
||||
*
|
||||
* @return A product's price
|
||||
*/
|
||||
@GetMapping("/price")
|
||||
@RequestMapping(value = "/price", method = RequestMethod.GET)
|
||||
public String getPrice() {
|
||||
LOGGER.info("Successfully found price info");
|
||||
return "20";
|
||||
|
@ -23,17 +23,16 @@
|
||||
|
||||
package com.iluwatar.price.microservice;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for Price Rest Controller
|
||||
*/
|
||||
class PriceControllerTest {
|
||||
|
||||
public class PriceControllerTest {
|
||||
@Test
|
||||
void testgetPrice() {
|
||||
public void testgetPrice() {
|
||||
var priceController = new PriceController();
|
||||
var price = priceController.getPrice();
|
||||
assertEquals("20", price);
|
||||
|
@ -81,10 +81,10 @@ Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the
|
||||
separated steps for each unit test.
|
||||
|
||||
```java
|
||||
class CashAAATest {
|
||||
public class CashAAATest {
|
||||
|
||||
@Test
|
||||
void testPlus() {
|
||||
public void testPlus() {
|
||||
//Arrange
|
||||
var cash = new Cash(3);
|
||||
//Act
|
||||
@ -94,7 +94,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMinus() {
|
||||
public void testMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(8);
|
||||
//Act
|
||||
@ -105,7 +105,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsufficientMinus() {
|
||||
public void testInsufficientMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(1);
|
||||
//Act
|
||||
@ -116,7 +116,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate() {
|
||||
public void testUpdate() {
|
||||
//Arrange
|
||||
var cash = new Cash(5);
|
||||
//Act
|
||||
|
@ -36,8 +36,8 @@
|
||||
<artifactId>arrange-act-assert</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -23,17 +23,18 @@
|
||||
|
||||
package com.iluwatar.arrangeactassert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* Arrange/Act/Assert (AAA) is a unit test pattern. In this simple example, we have a ({@link Cash})
|
||||
* object for plus, minus and counting amount.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class Cash {
|
||||
|
||||
private int amount;
|
||||
|
||||
Cash(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
//plus
|
||||
void plus(int addend) {
|
||||
amount += addend;
|
||||
|
@ -23,11 +23,11 @@
|
||||
|
||||
package com.iluwatar.arrangeactassert;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Arrange/Act/Assert (AAA) is a pattern for organizing unit tests. It is a way to structure your
|
||||
@ -51,11 +51,10 @@ import org.junit.jupiter.api.Test;
|
||||
* change and one reason to fail. In a large and complicated code base, tests that honor the single
|
||||
* responsibility principle are much easier to troubleshoot.
|
||||
*/
|
||||
|
||||
class CashAAATest {
|
||||
public class CashAAATest {
|
||||
|
||||
@Test
|
||||
void testPlus() {
|
||||
public void testPlus() {
|
||||
//Arrange
|
||||
var cash = new Cash(3);
|
||||
//Act
|
||||
@ -65,7 +64,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMinus() {
|
||||
public void testMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(8);
|
||||
//Act
|
||||
@ -76,7 +75,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsufficientMinus() {
|
||||
public void testInsufficientMinus() {
|
||||
//Arrange
|
||||
var cash = new Cash(1);
|
||||
//Act
|
||||
@ -87,7 +86,7 @@ class CashAAATest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate() {
|
||||
public void testUpdate() {
|
||||
//Arrange
|
||||
var cash = new Cash(5);
|
||||
//Act
|
||||
|
@ -23,24 +23,23 @@
|
||||
|
||||
package com.iluwatar.arrangeactassert;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* ({@link CashAAATest}) is an anti-example of AAA pattern. This test is functionally correct, but
|
||||
* with the addition of a new feature, it needs refactoring. There are an awful lot of steps in that
|
||||
* with the addition of new feature, it needs refactoring. There are an awful lot of steps in that
|
||||
* test method, but it verifies the class' important behavior in just eleven lines. It violates the
|
||||
* single responsibility principle. If this test method failed after a small code change, it might
|
||||
* take some digging to discover why.
|
||||
*/
|
||||
|
||||
class CashAntiAAATest {
|
||||
public class CashAntiAAATest {
|
||||
|
||||
@Test
|
||||
void testCash() {
|
||||
public void testCash() {
|
||||
//initialize
|
||||
var cash = new Cash(3);
|
||||
//test plus
|
||||
|
@ -45,6 +45,11 @@
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -24,7 +24,8 @@
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
|
||||
@ -54,9 +55,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @see java.util.concurrent.CompletableFuture
|
||||
* @see java.util.concurrent.ExecutorService
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*/
|
||||
|
@ -23,9 +23,11 @@
|
||||
|
||||
package com.iluwatar.balking;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* In Balking Design Pattern if an object’s method is invoked when it is in an inappropriate state,
|
||||
@ -38,9 +40,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* been already washing and any other thread execute wash() it can't do that once again and returns
|
||||
* doing nothing.
|
||||
*/
|
||||
@Slf4j
|
||||
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Entry Point.
|
||||
*
|
||||
@ -57,7 +61,6 @@ public class App {
|
||||
executorService.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.error("ERROR: Waiting on executor service shutdown!");
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,14 +24,15 @@
|
||||
package com.iluwatar.balking;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Washing machine class.
|
||||
*/
|
||||
@Slf4j
|
||||
public class WashingMachine {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WashingMachine.class);
|
||||
private final DelayProvider delayProvider;
|
||||
private WashingMachineState washingMachineState;
|
||||
|
||||
@ -43,8 +44,7 @@ public class WashingMachine {
|
||||
try {
|
||||
Thread.sleep(timeUnit.toMillis(interval));
|
||||
} catch (InterruptedException ie) {
|
||||
LOGGER.error("", ie);
|
||||
Thread.currentThread().interrupt();
|
||||
ie.printStackTrace();
|
||||
}
|
||||
task.run();
|
||||
});
|
||||
@ -71,7 +71,7 @@ public class WashingMachine {
|
||||
var machineState = getWashingMachineState();
|
||||
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
|
||||
if (this.washingMachineState == WashingMachineState.WASHING) {
|
||||
LOGGER.error("Cannot wash if the machine has been already washing!");
|
||||
LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
|
||||
return;
|
||||
}
|
||||
this.washingMachineState = WashingMachineState.WASHING;
|
||||
|
@ -28,6 +28,5 @@ package com.iluwatar.balking;
|
||||
* as well as during washing.
|
||||
*/
|
||||
public enum WashingMachineState {
|
||||
ENABLED,
|
||||
WASHING
|
||||
ENABLED, WASHING
|
||||
}
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.bridge;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Composition over inheritance. The Bridge pattern can also be thought of as two layers of
|
||||
@ -38,9 +39,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* enchantments. We can easily combine any weapon with any enchantment using composition instead of
|
||||
* creating deep class hierarchy.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.bridge;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* FlyingEnchantment.
|
||||
*/
|
||||
@Slf4j
|
||||
public class FlyingEnchantment implements Enchantment {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FlyingEnchantment.class);
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
LOGGER.info("The item begins to glow faintly.");
|
||||
|
@ -23,18 +23,22 @@
|
||||
|
||||
package com.iluwatar.bridge;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Hammer.
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class Hammer implements Weapon {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Hammer.class);
|
||||
|
||||
private final Enchantment enchantment;
|
||||
|
||||
public Hammer(Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wield() {
|
||||
LOGGER.info("The hammer is wielded.");
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.bridge;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* SoulEatingEnchantment.
|
||||
*/
|
||||
@Slf4j
|
||||
public class SoulEatingEnchantment implements Enchantment {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SoulEatingEnchantment.class);
|
||||
|
||||
@Override
|
||||
public void onActivate() {
|
||||
LOGGER.info("The item spreads bloodlust.");
|
||||
|
@ -23,18 +23,22 @@
|
||||
|
||||
package com.iluwatar.bridge;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Sword.
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class Sword implements Weapon {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Sword.class);
|
||||
|
||||
private final Enchantment enchantment;
|
||||
|
||||
public Sword(Enchantment enchantment) {
|
||||
this.enchantment = enchantment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wield() {
|
||||
LOGGER.info("The sword is wielded.");
|
||||
|
@ -24,7 +24,8 @@
|
||||
package com.iluwatar.builder;
|
||||
|
||||
import com.iluwatar.builder.Hero.Builder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The intention of the Builder pattern is to find a solution to the telescoping constructor
|
||||
@ -47,9 +48,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* configuration for the {@link Hero} object can be done using the fluent {@link Builder} interface.
|
||||
* When configuration is ready the build method is called to receive the final {@link Hero} object.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
@ -74,5 +76,6 @@ public class App {
|
||||
.withWeapon(Weapon.BOW)
|
||||
.build();
|
||||
LOGGER.info(thief.toString());
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,21 +23,19 @@
|
||||
|
||||
package com.iluwatar.builder;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* Armor enumeration.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum Armor {
|
||||
|
||||
CLOTHES("clothes"),
|
||||
LEATHER("leather"),
|
||||
CHAIN_MAIL("chain mail"),
|
||||
PLATE_MAIL("plate mail");
|
||||
CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
|
||||
|
||||
private final String title;
|
||||
|
||||
Armor(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
|
@ -28,11 +28,7 @@ package com.iluwatar.builder;
|
||||
*/
|
||||
public enum HairColor {
|
||||
|
||||
WHITE,
|
||||
BLOND,
|
||||
RED,
|
||||
BROWN,
|
||||
BLACK;
|
||||
WHITE, BLOND, RED, BROWN, BLACK;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
@ -23,22 +23,20 @@
|
||||
|
||||
package com.iluwatar.builder;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* HairType enumeration.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public enum HairType {
|
||||
|
||||
BALD("bald"),
|
||||
SHORT("short"),
|
||||
CURLY("curly"),
|
||||
LONG_STRAIGHT("long straight"),
|
||||
LONG_CURLY("long curly");
|
||||
BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
|
||||
"long curly");
|
||||
|
||||
private final String title;
|
||||
|
||||
HairType(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return title;
|
||||
|
@ -41,6 +41,7 @@ class AppTest {
|
||||
|
||||
@Test
|
||||
void shouldExecuteApplicationWithoutException() {
|
||||
|
||||
assertDoesNotThrow(() -> App.main(new String[]{}));
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ package com.iluwatar.business.delegate;
|
||||
public class BusinessDelegate {
|
||||
|
||||
private BusinessLookup lookupService;
|
||||
private BusinessService businessService;
|
||||
private ServiceType serviceType;
|
||||
|
||||
public void setLookupService(BusinessLookup businessLookup) {
|
||||
@ -40,7 +41,7 @@ public class BusinessDelegate {
|
||||
}
|
||||
|
||||
public void doTask() {
|
||||
BusinessService businessService = lookupService.getBusinessService(serviceType);
|
||||
businessService = lookupService.getBusinessService(serviceType);
|
||||
businessService.doProcessing();
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,9 @@
|
||||
|
||||
package com.iluwatar.business.delegate;
|
||||
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Class for performing service lookups.
|
||||
*/
|
||||
@Setter
|
||||
public class BusinessLookup {
|
||||
|
||||
private EjbService ejbService;
|
||||
@ -48,4 +45,12 @@ public class BusinessLookup {
|
||||
return jmsService;
|
||||
}
|
||||
}
|
||||
|
||||
public void setJmsService(JmsService jmsService) {
|
||||
this.jmsService = jmsService;
|
||||
}
|
||||
|
||||
public void setEjbService(EjbService ejbService) {
|
||||
this.ejbService = ejbService;
|
||||
}
|
||||
}
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.business.delegate;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service EJB implementation.
|
||||
*/
|
||||
@Slf4j
|
||||
public class EjbService implements BusinessService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(EjbService.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing() {
|
||||
LOGGER.info("EjbService is now processing");
|
||||
|
@ -23,14 +23,16 @@
|
||||
|
||||
package com.iluwatar.business.delegate;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Service JMS implementation.
|
||||
*/
|
||||
@Slf4j
|
||||
public class JmsService implements BusinessService {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(JmsService.class);
|
||||
|
||||
@Override
|
||||
public void doProcessing() {
|
||||
LOGGER.info("JmsService is now processing");
|
||||
|
@ -28,6 +28,5 @@ package com.iluwatar.business.delegate;
|
||||
*/
|
||||
public enum ServiceType {
|
||||
|
||||
EJB,
|
||||
JMS
|
||||
EJB, JMS
|
||||
}
|
||||
|
@ -35,17 +35,19 @@ import static org.mockito.Mockito.verify;
|
||||
* tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
|
||||
* encapsulates knowledge about how to locate, connect to, and interact with the business objects
|
||||
* that make up the application.
|
||||
*
|
||||
*
|
||||
* <p>Some of the services the Business Delegate uses are instantiated directly, and some can be
|
||||
* retrieved through service lookups. The Business Delegate itself may contain business logic too
|
||||
* potentially tying together multiple service calls, exception handling, retrying etc.
|
||||
*/
|
||||
class BusinessDelegateTest {
|
||||
public class BusinessDelegateTest {
|
||||
|
||||
private EjbService ejbService;
|
||||
|
||||
private JmsService jmsService;
|
||||
|
||||
private BusinessLookup businessLookup;
|
||||
|
||||
private BusinessDelegate businessDelegate;
|
||||
|
||||
/**
|
||||
@ -57,7 +59,7 @@ class BusinessDelegateTest {
|
||||
ejbService = spy(new EjbService());
|
||||
jmsService = spy(new JmsService());
|
||||
|
||||
BusinessLookup businessLookup = spy(new BusinessLookup());
|
||||
businessLookup = spy(new BusinessLookup());
|
||||
businessLookup.setEjbService(ejbService);
|
||||
businessLookup.setJmsService(jmsService);
|
||||
|
||||
@ -71,7 +73,7 @@ class BusinessDelegateTest {
|
||||
* service and makes the service call.
|
||||
*/
|
||||
@Test
|
||||
void testBusinessDelegate() {
|
||||
public void testBusinessDelegate() {
|
||||
|
||||
// setup a client object
|
||||
var client = new Client(businessDelegate);
|
||||
|
@ -24,7 +24,8 @@
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import com.iluwatar.bytecode.util.InstructionConverterUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The intention of Bytecode pattern is to give behavior the flexibility of data by encoding it as
|
||||
@ -39,8 +40,8 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of
|
||||
* the codebase.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Main app method.
|
||||
|
@ -23,14 +23,9 @@
|
||||
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Representation of instructions understandable by virtual machine.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum Instruction {
|
||||
|
||||
LITERAL(1),
|
||||
@ -45,7 +40,15 @@ public enum Instruction {
|
||||
ADD(10),
|
||||
DIVIDE(11);
|
||||
|
||||
private final int intValue;
|
||||
private final int value;
|
||||
|
||||
Instruction(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts integer value to Instruction.
|
||||
|
@ -24,12 +24,10 @@
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import java.util.Stack;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Implementation of virtual machine.
|
||||
*/
|
||||
@Getter
|
||||
public class VirtualMachine {
|
||||
|
||||
private final Stack<Integer> stack = new Stack<>();
|
||||
@ -110,6 +108,10 @@ public class VirtualMachine {
|
||||
}
|
||||
}
|
||||
|
||||
public Stack<Integer> getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void setHealth(int wizard, int amount) {
|
||||
wizards[wizard].setHealth(amount);
|
||||
}
|
||||
@ -133,4 +135,8 @@ public class VirtualMachine {
|
||||
public int getAgility(int wizard) {
|
||||
return wizards[wizard].getAgility();
|
||||
}
|
||||
|
||||
public Wizard[] getWizards() {
|
||||
return wizards;
|
||||
}
|
||||
}
|
||||
|
@ -23,18 +23,15 @@
|
||||
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* This class represent game objects which properties can be changed by instructions interpreted by
|
||||
* virtual machine.
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class Wizard {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
|
||||
|
||||
private int health;
|
||||
|
||||
@ -44,6 +41,30 @@ public class Wizard {
|
||||
private int numberOfPlayedSounds;
|
||||
private int numberOfSpawnedParticles;
|
||||
|
||||
public int getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
public void setHealth(int health) {
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
public int getAgility() {
|
||||
return agility;
|
||||
}
|
||||
|
||||
public void setAgility(int agility) {
|
||||
this.agility = agility;
|
||||
}
|
||||
|
||||
public int getWisdom() {
|
||||
return wisdom;
|
||||
}
|
||||
|
||||
public void setWisdom(int wisdom) {
|
||||
this.wisdom = wisdom;
|
||||
}
|
||||
|
||||
public void playSound() {
|
||||
LOGGER.info("Playing sound");
|
||||
numberOfPlayedSounds++;
|
||||
@ -54,4 +75,11 @@ public class Wizard {
|
||||
numberOfSpawnedParticles++;
|
||||
}
|
||||
|
||||
public int getNumberOfPlayedSounds() {
|
||||
return numberOfPlayedSounds;
|
||||
}
|
||||
|
||||
public int getNumberOfSpawnedParticles() {
|
||||
return numberOfSpawnedParticles;
|
||||
}
|
||||
}
|
||||
|
@ -23,19 +23,19 @@
|
||||
|
||||
package com.iluwatar.bytecode;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.iluwatar.bytecode.Instruction.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link VirtualMachine}
|
||||
* Test for {@Link VirtualMachine}
|
||||
*/
|
||||
class VirtualMachineTest {
|
||||
public class VirtualMachineTest {
|
||||
|
||||
@Test
|
||||
void testLiteral() {
|
||||
public void testLiteral() {
|
||||
var bytecode = new int[2];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
bytecode[1] = 10;
|
||||
@ -48,7 +48,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetHealth() {
|
||||
public void testSetHealth() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -64,7 +64,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetAgility() {
|
||||
public void testSetAgility() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -80,7 +80,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetWisdom() {
|
||||
public void testSetWisdom() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[5];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -96,7 +96,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetHealth() {
|
||||
public void testGetHealth() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[8];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -115,7 +115,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPlaySound() {
|
||||
public void testPlaySound() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[3];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -130,7 +130,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSpawnParticles() {
|
||||
public void testSpawnParticles() {
|
||||
var wizardNumber = 0;
|
||||
var bytecode = new int[3];
|
||||
bytecode[0] = LITERAL.getIntValue();
|
||||
@ -145,7 +145,7 @@ class VirtualMachineTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInvalidInstruction() {
|
||||
public void testInvalidInstruction() {
|
||||
var bytecode = new int[1];
|
||||
bytecode[0] = 999;
|
||||
var vm = new VirtualMachine();
|
||||
|
@ -24,16 +24,16 @@
|
||||
package com.iluwatar.bytecode.util;
|
||||
|
||||
import com.iluwatar.bytecode.Instruction;
|
||||
import com.iluwatar.bytecode.util.InstructionConverterUtil;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Test for {@link InstructionConverterUtil}
|
||||
* Test for {@Link InstructionConverterUtil}
|
||||
*/
|
||||
class InstructionConverterUtilTest {
|
||||
|
||||
public class InstructionConverterUtilTest {
|
||||
@Test
|
||||
void testEmptyInstruction() {
|
||||
public void testEmptyInstruction() {
|
||||
var instruction = "";
|
||||
|
||||
var bytecode = InstructionConverterUtil.convertToByteCode(instruction);
|
||||
@ -42,7 +42,7 @@ class InstructionConverterUtilTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstructions() {
|
||||
public void testInstructions() {
|
||||
var instructions = "LITERAL 35 SET_HEALTH SET_WISDOM SET_AGILITY PLAY_SOUND"
|
||||
+ " SPAWN_PARTICLES GET_HEALTH ADD DIVIDE";
|
||||
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.caching;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
|
||||
@ -59,9 +60,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @see LruCache
|
||||
* @see CachingPolicy
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
|
@ -26,14 +26,16 @@ package com.iluwatar.caching;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The caching strategies are implemented in this class.
|
||||
*/
|
||||
@Slf4j
|
||||
public class CacheStore {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CacheStore.class);
|
||||
|
||||
private static LruCache cache;
|
||||
|
||||
private CacheStore() {
|
||||
|
@ -23,19 +23,19 @@
|
||||
|
||||
package com.iluwatar.caching;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Enum class containing the four caching strategies implemented in the pattern.
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum CachingPolicy {
|
||||
THROUGH("through"),
|
||||
AROUND("around"),
|
||||
BEHIND("behind"),
|
||||
ASIDE("aside");
|
||||
THROUGH("through"), AROUND("around"), BEHIND("behind"), ASIDE("aside");
|
||||
|
||||
private final String policy;
|
||||
|
||||
CachingPolicy(String policy) {
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
public String getPolicy() {
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Data structure/implementation of the application's cache. The data structure consists of a hash
|
||||
@ -36,10 +37,11 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* the data is moved to the front of the list to depict itself as the most-recently-used data. The
|
||||
* LRU data is always at the end of the list.
|
||||
*/
|
||||
@Slf4j
|
||||
public class LruCache {
|
||||
|
||||
static class Node {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(LruCache.class);
|
||||
|
||||
class Node {
|
||||
String userId;
|
||||
UserAccount userAccount;
|
||||
Node previous;
|
||||
|
@ -23,20 +23,49 @@
|
||||
|
||||
package com.iluwatar.caching;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* Entity class (stored in cache and DB) used in the application.
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class UserAccount {
|
||||
private String userId;
|
||||
private String userName;
|
||||
private String additionalInfo;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public UserAccount(String userId, String userName, String additionalInfo) {
|
||||
this.userId = userId;
|
||||
this.userName = userName;
|
||||
this.additionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public String getAdditionalInfo() {
|
||||
return additionalInfo;
|
||||
}
|
||||
|
||||
public void setAdditionalInfo(String additionalInfo) {
|
||||
this.additionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return userId + ", " + userName + ", " + additionalInfo;
|
||||
}
|
||||
}
|
||||
|
@ -54,9 +54,10 @@ public abstract class Task {
|
||||
public abstract void execute();
|
||||
}
|
||||
|
||||
@Slf4j
|
||||
public final class SimpleTask extends Task {
|
||||
|
||||
private static final Logger LOGGER = getLogger(SimpleTask.class);
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
LOGGER.info("Perform some important activity and after call the callback method.");
|
||||
|
@ -23,16 +23,19 @@
|
||||
|
||||
package com.iluwatar.callback;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Callback pattern is more native for functional languages where functions are treated as
|
||||
* first-class citizens. Prior to Java 8 callbacks can be simulated using simple (alike command)
|
||||
* interfaces.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class App {
|
||||
|
||||
private static final Logger LOGGER = getLogger(App.class);
|
||||
|
||||
private App() {
|
||||
}
|
||||
|
||||
|
@ -23,16 +23,20 @@
|
||||
|
||||
package com.iluwatar.callback;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import static org.slf4j.LoggerFactory.getLogger;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* Implementation of task that need to be executed.
|
||||
*/
|
||||
@Slf4j
|
||||
public final class SimpleTask extends Task {
|
||||
|
||||
private static final Logger LOGGER = getLogger(SimpleTask.class);
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
LOGGER.info("Perform some important activity and after call the callback method.");
|
||||
LOGGER.info("Perform some important activity and after call the"
|
||||
+ " callback method.");
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public class CallbackTest {
|
||||
private Integer callingCount = 0;
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
public void test() {
|
||||
Callback callback = () -> callingCount++;
|
||||
|
||||
var task = new SimpleTask();
|
||||
|
@ -68,8 +68,8 @@ public enum RequestType {
|
||||
Then the request handler hierarchy
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public abstract class RequestHandler {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
||||
private final RequestHandler next;
|
||||
|
||||
public RequestHandler(RequestHandler next) {
|
||||
|
@ -47,5 +47,6 @@ public class App {
|
||||
king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
|
||||
king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
|
||||
king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,18 +23,22 @@
|
||||
|
||||
package com.iluwatar.chain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* RequestHandler.
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public abstract class RequestHandler {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class);
|
||||
|
||||
private final RequestHandler next;
|
||||
|
||||
public RequestHandler(RequestHandler next) {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request handler.
|
||||
*/
|
||||
|
@ -28,8 +28,6 @@ package com.iluwatar.chain;
|
||||
*/
|
||||
public enum RequestType {
|
||||
|
||||
DEFEND_CASTLE,
|
||||
TORTURE_PRISONER,
|
||||
COLLECT_TAX
|
||||
DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
|
||||
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import org.junit.jupiter.api.Test;
|
||||
*
|
||||
* @author Jeroen Meulemeester
|
||||
*/
|
||||
class OrcKingTest {
|
||||
public class OrcKingTest {
|
||||
|
||||
/**
|
||||
* All possible requests
|
||||
@ -45,7 +45,7 @@ class OrcKingTest {
|
||||
);
|
||||
|
||||
@Test
|
||||
void testMakeRequest() {
|
||||
public void testMakeRequest() {
|
||||
final var king = new OrcKing();
|
||||
|
||||
REQUESTS.forEach(request -> {
|
||||
|
@ -54,7 +54,6 @@ The service architecture is as follows:
|
||||
In terms of code, the end user application is:
|
||||
|
||||
```java
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
package com.iluwatar.circuitbreaker;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@ -54,9 +55,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* recovers, it goes back to the closed state and the cycle continues.
|
||||
* </p>
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
*
|
||||
|
@ -35,7 +35,7 @@ public class DefaultCircuitBreakerTest {
|
||||
|
||||
//long timeout, int failureThreshold, long retryTimePeriod
|
||||
@Test
|
||||
void testEvaluateState() {
|
||||
public void testEvaluateState() {
|
||||
var circuitBreaker = new DefaultCircuitBreaker(null, 1, 1, 100);
|
||||
//Right now, failureCount<failureThreshold, so state should be closed
|
||||
assertEquals(circuitBreaker.getState(), "CLOSED");
|
||||
@ -57,7 +57,7 @@ public class DefaultCircuitBreakerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSetStateForBypass() {
|
||||
public void testSetStateForBypass() {
|
||||
var circuitBreaker = new DefaultCircuitBreaker(null, 1, 1, 2000 * 1000 * 1000);
|
||||
//Right now, failureCount<failureThreshold, so state should be closed
|
||||
//Bypass it and set it to open
|
||||
@ -66,7 +66,7 @@ public class DefaultCircuitBreakerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testApiResponses() throws RemoteServiceException {
|
||||
public void testApiResponses() throws RemoteServiceException {
|
||||
RemoteService mockService = new RemoteService() {
|
||||
@Override
|
||||
public String call() throws RemoteServiceException {
|
||||
@ -79,5 +79,6 @@ public class DefaultCircuitBreakerTest {
|
||||
var serviceStartTime = System.nanoTime() - 60 * 1000 * 1000 * 1000;
|
||||
var response = circuitBreaker.attemptRequest();
|
||||
assertEquals(response, "Remote Success");
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
/**
|
||||
* Monitoring Service test
|
||||
*/
|
||||
class DelayedRemoteServiceTest {
|
||||
public class DelayedRemoteServiceTest {
|
||||
|
||||
/**
|
||||
* Testing immediate response of the delayed service.
|
||||
@ -39,7 +39,7 @@ class DelayedRemoteServiceTest {
|
||||
* @throws RemoteServiceException
|
||||
*/
|
||||
@Test
|
||||
void testDefaultConstructor() throws RemoteServiceException {
|
||||
public void testDefaultConstructor() throws RemoteServiceException {
|
||||
Assertions.assertThrows(RemoteServiceException.class, () -> {
|
||||
var obj = new DelayedRemoteService();
|
||||
obj.call();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user