ReusableCircuitBreaker.java

package net.secodo.jcircuitbreaker.breaker.impl;

import java.util.concurrent.Callable;

import net.secodo.jcircuitbreaker.breaker.builder.impl.ReusableCircuitBreakerBuilder;
import net.secodo.jcircuitbreaker.breakhandler.BreakHandler;
import net.secodo.jcircuitbreaker.breakhandler.exception.BreakHandlerException;
import net.secodo.jcircuitbreaker.breakstrategy.BreakStrategy;
import net.secodo.jcircuitbreaker.exception.CircuitBreakerException;
import net.secodo.jcircuitbreaker.exception.TaskExecutionException;
import net.secodo.jcircuitbreaker.task.Task;


/**
 * An abstract implementation of {@link net.secodo.jcircuitbreaker.breaker.CircuitBreaker} which stores its
 * {@link BreakStrategy} and {@link BreakHandler} as fields, so that there is no need to pass them each time.  This has 
 * following consequence: both <i>break strategy</i> and <i>break handler</i> will be shared between different 
 * executions of <i>target-method</i>, so they should be "stateless". If this is not guaranteed 
 * (for each Task (runtime method) different instances of {@link BreakHandler}) should be created) 
 * than {@link net.secodo.jcircuitbreaker.breakhandler.BreakHandlerFactory} should be used.
 *
 * @param <R> the return type of the called method
 */
public class ReusableCircuitBreaker<R> extends AbstractCircuitBreaker<R> {
  private final BreakStrategy<R> breakStrategy;
  private final BreakHandler<R> breakHandler;

  /**
   * Constructs new breaker with given break strategy and break handler. Break strategy and break handler will be
   * applied to each execution of the circuit breaker.
   *
   * @param breakStrategy a break strategy to apply to each Task executed by this circuit breaker
   * @param breakHandler  a break handler to apply fallback value (or fallback behaviour) when execution of task is
   *                      prohibited by break strategy
   */
  public ReusableCircuitBreaker(BreakStrategy<R> breakStrategy, BreakHandler<R> breakHandler) {
    super();
    this.breakStrategy = breakStrategy;
    this.breakHandler = breakHandler;
  }

  /**
   * Builder for {@link ReusableCircuitBreaker}. Allows to create {@link ReusableCircuitBreaker} in a
   * fluent-interface way.
   *
   * @return an instance of builder which is used to construct {@link ReusableCircuitBreaker}
   */
  @SuppressWarnings("rawtypes") // for convenience in usage
  public static ReusableCircuitBreakerBuilder builder() {
    return new ReusableCircuitBreakerBuilder();
  }

  /**
   * Builder for {@link ReusableCircuitBreaker}. Allows to create {@link ReusableCircuitBreaker} in a
   * fluent-interface way. This method is parameterized and requires return type of java <i>target-method</i> to be
   * defined while calling this method.
   *
   * @param <R> the return type or <i>target-method</i> to be executed by circuit breaker
   * @return an instance of builder which is used to construct {@link ReusableCircuitBreaker}
   */
  public static <R> ReusableCircuitBreakerBuilder<R> builderP() {
    return new ReusableCircuitBreakerBuilder<>();
  }


  /**
   * Executes given Task within this breaker using {@link BreakStrategy} and {@link BreakHandler} given as the params.
   *
   * @param task the real-method to be executed
   * @return the output value of the real method
   * @see net.secodo.jcircuitbreaker.breaker.CircuitBreaker#execute(Task, BreakStrategy, BreakHandler)
   *
   * @throws TaskExecutionException if execution of given Task results in exception
   */
  public R execute(Task<R> task) throws TaskExecutionException, CircuitBreakerException, BreakHandlerException {
    return super.execute(task, breakStrategy, breakHandler);
  }

  /**
   * Executes given Task within this breaker using {@link BreakStrategy} and {@link BreakHandler} given as the params
   * with custom data passed as userData param.
   *
   * @param task the real-method to be executed
   * @param userData custom object with data which will be made available to break strategy and break handler via
   *                 execution context
   * @param <U> the type of user data object which will be made available to break strategy and break handler via
   *           execution context
   * @return the output value of the real method
   *
   * @see net.secodo.jcircuitbreaker.breaker.CircuitBreaker#execute(Task, BreakStrategy, BreakHandler, Object)
   *
   * @throws TaskExecutionException if execution of given Task results in exception
   */
  public <U> R execute(Task<R> task, U userData) throws TaskExecutionException, CircuitBreakerException,
                                                            BreakHandlerException {
    return super.execute(task, breakStrategy, breakHandler, userData);
  }
}