/*
* Copyright (C) 2011 The Guava Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.common.util.concurrent;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.throwIfUnchecked;
import com.google.common.annotations.GwtIncompatible;
import com.google.common.collect.ImmutableList;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
An abstract ExecutorService
that allows subclasses to
wrap tasks before they are submitted to the underlying executor. Note that task wrapping may occur even if the task is never executed.
For delegation without task-wrapping, see ForwardingExecutorService
.
Author: Chris Nokleberg
/**
* An abstract {@code ExecutorService} that allows subclasses to {@linkplain #wrapTask(Callable)
* wrap} tasks before they are submitted to the underlying executor.
*
* <p>Note that task wrapping may occur even if the task is never executed.
*
* <p>For delegation without task-wrapping, see {@link ForwardingExecutorService}.
*
* @author Chris Nokleberg
*/
@CanIgnoreReturnValue // TODO(cpovirk): Consider being more strict.
@GwtIncompatible
abstract class WrappingExecutorService implements ExecutorService {
private final ExecutorService delegate;
protected WrappingExecutorService(ExecutorService delegate) {
this.delegate = checkNotNull(delegate);
}
Wraps a Callable
for submission to the underlying executor. This method is also applied to any Runnable
passed to the default implementation of wrapTask(Runnable)
. /**
* Wraps a {@code Callable} for submission to the underlying executor. This method is also applied
* to any {@code Runnable} passed to the default implementation of {@link #wrapTask(Runnable)}.
*/
protected abstract <T> Callable<T> wrapTask(Callable<T> callable);
Wraps a Runnable
for submission to the underlying executor. The default implementation delegates to wrapTask(Callable<Object>)
. /**
* Wraps a {@code Runnable} for submission to the underlying executor. The default implementation
* delegates to {@link #wrapTask(Callable)}.
*/
protected Runnable wrapTask(Runnable command) {
final Callable<Object> wrapped = wrapTask(Executors.callable(command, null));
return new Runnable() {
@Override
public void run() {
try {
wrapped.call();
} catch (Exception e) {
throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
};
}
Wraps a collection of tasks.
Throws: - NullPointerException – if any element of
tasks
is null
/**
* Wraps a collection of tasks.
*
* @throws NullPointerException if any element of {@code tasks} is null
*/
private <T> ImmutableList<Callable<T>> wrapTasks(Collection<? extends Callable<T>> tasks) {
ImmutableList.Builder<Callable<T>> builder = ImmutableList.builder();
for (Callable<T> task : tasks) {
builder.add(wrapTask(task));
}
return builder.build();
}
// These methods wrap before delegating.
@Override
public final void execute(Runnable command) {
delegate.execute(wrapTask(command));
}
@Override
public final <T> Future<T> submit(Callable<T> task) {
return delegate.submit(wrapTask(checkNotNull(task)));
}
@Override
public final Future<?> submit(Runnable task) {
return delegate.submit(wrapTask(task));
}
@Override
public final <T> Future<T> submit(Runnable task, T result) {
return delegate.submit(wrapTask(task), result);
}
@Override
public final <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return delegate.invokeAll(wrapTasks(tasks));
}
@Override
public final <T> List<Future<T>> invokeAll(
Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException {
return delegate.invokeAll(wrapTasks(tasks), timeout, unit);
}
@Override
public final <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
return delegate.invokeAny(wrapTasks(tasks));
}
@Override
public final <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return delegate.invokeAny(wrapTasks(tasks), timeout, unit);
}
// The remaining methods just delegate.
@Override
public final void shutdown() {
delegate.shutdown();
}
@Override
public final List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}
@Override
public final boolean isShutdown() {
return delegate.isShutdown();
}
@Override
public final boolean isTerminated() {
return delegate.isTerminated();
}
@Override
public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}
}