ProtocolLib/src/main/java/com/comphenix/protocol/executors/AbstractListeningService.java

289 lines
8.6 KiB
Java

package com.comphenix.protocol.executors;
/*
* This file is a modified version of
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java?revision=1.35
* which contained the following notice:
*
* Written by Doug Lea with assistance from members of JCP JSR-166 Expert Group and released to the
* public domain, as explained at http://creativecommons.org/publicdomain/zero/1.0/
*
* Rationale for copying:
* Guava targets JDK5, whose AbstractExecutorService class lacks the newTaskFor protected
* customization methods needed by MoreExecutors.listeningDecorator. This class is a copy of
* AbstractExecutorService from the JSR166 CVS repository. It contains the desired methods.
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.RunnableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListenableFutureTask;
import com.google.common.util.concurrent.ListeningExecutorService;
/**
* Provides default implementations of {@link ListeningExecutorService}
* execution methods. This class implements the <tt>submit</tt>,
* <tt>invokeAny</tt> and <tt>invokeAll</tt> methods using a
* {@link ListenableFutureTask} returned by <tt>newTaskFor</tt>. For example,
* the implementation of <tt>submit(Runnable)</tt> creates an associated
* <tt>ListenableFutureTask</tt> that is executed and returned.
*
* @author Doug Lea
*/
abstract class AbstractListeningService implements ListeningExecutorService {
/**
* Represents a runnable abstract listenable future task.
*
* @author Kristian
* @param <T>
*/
public static abstract class RunnableAbstractFuture<T>
extends AbstractFuture<T> implements RunnableFuture<T> {
}
/**
* Returns a <tt>ListenableFutureTask</tt> for the given runnable and
* default value.
*
* @param runnable - the runnable task being wrapped
* @param value - the default value for the returned future
* @return a <tt>ListenableFutureTask</tt> which when run will run the
* underlying runnable and which, as a <tt>Future</tt>, will yield
* the given value as its result and provide for cancellation of the
* underlying task.
*/
protected abstract <T> RunnableAbstractFuture<T> newTaskFor(Runnable runnable, T value);
/**
* Returns a <tt>ListenableFutureTask</tt> for the given callable task.
*
* @param callable - the callable task being wrapped
* @return a <tt>ListenableFutureTask</tt> which when run will call the
* underlying callable and which, as a <tt>Future</tt>, will yield
* the callable's result as its result and provide for cancellation
* of the underlying task.
*/
protected abstract <T> RunnableAbstractFuture<T> newTaskFor(Callable<T> callable);
@Override
public ListenableFuture<?> submit(Runnable task) {
if (task == null) {
throw new NullPointerException();
}
RunnableAbstractFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
@Override
public <T> ListenableFuture<T> submit(Runnable task, T result) {
if (task == null) {
throw new NullPointerException();
}
RunnableAbstractFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
@Override
public <T> ListenableFuture<T> submit(Callable<T> task) {
if (task == null) {
throw new NullPointerException();
}
RunnableAbstractFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/**
* The main mechanics of invokeAny.
*/
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null) {
throw new NullPointerException();
}
int ntasks = tasks.size();
if (ntasks == 0) {
throw new IllegalArgumentException();
}
List<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
long lastTime = timed ? System.nanoTime() : 0;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
} else if (active == 0) {
break;
} else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null) {
throw new TimeoutException();
}
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
} else {
f = ecs.take();
}
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null) {
ee = new ExecutionException(null);
}
throw ee;
} finally {
for (Future<T> f : futures)
f.cancel(true);
}
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,
ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
// assert false;
return null;
}
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null) {
throw new NullPointerException();
}
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableAbstractFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (Future<T> f : futures) {
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException | ExecutionException ignore) { }
}
}
done = true;
return futures;
} finally {
if (!done) {
for (Future<T> f : futures)
f.cancel(true);
}
}
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException {
if (tasks == null || unit == null) {
throw new NullPointerException();
}
long nanos = unit.toNanos(timeout);
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
long lastTime = System.nanoTime();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (Future<T> future : futures) {
execute((Runnable) future);
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
if (nanos <= 0) {
return futures;
}
}
for (Future<T> f : futures) {
if (!f.isDone()) {
if (nanos <= 0) {
return futures;
}
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException | ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
}
done = true;
return futures;
} finally {
if (!done) {
for (Future<T> f : futures)
f.cancel(true);
}
}
}
}