BreakHandlerFactory.java
package net.secodo.jcircuitbreaker.breakhandler;
import static java.util.Objects.isNull;
import java.util.concurrent.Callable;
import net.secodo.jcircuitbreaker.breaker.ContextAwareCircuitBreaker;
import net.secodo.jcircuitbreaker.breaker.execution.ExecutionContext;
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;
/**
* This is generic factory method interface. Each implementation should implement
* {@link #makeHandler(Task, ExecutionContext)} method which returns instance of a {@link BreakHandler}. The
* returned instance should be shareable between different executions of the target-method (between execution of
* different tasks). This means that the implementation should conform to one of following statements:
* <ul>
* <li>should be stateless - the returned handler should not allow modification of its internal state. This prevents
* possible {@link java.util.ConcurrentModificationException} when accessed by different threads</li>
* <li>should return new instance (but the instances may not share a common state via static fields etc. which may
* result in {@link java.util.ConcurrentModificationException} when accessed by different threads)</li>
* <li>may share state (or be the same instance) as long as any possible concurrent modifications are protected by
* synchronization/locking mechanism, so that multiple threads can access the instance on the same time</li>
* </ul>
*
* @param <R> the return type of onBreak method of the created {@link BreakHandler}. This must be the same return
* type as the of of executed Task
*/
public interface BreakHandlerFactory<R> extends BreakHandler<R> {
@Override
default R onBreak(ContextAwareCircuitBreaker<R> circuitBreaker, Task<R> task, BreakStrategy<R> breakStrategy,
ExecutionContext<R> executionContext) throws TaskExecutionException, CircuitBreakerException,
BreakHandlerException {
BreakHandler<R> handler = makeHandler(task, executionContext);
if (isNull(handler)) {
throw new BreakHandlerException("makeHandler() method returned handler which is null");
}
return handler.onBreak(circuitBreaker, task, breakStrategy, executionContext);
}
/**
* Returns an instance of {@link BreakHandler} which should be used to handle the <i>break</i>.
*
* @param task the task which is executed by this {@link BreakHandler}
* @param executionContext contains current execution data (specific to current execution)
* @return an instance of {@link BreakHandler}
* @throws BreakHandlerException when the handler could not have been produced
*/
BreakHandler<R> makeHandler(Task<R> task, ExecutionContext<R> executionContext) throws BreakHandlerException;
}