All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jodah.failsafe.FailsafeFuture Maven / Gradle / Ivy

package net.jodah.failsafe;

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 net.jodah.failsafe.AsyncListeners.AsyncCtxResultListener;
import net.jodah.failsafe.AsyncListeners.AsyncResultListener;
import net.jodah.failsafe.event.ContextualResultListener;
import net.jodah.failsafe.event.ContextualSuccessListener;
import net.jodah.failsafe.event.ResultListener;
import net.jodah.failsafe.event.SuccessListener;
import net.jodah.failsafe.internal.util.Assert;
import net.jodah.failsafe.internal.util.ReentrantCircuit;
import net.jodah.failsafe.util.concurrent.Scheduler;

/**
 * The future result of an asynchronous execution.
 * 
 * @author Jonathan Halterman
 * @param  result type
 */
public class FailsafeFuture implements Future {
  private final ReentrantCircuit circuit = new ReentrantCircuit();
  private final Scheduler scheduler;
  private ExecutionContext context;
  private volatile Future delegate;
  private volatile boolean done;
  private volatile boolean cancelled;
  private volatile boolean success;
  private volatile T result;
  private volatile Throwable failure;

  // Listeners
  private final Listeners listeners;
  private volatile AsyncResultListener asyncCompleteListener;
  private volatile AsyncCtxResultListener asyncCtxCompleteListener;
  private volatile AsyncResultListener asyncFailureListener;
  private volatile AsyncCtxResultListener asyncCtxFailureListener;
  private volatile AsyncResultListener asyncSuccessListener;
  private volatile AsyncCtxResultListener asyncCtxSuccessListener;

  FailsafeFuture(Scheduler scheduler, Listeners listeners) {
    this.scheduler = scheduler;
    this.listeners = listeners == null ? new Listeners() : listeners;
    circuit.open();
  }

  static  FailsafeFuture of(final java.util.concurrent.CompletableFuture future, Scheduler scheduler,
      Listeners listeners) {
    Assert.notNull(future, "future");
    Assert.notNull(scheduler, "scheduler");
    return new FailsafeFuture(scheduler, listeners).onComplete(new ResultListener() {
      @Override
      public void onResult(T result, Throwable failure) {
        if (failure == null)
          future.complete(result);
        else
          future.completeExceptionally(failure);
      }
    });
  }

  @Override
  public synchronized boolean cancel(boolean mayInterruptIfRunning) {
    boolean result = delegate.cancel(mayInterruptIfRunning);
    cancelled = true;
    circuit.close();
    return result;
  }

  @Override
  public T get() throws InterruptedException, ExecutionException {
    circuit.await();
    if (failure != null)
      throw new ExecutionException(failure);
    return result;
  }

  @Override
  public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    if (!circuit.await(timeout, Assert.notNull(unit, "unit")))
      throw new TimeoutException();
    if (failure != null)
      throw new ExecutionException(failure);
    return result;
  }

  @Override
  public boolean isCancelled() {
    return cancelled;
  }

  @Override
  public boolean isDone() {
    return done;
  }

  /**
   * Registers the {@code listener} to be called when an execution is completed.
   */
  public synchronized FailsafeFuture onComplete(ContextualResultListener listener) {
    listeners.onComplete(listener);
    if (done)
      listeners.handleComplete(result, failure, context);
    return this;
  }

  /**
   * Registers the {@code listener} to be called when an execution is completed.
   */
  public synchronized FailsafeFuture onComplete(ResultListener listener) {
    listeners.onComplete(listener);
    if (done)
      listeners.handleComplete(result, failure);
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when an execution is completed.
   */
  public synchronized FailsafeFuture onCompleteAsync(
      ContextualResultListener listener) {
    call(done, asyncCtxCompleteListener = new AsyncCtxResultListener(listener));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when an execution is completed.
   */
  public synchronized FailsafeFuture onCompleteAsync(
      ContextualResultListener listener, ExecutorService executor) {
    call(done, asyncCtxCompleteListener = new AsyncCtxResultListener(listener, executor));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when an execution is completed.
   */
  public synchronized FailsafeFuture onCompleteAsync(ResultListener listener) {
    call(done, asyncCompleteListener = new AsyncResultListener(listener));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when an execution is completed.
   */
  public synchronized FailsafeFuture onCompleteAsync(ResultListener listener,
      ExecutorService executor) {
    call(done, asyncCompleteListener = new AsyncResultListener(listener, executor));
    return this;
  }

  /**
   * Registers the {@code listener} to be called when the retry policy is exceeded and the result is a failure.
   */
  public synchronized FailsafeFuture onFailure(ContextualResultListener listener) {
    listeners.onFailure(listener);
    if (done && !success)
      listeners.handleFailure(result, failure, context);
    return this;
  }

  /**
   * Registers the {@code listener} to be called when the retry policy is exceeded and the result is a failure.
   */
  public synchronized FailsafeFuture onFailure(ResultListener listener) {
    listeners.onFailure(listener);
    if (done && !success)
      listeners.handleFailure(result, failure);
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when the retry policy is exceeded and the result is a
   * failure.
   */
  public synchronized FailsafeFuture onFailureAsync(
      ContextualResultListener listener) {
    call(done && !success, asyncCtxFailureListener = new AsyncCtxResultListener(listener));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when the retry policy is exceeded and the result is a
   * failure.
   */
  public synchronized FailsafeFuture onFailureAsync(
      ContextualResultListener listener, ExecutorService executor) {
    call(done && !success, asyncCtxFailureListener = new AsyncCtxResultListener(listener, executor));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when the retry policy is exceeded and the result is a
   * failure.
   */
  public synchronized FailsafeFuture onFailureAsync(ResultListener listener) {
    call(done && !success, asyncFailureListener = new AsyncResultListener(listener));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously when the retry policy is exceeded and the result is a
   * failure.
   */
  public synchronized FailsafeFuture onFailureAsync(ResultListener listener,
      ExecutorService executor) {
    call(done && !success, asyncFailureListener = new AsyncResultListener(listener, executor));
    return this;
  }

  /**
   * Registers the {@code listener} to be called after a successful execution.
   */
  public synchronized FailsafeFuture onSuccess(ContextualSuccessListener listener) {
    listeners.onSuccess(listener);
    if (done && success)
      listeners.handleSuccess(result, context);
    return this;
  }

  /**
   * Registers the {@code listener} to be called after a successful execution.
   */
  public synchronized FailsafeFuture onSuccess(SuccessListener listener) {
    listeners.onSuccess(listener);
    if (done && success)
      listeners.handleSuccess(result);
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously after a successful execution.
   */
  public synchronized FailsafeFuture onSuccessAsync(ContextualSuccessListener listener) {
    call(done && success,
        asyncCtxSuccessListener = new AsyncCtxResultListener(Listeners.resultListenerOf(listener)));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously after a successful execution.
   */
  public synchronized FailsafeFuture onSuccessAsync(ContextualSuccessListener listener,
      ExecutorService executor) {
    call(done && success,
        asyncCtxSuccessListener = new AsyncCtxResultListener(Listeners.resultListenerOf(listener), executor));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously after a successful execution.
   */
  public synchronized FailsafeFuture onSuccessAsync(SuccessListener listener) {
    call(done && success, asyncSuccessListener = new AsyncResultListener(Listeners.resultListenerOf(listener)));
    return this;
  }

  /**
   * Registers the {@code listener} to be called asynchronously after a successful execution.
   */
  public synchronized FailsafeFuture onSuccessAsync(SuccessListener listener, ExecutorService executor) {
    call(done && success,
        asyncSuccessListener = new AsyncResultListener(Listeners.resultListenerOf(listener), executor));
    return this;
  }

  synchronized void complete(T result, Throwable failure, boolean success) {
    this.result = result;
    this.failure = failure;
    this.success = success;
    done = true;
    if (success)
      AsyncListeners.call(asyncSuccessListener, asyncCtxSuccessListener, result, failure, context, scheduler);
    else
      AsyncListeners.call(asyncFailureListener, asyncCtxFailureListener, result, failure, context, scheduler);
    AsyncListeners.call(asyncCompleteListener, asyncCtxCompleteListener, result, failure, context, scheduler);
    listeners.complete(result, failure, context, success);
    circuit.close();
  }

  void inject(ExecutionContext context) {
    this.context = context;
  }

  void setFuture(Future delegate) {
    this.delegate = delegate;
  }

  private void call(boolean condition, AsyncCtxResultListener listener) {
    if (condition)
      AsyncListeners.call(listener, result, failure, context, scheduler);
  }

  private void call(boolean condition, AsyncResultListener listener) {
    if (condition)
      AsyncListeners.call(listener, result, failure, context, scheduler);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy