io.foldright.cffu.DelayExecutionHelpers Maven / Gradle / Ivy
package io.foldright.cffu;
////////////////////////////////////////////////////////////////////////////////
//# delay execution helper classes
//
// below code is copied from CompletableFuture with small adoption
////////////////////////////////////////////////////////////////////////////////
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.concurrent.*;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import static java.util.Objects.requireNonNull;
/**
* Singleton delay scheduler, used only for starting and cancelling tasks
*
* code is copied from {@link CompletableFuture.Delayer} with small adoption.
*/
@SuppressWarnings("JavadocReference")
final class Delayer {
/**
* @return a Future that can be used to cancel the delayed task
* @see FutureCanceller
* @see DelayedExecutor#execute(Runnable)
*/
static ScheduledFuture> delay(Runnable command, long delay, TimeUnit unit) {
return DelayerHolder.delayer.schedule(command, delay, unit);
}
/**
* @return a Future can be used to cancel the delayed task(timeout CF)
* @see FutureCanceller
*/
static ScheduledFuture> delayToTimeoutCf(CompletableFuture> cf, long delay, TimeUnit unit) {
return delay(new CfTimeout(cf), delay, unit);
}
/**
* @return a Future can be used to cancel the delayed task(complete CF)
* @see FutureCanceller
*/
static ScheduledFuture> delayToCompleteCf(
CompletableFuture super T> cf, @Nullable T value, long delay, TimeUnit unit) {
return delay(new CfCompleter<>(cf, value), delay, unit);
}
/**
* Checks whether execution is at the thread of CompletableFuture/Cffu delayer.
*
* The constant {@code "CompletableFutureDelayScheduler"} is defined
* at {@link CompletableFuture.Delayer.DaemonThreadFactory}.
*/
@SuppressWarnings("JavadocReference")
static boolean atCfDelayerThread() {
final String name = Thread.currentThread().getName();
return "CompletableFutureDelayScheduler".equals(name) || THREAD_NAME_OF_CFFU_DELAY_SCHEDULER.equals(name);
}
private static final String THREAD_NAME_OF_CFFU_DELAY_SCHEDULER = "CffuBuiltinDelayScheduler";
/**
* Holds {@link #delayer} scheduler as field of static inner class for lazy loading(init only when needed).
*
* The lazy loading is need because {@link #atCfDelayerThread()} method of
* class {@link Delayer} is used on {@code Java 9+}.
*/
private static class DelayerHolder {
static final ScheduledThreadPoolExecutor delayer;
static {
delayer = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory());
delayer.setRemoveOnCancelPolicy(true);
}
}
private static final class DaemonThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
t.setName(THREAD_NAME_OF_CFFU_DELAY_SCHEDULER);
return t;
}
}
private Delayer() {
}
}
/**
* An executor wrapper with delayed execution.
*
* code is copied from {@link CompletableFuture.DelayedExecutor} with small adoption.
*/
@SuppressWarnings("JavadocReference")
final class DelayedExecutor implements Executor {
private final long delay;
private final TimeUnit unit;
private final Executor executor;
DelayedExecutor(long delay, TimeUnit unit, Executor executor) {
this.delay = delay;
this.unit = unit;
this.executor = executor;
}
@Override
public void execute(Runnable r) {
Delayer.delay(new TaskSubmitter(executor, requireNonNull(r, "runnable is null")), delay, unit);
}
}
////////////////////////////////////////////////////////////////////////////////
// Little classified lambdas to better support monitoring
////////////////////////////////////////////////////////////////////////////////
/**
* Action to submit task(Runnable) to executor.
*
* code is copied from {@link CompletableFuture.TaskSubmitter} with small adoption.
*/
@SuppressWarnings("JavadocReference")
final class TaskSubmitter implements Runnable {
private final Executor executor;
private final Runnable action;
TaskSubmitter(Executor executor, Runnable action) {
this.executor = executor;
this.action = action;
}
@Override
public void run() {
executor.execute(action);
}
}
/**
* Action to cf.completeExceptionally with TimeoutException.
*
* code is copied from {@link CompletableFuture.Timeout} with small adoption.
*/
@SuppressWarnings("JavadocReference")
final class CfTimeout implements Runnable {
private final CompletableFuture> cf;
CfTimeout(CompletableFuture> cf) {
this.cf = cf;
}
@Override
public void run() {
if (!cf.isDone()) cf.completeExceptionally(new TimeoutException());
}
}
/**
* Action to complete cf.
*
* code is copied from {@link CompletableFuture.DelayedCompleter} with small adoption.
*/
@SuppressWarnings("JavadocReference")
final class CfCompleter implements Runnable {
private final CompletableFuture super T> cf;
@Nullable
private final T value;
CfCompleter(CompletableFuture super T> cf, @Nullable T value) {
this.cf = cf;
this.value = value;
}
@Override
public void run() {
cf.complete(value);
}
}
/**
* Action to cancel unneeded scheduled task by Future (for example timeouts).
*
* code is copied from {@link CompletableFuture.Canceller} with small adoption.
*
* @see Delayer#delay(Runnable, long, TimeUnit)
* @see Delayer#delayToTimeoutCf(CompletableFuture, long, TimeUnit)
* @see Delayer#delayToCompleteCf(CompletableFuture, Object, long, TimeUnit)
*/
@SuppressWarnings("JavadocReference")
final class FutureCanceller implements BiConsumer