Skip to content

Commit

Permalink
Improve javadoc for the 'delegation' core package.
Browse files Browse the repository at this point in the history
Signed-off-by: Sjoerd Talsma <sjoerdtalsma@users.noreply.github.com>
  • Loading branch information
sjoerdtalsma committed Nov 18, 2024
1 parent 1dd0bc6 commit b394cc9
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package nl.talsmasoftware.context.core.delegation;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
Expand All @@ -25,15 +24,20 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import static java.util.stream.Collectors.toList;

/**
* Abstract baseclass that makes it a little easier to wrap existing {@link ExecutorService} implementations by
* forwarding all methods to a {@link Wrapper#delegate() delegate} executor service.<br>
* The class also provides overridable <code>wrapper</code> methods for all complex input (e.g. {@link Callable}, {@link Runnable})
* and result types (e.g. {@link Future}).
* {@linkplain java.util.concurrent.ExecutorService ExecutorService} delegating all scheduling operations,
* providing a consistent way to {@code wrap} the scheduled tasks and resulting futures.
*
* <p>
* Although this class does implement <em>all</em> required methods of {@link ExecutorService} it is still declared
* as an <em>abstract</em> class.<br>
* This is because it does not provide any value in itself.
* This base class makes it easier to wrap existing {@link ExecutorService} implementations by forwarding all methods
* to a {@link Wrapper#delegate() delegate} executor service.<br>
* It also provides overridable <em>wrap</em> methods for scheduled tasks and resulting futures.
*
* <p>
* Although this class implements <em>all</em> required methods, it is still declared <em>abstract</em>
* because it only provides value if at least one method is overridden.
*
* @author Sjoerd Talsma
*/
Expand All @@ -51,100 +55,257 @@ protected DelegatingExecutorService(ExecutorService delegate) {
super(delegate);
}

protected <T> Callable<T> wrap(Callable<T> source) {
return source;
/**
* Wrap the given task.
*
* <p>
* By default, the given task is returned as-is. Overriding this method provides subclasses
* a consistent way to manipulate the tasks being scheduled.
*
* @param task The task to schedule.
* @param <T> The result of the task.
* @return The wrapped task.
* @see #wrap(Runnable)
*/
protected <T> Callable<T> wrap(Callable<T> task) {
return task;
}

protected Runnable wrap(Runnable source) {
return source;
/**
* Wrap the given task.
*
* <p>
* By default, the given task is returned as-is. Overriding this method provides subclasses
* a consistent way to manipulate the tasks being scheduled.
*
* @param task The task to schedule.
* @return The wrapped task.
* @see #wrap(Callable)
*/
protected Runnable wrap(Runnable task) {
return task;
}

protected <T> Future<T> wrap(Future<T> source) {
return source;
/**
* Wrap the given future.
*
* <p>
* By default, the given future is returned as-is. Overriding this method provides subclasses
* a consistent way to manipulate a task's future result before returning it.
*
* @param future The future to be returned.
* @param <T> The result of the future.
* @return The wrapped future.
*/
protected <T> Future<T> wrap(Future<T> future) {
return future;
}

/**
* Default way of mapping a {@link Collection} of {@link Callable} objects:
* Default way of wrapping a {@link Collection} of {@link Callable} objects:
* Create a new collection and add each {@link #wrap(Callable) individually wrapped} object into it.
*
* @param tasks The tasks to be mapped.
* @param tasks The tasks to be wrapped.
* @param <T> The common result type for the collection of tasks.
* @return A collection with each individual task wrapped.
* @see #wrap(Callable)
*/
protected <T> Collection<? extends Callable<T>> wrapTasks(Collection<? extends Callable<T>> tasks) {
if (tasks == null) return null;
final List<Callable<T>> wrappedTasks = new ArrayList<>(tasks.size());
for (Callable<T> task : tasks) wrappedTasks.add(wrap(task));
return wrappedTasks;
return tasks == null ? null : tasks.stream().map(this::wrap).collect(toList());
}

/**
* Default way of mapping a {@link Collection} of {@link Future} objects:
* Default way of wrapping a {@link Collection} of {@link Future} objects:
* Create a new list and add each {@link #wrap(Future) individually wrapped} object into it.
*
* @param futures The futures to be mapped.
* @param futures The futures to be wrapped.
* @param <T> The common result type for the collection of futures.
* @return A list with each individual future wrapped.
* @see #wrap(Future)
*/
protected <T> List<Future<T>> wrapFutures(Collection<? extends Future<T>> futures) {
if (futures == null) return null;
final List<Future<T>> wrappedFutures = new ArrayList<>(futures.size());
for (Future<T> future : futures) wrappedFutures.add(wrap(future));
return wrappedFutures;
return futures == null ? null : futures.stream().map(this::wrap).collect(toList());
}

/**
* Shuts down the executor service by shutting down the delegate.
*/
public void shutdown() {
delegate().shutdown();
}

/**
* Shuts down the executor service now by shutting down the delegate.
*
* @return The tasks the delegate returned.
*/
public List<Runnable> shutdownNow() {
return delegate().shutdownNow();
}

/**
* Returns whether the delegate is shut down.
*
* @return Whether the delegate is shut down.
*/
public boolean isShutdown() {
return delegate().isShutdown();
}

/**
* Returns whether the delegate is terminated.
*
* @return Whether the delegate is terminated.
*/
public boolean isTerminated() {
return delegate().isTerminated();
}

/**
* Await termination of the delegate.
*
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return {@code true} if the delegate terminated, {@code false} if a timeout occurred.
* @throws InterruptedException if interrupted while waiting.
*/
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate().awaitTermination(timeout, unit);
}

/**
* Submits a task to the delegate.
*
* <p>
* This method allows subclasses to <em>wrap</em> both the {@linkplain #wrap(Callable) task}
* and the {@linkplain #wrap(Future) result}.
*
* @param task the task to submit.
* @param <T> the type of the task's result.
* @return a Future representing pending completion of the task.
* @see #wrap(Callable)
* @see #wrap(Future)
*/
public <T> Future<T> submit(Callable<T> task) {
return wrap(delegate().submit(wrap(task)));
}

/**
* Submits a task to the delegate with a fixed result.
*
* <p>
* This method allows subclasses to <em>wrap</em> both the {@linkplain #wrap(Runnable) task}
* and the {@linkplain #wrap(Future) result}.
*
* @param task the task to submit.
* @param result the result to return.
* @param <T> the type of the result.
* @return a Future representing pending completion of the task.
* @see #wrap(Runnable)
* @see #wrap(Future)
*/
public <T> Future<T> submit(Runnable task, T result) {
return wrap(delegate().submit(wrap(task), result));
}

/**
* Submits a task to the delegate.
*
* <p>
* This method allows subclasses to <em>wrap</em> both the {@linkplain #wrap(Runnable) task}
* and the {@linkplain #wrap(Future) result}.
*
* @param task the task to submit.
* @return a Future representing pending completion of the task.
* @see #wrap(Runnable)
* @see #wrap(Future)
*/
public Future<?> submit(Runnable task) {
return wrap(delegate().submit(wrap(task)));
}

/**
* Submits several tasks to the delegate.
*
* <p>
* This method allows subclasses to <em>wrap</em> both the {@linkplain #wrap(Callable) task}
* and the {@linkplain #wrap(Future) result}.
*
* @param tasks the tasks to submit.
* @param <T> the type of the values returned from the tasks.
* @return a Future representing pending completion of the task.
* @see #wrap(Callable)
* @see #wrap(Future)
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {
final List<Future<T>> futures = delegate().invokeAll(wrapTasks(tasks));
return wrapFutures(futures);
}

/**
* Invokes several tasks to the delegate.
*
* <p>
* This method allows subclasses to <em>wrap</em> both the {@linkplain #wrap(Runnable) task}
* and the {@linkplain #wrap(Future) result}.
*
* @param tasks the tasks to invoke.
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return a list of Futures representing pending completions of the tasks.
* @see #wrap(Runnable)
* @see #wrap(Future)
*/
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
final List<Future<T>> futures = delegate().invokeAll(wrapTasks(tasks), timeout, unit);
return wrapFutures(futures);
}

/**
* Executes the given tasks on the delegate, returning the result of one that has completed successfully
* (i. e., without throwing an exception), if any do.
*
* <p>
* This method allows subclasses to {@linkplain #wrap(Callable) wrap} the tasks.
*
* @param tasks the tasks to execute.
* @return the result returned by one of the tasks.
* @see #wrap(Callable)
*/
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
return delegate().invokeAny(wrapTasks(tasks));
}

/**
* Executes the given tasks on the delegate, returning the result of one that has completed successfully
* (i. e., without throwing an exception), if any do before the timeout elapses.
*
* <p>
* This method allows subclasses to {@linkplain #wrap(Callable) wrap} the tasks.
*
* @param tasks the tasks to execute.
* @param timeout the maximum time to wait
* @param unit the time unit of the timeout argument
* @return the result returned by one of the tasks.
* @throws InterruptedException if interrupted while waiting.
* @throws NullPointerException if tasks, or unit, or any element task subject to execution is null.
* @throws TimeoutException if the given timeout elapses before any task successfully completes.
* @throws ExecutionException if no task successfully completes.
* @see #wrap(Callable)
*/
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate().invokeAny(wrapTasks(tasks), timeout, unit);
}

/**
* Executes the given command on the delegate.
*
* <p>
* This method allows subclasses to {@linkplain #wrap(Runnable) wrap} the command.
*
* @param command the command to execute.
* @see #wrap(Runnable)
*/
public void execute(Runnable command) {
delegate().execute(wrap(command));
}
Expand Down
Loading

0 comments on commit b394cc9

Please sign in to comment.