1 package net.secodo.jcircuitbreaker.breakhandler;
2
3 import static java.util.Objects.isNull;
4
5 import java.util.concurrent.Callable;
6
7 import net.secodo.jcircuitbreaker.breaker.ContextAwareCircuitBreaker;
8 import net.secodo.jcircuitbreaker.breaker.execution.ExecutionContext;
9 import net.secodo.jcircuitbreaker.breakhandler.exception.BreakHandlerException;
10 import net.secodo.jcircuitbreaker.breakstrategy.BreakStrategy;
11 import net.secodo.jcircuitbreaker.exception.CircuitBreakerException;
12 import net.secodo.jcircuitbreaker.exception.TaskExecutionException;
13 import net.secodo.jcircuitbreaker.task.Task;
14
15
16 /**
17 * This is generic factory method interface. Each implementation should implement
18 * {@link #makeHandler(Task, ExecutionContext)} method which returns instance of a {@link BreakHandler}. The
19 * returned instance should be shareable between different executions of the target-method (between execution of
20 * different tasks). This means that the implementation should conform to one of following statements:
21 * <ul>
22 * <li>should be stateless - the returned handler should not allow modification of its internal state. This prevents
23 * possible {@link java.util.ConcurrentModificationException} when accessed by different threads</li>
24 * <li>should return new instance (but the instances may not share a common state via static fields etc. which may
25 * result in {@link java.util.ConcurrentModificationException} when accessed by different threads)</li>
26 * <li>may share state (or be the same instance) as long as any possible concurrent modifications are protected by
27 * synchronization/locking mechanism, so that multiple threads can access the instance on the same time</li>
28 * </ul>
29 *
30 * @param <R> the return type of onBreak method of the created {@link BreakHandler}. This must be the same return
31 * type as the of of executed Task
32 */
33 public interface BreakHandlerFactory<R> extends BreakHandler<R> {
34 @Override
35 default R onBreak(ContextAwareCircuitBreaker<R> circuitBreaker, Task<R> task, BreakStrategy<R> breakStrategy,
36 ExecutionContext<R> executionContext) throws TaskExecutionException, CircuitBreakerException,
37 BreakHandlerException {
38 BreakHandler<R> handler = makeHandler(task, executionContext);
39 if (isNull(handler)) {
40 throw new BreakHandlerException("makeHandler() method returned handler which is null");
41 }
42
43 return handler.onBreak(circuitBreaker, task, breakStrategy, executionContext);
44 }
45
46 /**
47 * Returns an instance of {@link BreakHandler} which should be used to handle the <i>break</i>.
48 *
49 * @param task the task which is executed by this {@link BreakHandler}
50 * @param executionContext contains current execution data (specific to current execution)
51 * @return an instance of {@link BreakHandler}
52 * @throws BreakHandlerException when the handler could not have been produced
53 */
54 BreakHandler<R> makeHandler(Task<R> task, ExecutionContext<R> executionContext) throws BreakHandlerException;
55 }