package org.dcache.util;
import com.google.common.util.concurrent.ForwardingExecutorService;
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.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import dmg.cells.nucleus.CDC;
import static java.util.stream.Collectors.toList;
/**
* Decorates a ExecutorService and makes tasks CDC aware.
*
* The CDC of a task submitted to the ExecutorService will be initialized to
* the CDC of the thread that submitted the task.
*/
public class CDCExecutorServiceDecorator<E extends ExecutorService> extends ForwardingExecutorService
{
private final E _delegate;
public CDCExecutorServiceDecorator(E delegate)
{
this._delegate = delegate;
}
@Override
public E delegate()
{
return _delegate;
}
@Override
public <T> Future<T> submit(Callable<T> task)
{
return _delegate.submit(wrap(task));
}
@Override
public Future<?> submit(Runnable task)
{
return _delegate.submit(wrap(task));
}
@Override
public <T> Future<T> submit(Runnable task, T result)
{
return _delegate.submit(wrap(task), result);
}
@Override
public <T> List<Future<T>> invokeAll(
Collection<? extends Callable<T>> tasks) throws InterruptedException
{
return _delegate.invokeAll(wrap(tasks));
}
@Override
public <T> List<Future<T>> invokeAll(
Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException
{
return _delegate.invokeAll(wrap(tasks), timeout, unit);
}
@Override
public <T> T invokeAny(
Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException
{
return _delegate.invokeAny(wrap(tasks));
}
@Override
public <T> T invokeAny(
Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
{
return _delegate.invokeAny(wrap(tasks), timeout, unit);
}
@Override
public void execute(Runnable command)
{
_delegate.execute(wrap(command));
}
@Override
public List<Runnable> shutdownNow()
{
return unwrap(super.shutdownNow());
}
protected Runnable wrap(final Runnable task)
{
return new WrappedRunnable(new CDC(), task);
}
protected <T> Callable<T> wrap(final Callable<T> task)
{
final CDC cdc = new CDC();
return () -> {
try (CDC ignored = cdc.restore()) {
return task.call();
}
};
}
protected <T> Collection<? extends Callable<T>> wrap(Collection<? extends Callable<T>> tasks)
{
return tasks.stream().map(this::wrap).collect(toList());
}
private Runnable unwrap(Runnable runnable)
{
return (runnable instanceof WrappedRunnable) ? ((WrappedRunnable) runnable).getInner() : runnable;
}
private List<Runnable> unwrap(List<Runnable> runnables)
{
return runnables.stream().map(this::unwrap).collect(toList());
}
private static class WrappedRunnable implements Runnable
{
private final CDC cdc;
private final Runnable task;
public WrappedRunnable(CDC cdc, Runnable task)
{
this.cdc = cdc;
this.task = task;
}
public Runnable getInner()
{
return task;
}
@Override
public void run()
{
try (CDC ignored = cdc.restore()) {
task.run();
}
}
}
}