Resolves checkstyle errors for ambassador, async-method-invocation, balking, bridge, builder (#1058)
* Decreases checkstyle errors for ambassador pattern * Reduces checkstyle errors in async-method-invocation * Reduces checkstyle errors in balking * Reduces checkstyle errors in bridge * Reduces checkstyle errors in builder
This commit is contained in:
committed by
Ilkka Seppälä
parent
1fa8a604eb
commit
6d1c0b1563
@ -23,35 +23,34 @@
|
||||
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
|
||||
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated value,
|
||||
* <code>AsyncCallback</code> which can be provided to be executed on task completion and <code>AsyncExecutor</code>
|
||||
* that manages the execution of the async tasks.
|
||||
* <p>
|
||||
* The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
|
||||
* durations and then continues its own work. When the main thread has done it's job it collects the results of the
|
||||
* async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
|
||||
* tasks complete.
|
||||
* <p>
|
||||
* Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
|
||||
* in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
|
||||
* thread pools.
|
||||
* <p>
|
||||
* Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
|
||||
* ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
|
||||
* the implementations are not trivial. This example does not take all possible scenarios into account but rather
|
||||
* provides a simple version that helps to understand the pattern.
|
||||
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated
|
||||
* value, <code>AsyncCallback</code> which can be provided to be executed on task completion and
|
||||
* <code>AsyncExecutor</code> that manages the execution of the async tasks.
|
||||
*
|
||||
* <p>The main method shows example flow of async invocations. The main thread starts multiple
|
||||
* tasks with variable durations and then continues its own work. When the main thread has done it's
|
||||
* job it collects the results of the async tasks. Two of the tasks are handled with callbacks,
|
||||
* meaning the callbacks are executed immediately when the tasks complete.
|
||||
*
|
||||
* <p>Noteworthy difference of thread usage between the async results and callbacks is that the
|
||||
* async results are collected in the main thread but the callbacks are executed within the worker
|
||||
* threads. This should be noted when working with thread pools.
|
||||
*
|
||||
* <p>Java provides its own implementations of async method invocation pattern. FutureTask,
|
||||
* CompletableFuture and ExecutorService are the real world implementations of this pattern. But due
|
||||
* to the nature of parallel programming, the implementations are not trivial. This example does not
|
||||
* take all possible scenarios into account but rather provides a simple version that helps to
|
||||
* understand the pattern.
|
||||
*
|
||||
* @see AsyncResult
|
||||
* @see AsyncCallback
|
||||
* @see AsyncExecutor
|
||||
*
|
||||
* @see java.util.concurrent.FutureTask
|
||||
* @see java.util.concurrent.CompletableFuture
|
||||
* @see java.util.concurrent.ExecutorService
|
||||
@ -61,27 +60,29 @@ public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
* Program entry point.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// construct a new executor that will run async tasks
|
||||
AsyncExecutor executor = new ThreadAsyncExecutor();
|
||||
|
||||
// start few async tasks with varying processing times, two last with callback handlers
|
||||
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||
AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||
AsyncResult<String> asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
|
||||
final AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||
final AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||
final AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||
final AsyncResult<Integer> asyncResult4 =
|
||||
executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||
final AsyncResult<String> asyncResult5 =
|
||||
executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
|
||||
|
||||
// emulate processing in the current thread while async tasks are running in their own threads
|
||||
Thread.sleep(350); // Oh boy I'm working hard here
|
||||
log("Some hard work done");
|
||||
|
||||
// wait for completion of the tasks
|
||||
Integer result1 = executor.endProcess(asyncResult1);
|
||||
String result2 = executor.endProcess(asyncResult2);
|
||||
Long result3 = executor.endProcess(asyncResult3);
|
||||
final Integer result1 = executor.endProcess(asyncResult1);
|
||||
final String result2 = executor.endProcess(asyncResult2);
|
||||
final Long result3 = executor.endProcess(asyncResult3);
|
||||
asyncResult4.await();
|
||||
asyncResult5.await();
|
||||
|
||||
@ -94,10 +95,8 @@ public class App {
|
||||
/**
|
||||
* Creates a callable that lazily evaluates to given value with artificial delay.
|
||||
*
|
||||
* @param value
|
||||
* value to evaluate
|
||||
* @param delayMillis
|
||||
* artificial delay in milliseconds
|
||||
* @param value value to evaluate
|
||||
* @param delayMillis artificial delay in milliseconds
|
||||
* @return new callable for lazy evaluation
|
||||
*/
|
||||
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
||||
@ -111,8 +110,7 @@ public class App {
|
||||
/**
|
||||
* Creates a simple callback that logs the complete status of the async result.
|
||||
*
|
||||
* @param name
|
||||
* callback name
|
||||
* @param name callback name
|
||||
* @return new async callback
|
||||
*/
|
||||
private static <T> AsyncCallback<T> callback(String name) {
|
||||
|
@ -26,11 +26,9 @@ package com.iluwatar.async.method.invocation;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
*
|
||||
* AsyncCallback interface
|
||||
* AsyncCallback interface.
|
||||
*
|
||||
* @param <T>
|
||||
*
|
||||
* @param <T> Type of Result
|
||||
*/
|
||||
public interface AsyncCallback<T> {
|
||||
|
||||
@ -38,7 +36,7 @@ public interface AsyncCallback<T> {
|
||||
* Complete handler which is executed when async task is completed or fails execution.
|
||||
*
|
||||
* @param value the evaluated value from async task, undefined when execution fails
|
||||
* @param ex empty value if execution succeeds, some exception if executions fails
|
||||
* @param ex empty value if execution succeeds, some exception if executions fails
|
||||
*/
|
||||
void onComplete(T value, Optional<Exception> ex);
|
||||
}
|
||||
|
@ -27,9 +27,7 @@ import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
*
|
||||
* AsyncExecutor interface
|
||||
*
|
||||
* AsyncExecutor interface.
|
||||
*/
|
||||
public interface AsyncExecutor {
|
||||
|
||||
@ -45,7 +43,7 @@ public interface AsyncExecutor {
|
||||
* Starts processing of an async task. Returns immediately with async result. Executes callback
|
||||
* when the task is completed.
|
||||
*
|
||||
* @param task task to be executed asynchronously
|
||||
* @param task task to be executed asynchronously
|
||||
* @param callback callback to be executed on task completion
|
||||
* @return async result for the task
|
||||
*/
|
||||
@ -57,7 +55,7 @@ public interface AsyncExecutor {
|
||||
*
|
||||
* @param asyncResult async result of a task
|
||||
* @return evaluated value of the completed task
|
||||
* @throws ExecutionException if execution has failed, containing the root cause
|
||||
* @throws ExecutionException if execution has failed, containing the root cause
|
||||
* @throws InterruptedException if the execution is interrupted
|
||||
*/
|
||||
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
|
||||
|
@ -26,7 +26,8 @@ package com.iluwatar.async.method.invocation;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* AsyncResult interface
|
||||
* AsyncResult interface.
|
||||
*
|
||||
* @param <T> parameter returned when getValue is invoked
|
||||
*/
|
||||
public interface AsyncResult<T> {
|
||||
@ -42,7 +43,7 @@ public interface AsyncResult<T> {
|
||||
* Gets the value of completed async task.
|
||||
*
|
||||
* @return evaluated value or throws ExecutionException if execution has failed
|
||||
* @throws ExecutionException if execution has failed, containing the root cause
|
||||
* @throws ExecutionException if execution has failed, containing the root cause
|
||||
* @throws IllegalStateException if execution is not completed
|
||||
*/
|
||||
T getValue() throws ExecutionException;
|
||||
|
@ -29,13 +29,13 @@ import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
*
|
||||
* Implementation of async executor that creates a new thread for every task.
|
||||
*
|
||||
*/
|
||||
public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
|
||||
/** Index for thread naming */
|
||||
/**
|
||||
* Index for thread naming.
|
||||
*/
|
||||
private final AtomicInteger idx = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
@ -52,12 +52,13 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
} catch (Exception ex) {
|
||||
result.setException(ex);
|
||||
}
|
||||
} , "executor-" + idx.incrementAndGet()).start();
|
||||
}, "executor-" + idx.incrementAndGet()).start();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
|
||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException,
|
||||
InterruptedException {
|
||||
if (!asyncResult.isCompleted()) {
|
||||
asyncResult.await();
|
||||
}
|
||||
@ -65,8 +66,9 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
|
||||
* exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
|
||||
* Simple implementation of async result that allows completing it successfully with a value or
|
||||
* exceptionally with an exception. A really simplified version from its real life cousins
|
||||
* FutureTask and CompletableFuture.
|
||||
*
|
||||
* @see java.util.concurrent.FutureTask
|
||||
* @see java.util.concurrent.CompletableFuture
|
||||
@ -90,11 +92,10 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
|
||||
* completion.
|
||||
* Sets the value from successful execution and executes callback if available. Notifies any
|
||||
* thread waiting for completion.
|
||||
*
|
||||
* @param value
|
||||
* value of the evaluated task
|
||||
* @param value value of the evaluated task
|
||||
*/
|
||||
void setValue(T value) {
|
||||
this.value = value;
|
||||
@ -106,11 +107,10 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
|
||||
* completion.
|
||||
* Sets the exception from failed execution and executes callback if available. Notifies any
|
||||
* thread waiting for completion.
|
||||
*
|
||||
* @param exception
|
||||
* exception of the failed task
|
||||
* @param exception exception of the failed task
|
||||
*/
|
||||
void setException(Exception exception) {
|
||||
this.exception = exception;
|
||||
|
@ -26,9 +26,7 @@ package com.iluwatar.async.method.invocation;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* Application test
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
|
@ -23,30 +23,18 @@
|
||||
|
||||
package com.iluwatar.async.method.invocation;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Matchers;
|
||||
import static java.time.Duration.ofMillis;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static java.time.Duration.ofMillis;
|
||||
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.Mockito.mock;
|
||||
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 org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Matchers;
|
||||
|
||||
/**
|
||||
* Date: 12/6/15 - 10:49 AM
|
||||
@ -82,7 +70,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||
* AsyncCallback)}
|
||||
*/
|
||||
@Test
|
||||
public void testSuccessfulTaskWithCallback() throws Exception {
|
||||
@ -104,7 +93,8 @@ public class ThreadAsyncExecutorTest {
|
||||
verify(task, times(1)).call();
|
||||
|
||||
// ... same for the callback, we expect our object
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||
ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||
|
||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||
@ -117,8 +107,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||
* to execute
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
|
||||
* task takes a while to execute
|
||||
*/
|
||||
@Test
|
||||
public void testLongRunningTaskWithoutCallback() throws Exception {
|
||||
@ -158,8 +148,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
|
||||
* takes a while to execute
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||
* AsyncCallback)} when a task takes a while to execute
|
||||
*/
|
||||
@Test
|
||||
public void testLongRunningTaskWithCallback() throws Exception {
|
||||
@ -191,7 +181,8 @@ public class ThreadAsyncExecutorTest {
|
||||
// Our task should only execute once, but it can take a while ...
|
||||
verify(task, timeout(3000).times(1)).call();
|
||||
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||
ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||
|
||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||
@ -209,8 +200,9 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||
* to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
|
||||
* task takes a while to execute, while waiting on the result using {@link
|
||||
* ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||
*/
|
||||
@Test
|
||||
public void testEndProcess() throws Exception {
|
||||
@ -247,7 +239,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when
|
||||
* the callable is 'null'
|
||||
*/
|
||||
@Test
|
||||
public void testNullTask() throws Exception {
|
||||
@ -273,8 +266,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
|
||||
* callable is 'null', but the asynchronous callback is provided
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||
* AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided
|
||||
*/
|
||||
@Test
|
||||
public void testNullTaskWithCallback() throws Exception {
|
||||
@ -288,7 +281,8 @@ public class ThreadAsyncExecutorTest {
|
||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||
assertTrue(asyncResult.isCompleted());
|
||||
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||
ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
||||
|
||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||
@ -312,8 +306,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
|
||||
* the callable and the asynchronous callback are 'null'
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||
* AsyncCallback)} when both the callable and the asynchronous callback are 'null'
|
||||
*/
|
||||
@Test
|
||||
public void testNullTaskWithNullCallback() throws Exception {
|
||||
|
Reference in New Issue
Block a user