Java 11 migration: ambassador async-method-invocation balking bridge builder (#1076)

* Moves ambassador pattern to java 11

* Moves async-method-invocation pattern  to java 11

* Moves balking pattern  to java 11

* Moves bridge pattern  to java 11

* Moves builder pattern  to java 11
This commit is contained in:
Anurag Agarwal 2019-11-12 01:17:09 +05:30 committed by Ilkka Seppälä
parent f0f0143d48
commit c4418311c6
27 changed files with 173 additions and 176 deletions

View File

@ -42,7 +42,7 @@ A remote services represented as a singleton.
```java ```java
public class RemoteService implements RemoteServiceInterface { public class RemoteService implements RemoteServiceInterface {
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class); private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
private static RemoteService service = null; private static RemoteService service = null;
static synchronized RemoteService getRemoteService() { static synchronized RemoteService getRemoteService() {
@ -56,14 +56,14 @@ public class RemoteService implements RemoteServiceInterface {
@Override @Override
public long doRemoteFunction(int value) { public long doRemoteFunction(int value) {
long waitTime = (long) Math.floor(Math.random() * 1000); long waitTime = (long) Math.floor(Math.random() * 1000);
try { try {
sleep(waitTime); sleep(waitTime);
} catch (InterruptedException e) { } catch (InterruptedException e) {
LOGGER.error("Thread sleep interrupted", e) LOGGER.error("Thread sleep interrupted", e);
} }
return waitTime >= 200 ? value * 10 : -1; return waitTime >= 200 ? value * 10 : -1;
} }
} }
@ -137,7 +137,7 @@ public class Client {
long useService(int value) { long useService(int value) {
long result = serviceAmbassador.doRemoteFunction(value); long result = serviceAmbassador.doRemoteFunction(value);
LOGGER.info("Service result: " + result) LOGGER.info("Service result: " + result);
return result; return result;
} }
} }
@ -146,10 +146,14 @@ public class Client {
And here are two clients using the service. And here are two clients using the service.
```java ```java
Client host1 = new Client(); public class App {
Client host2 = new Client(); public static void main(String[] args) {
host1.useService(12); Client host1 = new Client();
host2.useService(73); Client host2 = new Client();
host1.useService(12);
host2.useService(73);
}
}
``` ```
## Applicability ## Applicability

View File

@ -35,7 +35,7 @@ public class Client {
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador(); private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
long useService(int value) { long useService(int value) {
long result = serviceAmbassador.doRemoteFunction(value); var result = serviceAmbassador.doRemoteFunction(value);
LOGGER.info("Service result: " + result); LOGGER.info("Service result: " + result);
return result; return result;
} }

View File

@ -33,7 +33,7 @@ import org.slf4j.LoggerFactory;
* A remote legacy application represented by a Singleton implementation. * A remote legacy application represented by a Singleton implementation.
*/ */
public class RemoteService implements RemoteServiceInterface { public class RemoteService implements RemoteServiceInterface {
static final int THRESHOLD = 200; private static final int THRESHOLD = 200;
private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class); private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class);
private static RemoteService service = null; private static RemoteService service = null;
private final RandomProvider randomProvider; private final RandomProvider randomProvider;
@ -50,7 +50,7 @@ public class RemoteService implements RemoteServiceInterface {
} }
/** /**
* This constuctor is used for testing purposes only. * This constructor is used for testing purposes only.
*/ */
RemoteService(RandomProvider randomProvider) { RemoteService(RandomProvider randomProvider) {
this.randomProvider = randomProvider; this.randomProvider = randomProvider;

View File

@ -48,21 +48,19 @@ public class ServiceAmbassador implements RemoteServiceInterface {
} }
private long checkLatency(int value) { private long checkLatency(int value) {
long startTime = System.currentTimeMillis(); var startTime = System.currentTimeMillis();
long result = RemoteService.getRemoteService().doRemoteFunction(value); var result = RemoteService.getRemoteService().doRemoteFunction(value);
long timeTaken = System.currentTimeMillis() - startTime; var timeTaken = System.currentTimeMillis() - startTime;
LOGGER.info("Time taken (ms): " + timeTaken); LOGGER.info("Time taken (ms): " + timeTaken);
return result; return result;
} }
private long safeCall(int value) { private long safeCall(int value) {
var retries = 0;
int retries = 0; var result = (long) FAILURE;
long result = FAILURE;
for (int i = 0; i < RETRIES; i++) { for (int i = 0; i < RETRIES; i++) {
if (retries >= RETRIES) { if (retries >= RETRIES) {
return FAILURE; return FAILURE;
} }

View File

@ -28,10 +28,10 @@ import org.junit.jupiter.api.Test;
/** /**
* Application test * Application test
*/ */
public class AppTest { class AppTest {
@Test @Test
public void test() { void test() {
App.main(new String[]{}); App.main(new String[]{});
} }
} }

View File

@ -30,13 +30,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* Test for {@link Client} * Test for {@link Client}
*/ */
public class ClientTest { class ClientTest {
@Test @Test
public void test() { void test() {
Client client = new Client(); Client client = new Client();
long result = client.useService(10); var result = client.useService(10);
assertTrue(result == 100 || result == RemoteService.FAILURE); assertTrue(result == 100 || result == RemoteService.FAILURE);
} }

View File

@ -23,34 +23,31 @@
package com.iluwatar.ambassador; package com.iluwatar.ambassador;
import static org.junit.jupiter.api.Assertions.assertEquals;
import com.iluwatar.ambassador.util.RandomProvider; import com.iluwatar.ambassador.util.RandomProvider;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* Test for {@link RemoteService} * Test for {@link RemoteService}
*/ */
public class RemoteServiceTest { class RemoteServiceTest {
@Test @Test
public void testFailedCall() { void testFailedCall() {
RemoteService remoteService = new RemoteService( var remoteService = new RemoteService(new StaticRandomProvider(0.21));
new StaticRandomProvider(0.21)); var result = remoteService.doRemoteFunction(10);
long result = remoteService.doRemoteFunction(10);
assertEquals(RemoteServiceInterface.FAILURE, result); assertEquals(RemoteServiceInterface.FAILURE, result);
} }
@Test @Test
public void testSuccessfulCall() { void testSuccessfulCall() {
RemoteService remoteService = new RemoteService( var remoteService = new RemoteService(new StaticRandomProvider(0.2));
new StaticRandomProvider(0.2)); var result = remoteService.doRemoteFunction(10);
long result = remoteService.doRemoteFunction(10);
assertEquals(100, result); assertEquals(100, result);
} }
private class StaticRandomProvider implements RandomProvider { private static class StaticRandomProvider implements RandomProvider {
private double value; private double value;
StaticRandomProvider(double value) { StaticRandomProvider(double value) {

View File

@ -30,10 +30,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* Test for {@link ServiceAmbassador} * Test for {@link ServiceAmbassador}
*/ */
public class ServiceAmbassadorTest { class ServiceAmbassadorTest {
@Test @Test
public void test() { void test() {
long result = new ServiceAmbassador().doRemoteFunction(10); long result = new ServiceAmbassador().doRemoteFunction(10);
assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE); assertTrue(result == 100 || result == RemoteServiceInterface.FAILURE);
} }

View File

@ -64,15 +64,14 @@ public class App {
*/ */
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// construct a new executor that will run async tasks // construct a new executor that will run async tasks
AsyncExecutor executor = new ThreadAsyncExecutor(); var executor = new ThreadAsyncExecutor();
// start few async tasks with varying processing times, two last with callback handlers // start few async tasks with varying processing times, two last with callback handlers
final AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500)); final var asyncResult1 = executor.startProcess(lazyval(10, 500));
final AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300)); final var asyncResult2 = executor.startProcess(lazyval("test", 300));
final AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700)); final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
final AsyncResult<Integer> asyncResult4 = final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
executor.startProcess(lazyval(20, 400), callback("Callback result 4")); final var asyncResult5 =
final AsyncResult<String> asyncResult5 =
executor.startProcess(lazyval("callback", 600), callback("Callback result 5")); executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
// emulate processing in the current thread while async tasks are running in their own threads // emulate processing in the current thread while async tasks are running in their own threads
@ -80,9 +79,9 @@ public class App {
log("Some hard work done"); log("Some hard work done");
// wait for completion of the tasks // wait for completion of the tasks
final Integer result1 = executor.endProcess(asyncResult1); final var result1 = executor.endProcess(asyncResult1);
final String result2 = executor.endProcess(asyncResult2); final var result2 = executor.endProcess(asyncResult2);
final Long result3 = executor.endProcess(asyncResult3); final var result3 = executor.endProcess(asyncResult3);
asyncResult4.await(); asyncResult4.await();
asyncResult5.await(); asyncResult5.await();

View File

@ -45,7 +45,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
@Override @Override
public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) { public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) {
CompletableResult<T> result = new CompletableResult<>(callback); var result = new CompletableResult<>(callback);
new Thread(() -> { new Thread(() -> {
try { try {
result.setValue(task.call()); result.setValue(task.call());

View File

@ -28,11 +28,9 @@ import org.junit.jupiter.api.Test;
/** /**
* Application test * Application test
*/ */
public class AppTest { class AppTest {
@Test @Test
public void test() throws Exception { void test() throws Exception {
String[] args = {}; App.main(new String[]{});
App.main(args);
} }
} }

View File

@ -24,39 +24,66 @@
package com.iluwatar.async.method.invocation; package com.iluwatar.async.method.invocation;
import static java.time.Duration.ofMillis; import static java.time.Duration.ofMillis;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times; import static org.mockito.internal.verification.VerificationModeFactory.times;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Matchers; import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/** /**
* Date: 12/6/15 - 10:49 AM * Date: 12/6/15 - 10:49 AM
* *
* @author Jeroen Meulemeester * @author Jeroen Meulemeester
*/ */
public class ThreadAsyncExecutorTest { class ThreadAsyncExecutorTest {
@Captor
private ArgumentCaptor<Optional<Exception>> optionalCaptor;
@Mock
private Callable<Object> task;
@Mock
private AsyncCallback<Object> callback;
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
/** /**
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
*/ */
@Test @Test
public void testSuccessfulTaskWithoutCallback() throws Exception { void testSuccessfulTaskWithoutCallback() throws Exception {
assertTimeout(ofMillis(3000), () -> { assertTimeout(ofMillis(3000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final Object result = new Object(); final var result = new Object();
final Callable<Object> task = mock(Callable.class);
when(task.call()).thenReturn(result); when(task.call()).thenReturn(result);
final AsyncResult<Object> asyncResult = executor.startProcess(task); final var asyncResult = executor.startProcess(task);
assertNotNull(asyncResult); assertNotNull(asyncResult);
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());
@ -74,17 +101,15 @@ public class ThreadAsyncExecutorTest {
* AsyncCallback)} * AsyncCallback)}
*/ */
@Test @Test
public void testSuccessfulTaskWithCallback() throws Exception { void testSuccessfulTaskWithCallback() throws Exception {
assertTimeout(ofMillis(3000), () -> { assertTimeout(ofMillis(3000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final Object result = new Object(); final var result = new Object();
final Callable<Object> task = mock(Callable.class);
when(task.call()).thenReturn(result); when(task.call()).thenReturn(result);
final AsyncCallback callback = mock(AsyncCallback.class); final var asyncResult = executor.startProcess(task, callback);
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
assertNotNull(asyncResult); assertNotNull(asyncResult);
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());
@ -93,11 +118,9 @@ public class ThreadAsyncExecutorTest {
verify(task, times(1)).call(); verify(task, times(1)).call();
// ... same for the callback, we expect our object // ... same for the callback, we expect our object
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
ArgumentCaptor.forClass((Class) Optional.class);
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture()); verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final var optionalException = optionalCaptor.getValue();
assertNotNull(optionalException); assertNotNull(optionalException);
assertFalse(optionalException.isPresent()); assertFalse(optionalException.isPresent());
@ -111,19 +134,18 @@ public class ThreadAsyncExecutorTest {
* task takes a while to execute * task takes a while to execute
*/ */
@Test @Test
public void testLongRunningTaskWithoutCallback() throws Exception { void testLongRunningTaskWithoutCallback() throws Exception {
assertTimeout(ofMillis(5000), () -> { assertTimeout(ofMillis(5000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final Object result = new Object(); final var result = new Object();
final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncResult<Object> asyncResult = executor.startProcess(task); final var asyncResult = executor.startProcess(task);
assertNotNull(asyncResult); assertNotNull(asyncResult);
assertFalse(asyncResult.isCompleted()); assertFalse(asyncResult.isCompleted());
@ -152,20 +174,18 @@ public class ThreadAsyncExecutorTest {
* AsyncCallback)} when a task takes a while to execute * AsyncCallback)} when a task takes a while to execute
*/ */
@Test @Test
public void testLongRunningTaskWithCallback() throws Exception { void testLongRunningTaskWithCallback() throws Exception {
assertTimeout(ofMillis(5000), () -> { assertTimeout(ofMillis(5000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final Object result = new Object(); final var result = new Object();
final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncCallback<Object> callback = mock(AsyncCallback.class); final var asyncResult = executor.startProcess(task, callback);
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
assertNotNull(asyncResult); assertNotNull(asyncResult);
assertFalse(asyncResult.isCompleted()); assertFalse(asyncResult.isCompleted());
@ -180,12 +200,9 @@ public class ThreadAsyncExecutorTest {
// Our task should only execute once, but it can take a while ... // Our task should only execute once, but it can take a while ...
verify(task, timeout(3000).times(1)).call(); verify(task, timeout(3000).times(1)).call();
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
ArgumentCaptor.forClass((Class) Optional.class);
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture()); verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final var optionalException = optionalCaptor.getValue();
assertNotNull(optionalException); assertNotNull(optionalException);
assertFalse(optionalException.isPresent()); assertFalse(optionalException.isPresent());
@ -205,19 +222,18 @@ public class ThreadAsyncExecutorTest {
* ThreadAsyncExecutor#endProcess(AsyncResult)} * ThreadAsyncExecutor#endProcess(AsyncResult)}
*/ */
@Test @Test
public void testEndProcess() throws Exception { void testEndProcess() throws Exception {
assertTimeout(ofMillis(5000), () -> { assertTimeout(ofMillis(5000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final Object result = new Object(); final var result = new Object();
final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncResult<Object> asyncResult = executor.startProcess(task); final var asyncResult = executor.startProcess(task);
assertNotNull(asyncResult); assertNotNull(asyncResult);
assertFalse(asyncResult.isCompleted()); assertFalse(asyncResult.isCompleted());
@ -243,11 +259,11 @@ public class ThreadAsyncExecutorTest {
* the callable is 'null' * the callable is 'null'
*/ */
@Test @Test
public void testNullTask() throws Exception { void testNullTask() throws Exception {
assertTimeout(ofMillis(3000), () -> { assertTimeout(ofMillis(3000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final AsyncResult<Object> asyncResult = executor.startProcess(null); final var asyncResult = executor.startProcess(null);
assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'."); assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'.");
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
@ -270,26 +286,22 @@ public class ThreadAsyncExecutorTest {
* AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided * AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided
*/ */
@Test @Test
public void testNullTaskWithCallback() throws Exception { void testNullTaskWithCallback() throws Exception {
assertTimeout(ofMillis(3000), () -> { assertTimeout(ofMillis(3000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final AsyncCallback<Object> callback = mock(AsyncCallback.class); final var asyncResult = executor.startProcess(null, callback);
final AsyncResult<Object> asyncResult = executor.startProcess(null, callback);
assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'."); assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'.");
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
ArgumentCaptor.forClass((Class) Optional.class);
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture()); verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final var optionalException = optionalCaptor.getValue();
assertNotNull(optionalException); assertNotNull(optionalException);
assertTrue(optionalException.isPresent()); assertTrue(optionalException.isPresent());
final Exception exception = optionalException.get(); final var exception = optionalException.get();
assertNotNull(exception); assertNotNull(exception);
assertEquals(NullPointerException.class, exception.getClass()); assertEquals(NullPointerException.class, exception.getClass());
@ -310,11 +322,11 @@ public class ThreadAsyncExecutorTest {
* AsyncCallback)} when both the callable and the asynchronous callback are 'null' * AsyncCallback)} when both the callable and the asynchronous callback are 'null'
*/ */
@Test @Test
public void testNullTaskWithNullCallback() throws Exception { void testNullTaskWithNullCallback() throws Exception {
assertTimeout(ofMillis(3000), () -> { assertTimeout(ofMillis(3000), () -> {
// Instantiate a new executor and start a new 'null' task ... // Instantiate a new executor and start a new 'null' task ...
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final var executor = new ThreadAsyncExecutor();
final AsyncResult<Object> asyncResult = executor.startProcess(null, null); final var asyncResult = executor.startProcess(null, null);
assertNotNull( assertNotNull(
asyncResult, asyncResult,

View File

@ -51,8 +51,8 @@ public class App {
* @param args the command line arguments - not used * @param args the command line arguments - not used
*/ */
public static void main(String... args) { public static void main(String... args) {
final WashingMachine washingMachine = new WashingMachine(); final var washingMachine = new WashingMachine();
ExecutorService executorService = Executors.newFixedThreadPool(3); var executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
executorService.execute(washingMachine::wash); executorService.execute(washingMachine::wash);
} }

View File

@ -68,7 +68,7 @@ public class WashingMachine {
*/ */
public void wash() { public void wash() {
synchronized (this) { synchronized (this) {
WashingMachineState machineState = getWashingMachineState(); var machineState = getWashingMachineState();
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState); LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
if (this.washingMachineState == WashingMachineState.WASHING) { if (this.washingMachineState == WashingMachineState.WASHING) {
LOGGER.error("ERROR: Cannot wash if the machine has been already washing!"); LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");

View File

@ -28,12 +28,11 @@ import org.junit.jupiter.api.Test;
/** /**
* Application test * Application test
*/ */
public class AppTest { class AppTest {
@Test @Test
public void main() throws Exception { void main() {
String[] args = {}; App.main();
App.main(args);
} }
} }

View File

@ -31,18 +31,18 @@ import org.junit.jupiter.api.Test;
/** /**
* Tests for {@link WashingMachine} * Tests for {@link WashingMachine}
*/ */
public class WashingMachineTest { class WashingMachineTest {
private FakeDelayProvider fakeDelayProvider = new FakeDelayProvider(); private final FakeDelayProvider fakeDelayProvider = new FakeDelayProvider();
@Test @Test
public void wash() { void wash() {
WashingMachine washingMachine = new WashingMachine(fakeDelayProvider); var washingMachine = new WashingMachine(fakeDelayProvider);
washingMachine.wash(); washingMachine.wash();
washingMachine.wash(); washingMachine.wash();
WashingMachineState machineStateGlobal = washingMachine.getWashingMachineState(); var machineStateGlobal = washingMachine.getWashingMachineState();
fakeDelayProvider.task.run(); fakeDelayProvider.task.run();
@ -54,13 +54,13 @@ public class WashingMachineTest {
} }
@Test @Test
public void endOfWashing() { void endOfWashing() {
WashingMachine washingMachine = new WashingMachine(); var washingMachine = new WashingMachine();
washingMachine.wash(); washingMachine.wash();
assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState()); assertEquals(WashingMachineState.ENABLED, washingMachine.getWashingMachineState());
} }
private class FakeDelayProvider implements DelayProvider { private static class FakeDelayProvider implements DelayProvider {
private Runnable task; private Runnable task;
@Override @Override

View File

@ -50,13 +50,13 @@ public class App {
*/ */
public static void main(String[] args) { public static void main(String[] args) {
LOGGER.info("The knight receives an enchanted sword."); LOGGER.info("The knight receives an enchanted sword.");
Sword enchantedSword = new Sword(new SoulEatingEnchantment()); var enchantedSword = new Sword(new SoulEatingEnchantment());
enchantedSword.wield(); enchantedSword.wield();
enchantedSword.swing(); enchantedSword.swing();
enchantedSword.unwield(); enchantedSword.unwield();
LOGGER.info("The valkyrie receives an enchanted hammer."); LOGGER.info("The valkyrie receives an enchanted hammer.");
Hammer hammer = new Hammer(new FlyingEnchantment()); var hammer = new Hammer(new FlyingEnchantment());
hammer.wield(); hammer.wield();
hammer.swing(); hammer.swing();
hammer.unwield(); hammer.unwield();

View File

@ -26,15 +26,11 @@ package com.iluwatar.bridge;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
*
* Application test * Application test
*
*/ */
public class AppTest { class AppTest {
@Test @Test
public void test() { void test() {
String[] args = {}; App.main(new String[]{});
App.main(args);
} }
} }

View File

@ -23,23 +23,23 @@
package com.iluwatar.bridge; package com.iluwatar.bridge;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import org.junit.jupiter.api.Test;
/** /**
* Tests for hammer * Tests for hammer
*/ */
public class HammerTest extends WeaponTest { class HammerTest extends WeaponTest {
/** /**
* Invoke all possible actions on the weapon and check if the actions are executed on the actual * Invoke all possible actions on the weapon and check if the actions are executed on the actual
* underlying weapon implementation. * underlying weapon implementation.
*/ */
@Test @Test
public void testHammer() { void testHammer() {
final Hammer hammer = spy(new Hammer(mock(FlyingEnchantment.class))); final var hammer = spy(new Hammer(mock(FlyingEnchantment.class)));
testBasicWeaponActions(hammer); testBasicWeaponActions(hammer);
} }
} }

View File

@ -23,23 +23,23 @@
package com.iluwatar.bridge; package com.iluwatar.bridge;
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import org.junit.jupiter.api.Test;
/** /**
* Tests for sword * Tests for sword
*/ */
public class SwordTest extends WeaponTest { class SwordTest extends WeaponTest {
/** /**
* Invoke all possible actions on the weapon and check if the actions are executed on the actual * Invoke all possible actions on the weapon and check if the actions are executed on the actual
* underlying weapon implementation. * underlying weapon implementation.
*/ */
@Test @Test
public void testSword() { void testSword() {
final Sword sword = spy(new Sword(mock(FlyingEnchantment.class))); final var sword = spy(new Sword(mock(FlyingEnchantment.class)));
testBasicWeaponActions(sword); testBasicWeaponActions(sword);
} }
} }

View File

@ -23,8 +23,6 @@
package com.iluwatar.bridge; package com.iluwatar.bridge;
import org.junit.jupiter.api.Disabled;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
@ -32,16 +30,15 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
/** /**
* Base class for weapon tests * Base class for weapon tests
*/ */
public abstract class WeaponTest { abstract class WeaponTest {
/** /**
* Invoke the basic actions of the given weapon, and test if the underlying enchantment implementation * Invoke the basic actions of the given weapon, and test if the underlying enchantment
* is invoked * implementation is invoked
*
*/ */
protected final void testBasicWeaponActions(final Weapon weapon) { final void testBasicWeaponActions(final Weapon weapon) {
assertNotNull(weapon); assertNotNull(weapon);
Enchantment enchantment = weapon.getEnchantment(); var enchantment = weapon.getEnchantment();
assertNotNull(enchantment); assertNotNull(enchantment);
assertNotNull(weapon.getEnchantment()); assertNotNull(weapon.getEnchantment());

View File

@ -59,20 +59,22 @@ public class App {
*/ */
public static void main(String[] args) { public static void main(String[] args) {
Hero mage = var mage = new Hero.Builder(Profession.MAGE, "Riobard")
new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK) .withHairColor(HairColor.BLACK)
.withWeapon(Weapon.DAGGER).build(); .withWeapon(Weapon.DAGGER)
.build();
LOGGER.info(mage.toString()); LOGGER.info(mage.toString());
Hero warrior = var warrior = new Hero.Builder(Profession.WARRIOR, "Amberjill")
new Hero.Builder(Profession.WARRIOR, "Amberjill").withHairColor(HairColor.BLOND) .withHairColor(HairColor.BLOND)
.withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD) .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD)
.build(); .build();
LOGGER.info(warrior.toString()); LOGGER.info(warrior.toString());
Hero thief = var thief = new Hero.Builder(Profession.THIEF, "Desmond")
new Hero.Builder(Profession.THIEF, "Desmond").withHairType(HairType.BALD) .withHairType(HairType.BALD)
.withWeapon(Weapon.BOW).build(); .withWeapon(Weapon.BOW)
.build();
LOGGER.info(thief.toString()); LOGGER.info(thief.toString());
} }

View File

@ -30,7 +30,7 @@ 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 String title; private final String title;
Armor(String title) { Armor(String title) {
this.title = title; this.title = title;

View File

@ -31,7 +31,7 @@ public enum HairType {
BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY( BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
"long curly"); "long curly");
private String title; private final String title;
HairType(String title) { HairType(String title) {
this.title = title; this.title = title;

View File

@ -71,7 +71,7 @@ public final class Hero {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); var sb = new StringBuilder();
sb.append("This is a ") sb.append("This is a ")
.append(profession) .append(profession)
.append(" named ") .append(" named ")

View File

@ -26,15 +26,11 @@ package com.iluwatar.builder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
*
* Application test * Application test
*
*/ */
public class AppTest { class AppTest {
@Test @Test
public void test() { void test() {
String[] args = {}; App.main(new String[]{});
App.main(args);
} }
} }

View File

@ -23,24 +23,24 @@
package com.iluwatar.builder; package com.iluwatar.builder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
/** /**
* Date: 12/6/15 - 11:01 PM * Date: 12/6/15 - 11:01 PM
* *
* @author Jeroen Meulemeester * @author Jeroen Meulemeester
*/ */
public class HeroTest { class HeroTest {
/** /**
* Test if we get the expected exception when trying to create a hero without a profession * Test if we get the expected exception when trying to create a hero without a profession
*/ */
@Test @Test
public void testMissingProfession() throws Exception { void testMissingProfession() {
assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(null, "Sir without a job")); assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(null, "Sir without a job"));
} }
@ -48,7 +48,7 @@ public class HeroTest {
* Test if we get the expected exception when trying to create a hero without a name * Test if we get the expected exception when trying to create a hero without a name
*/ */
@Test @Test
public void testMissingName() throws Exception { void testMissingName() {
assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(Profession.THIEF, null)); assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(Profession.THIEF, null));
} }
@ -56,10 +56,10 @@ public class HeroTest {
* Test if the hero build by the builder has the correct attributes, as requested * Test if the hero build by the builder has the correct attributes, as requested
*/ */
@Test @Test
public void testBuildHero() throws Exception { void testBuildHero() {
final String heroName = "Sir Lancelot"; final String heroName = "Sir Lancelot";
final Hero hero = new Hero.Builder(Profession.WARRIOR, heroName) final var hero = new Hero.Builder(Profession.WARRIOR, heroName)
.withArmor(Armor.CHAIN_MAIL) .withArmor(Armor.CHAIN_MAIL)
.withWeapon(Weapon.SWORD) .withWeapon(Weapon.SWORD)
.withHairType(HairType.LONG_CURLY) .withHairType(HairType.LONG_CURLY)