1 package net.secodo.jcircuitbreaker.breakhandler;
2
3 import net.secodo.jcircuitbreaker.breaker.CircuitBreaker;
4 import net.secodo.jcircuitbreaker.breaker.ContextAwareCircuitBreaker;
5 import net.secodo.jcircuitbreaker.breaker.execution.ExecutionContext;
6 import net.secodo.jcircuitbreaker.breakhandler.exception.BreakHandlerException;
7 import net.secodo.jcircuitbreaker.breakstrategy.BreakStrategy;
8 import net.secodo.jcircuitbreaker.task.Task;
9
10
11 /**
12 * An implementation of {@link BreakHandlerFactory} which creates new instance of given {@link BreakHandler} if it
13 * does not exist in current execution context, otherwise returns {@link BreakHandler} bound to current execution
14 * context (reuses the same instance for handling subsequent calls to
15 * {@link BreakHandler#onBreak(ContextAwareCircuitBreaker, Task, BreakStrategy, ExecutionContext)}).
16 *
17 * <p>NOTE: Each call to {@link CircuitBreaker#execute(Task, BreakStrategy, BreakHandler)} method creates new
18 * context.
19 * If implementation of {@link OnePerExecutionHandlerFactory} is used as a {@link BreakHandler}, "one and only one"
20 * instance of given {@link BreakHandler} is created for per execution context (this is guaranteed by default
21 * implementation of {@link #makeHandler(Task, ExecutionContext)} provided by this interface)
22 */
23 public interface OnePerExecutionHandlerFactory<R> extends BreakHandlerFactory<R> {
24 @Override
25 default BreakHandler<R> makeHandler(Task<R> task, ExecutionContext<R> executionContext)
26 throws BreakHandlerException {
27 String executionContextParamName = getOnePerExecutionContextParamName(task, executionContext);
28
29 if (!executionContext.hasContextAttribute(executionContextParamName)) {
30 // no retry handler was create for current execution so we need to create it
31
32 BreakHandler<R> breakHandler = createNewHandler(task, executionContext);
33 executionContext.setContextAttribute(executionContextParamName, breakHandler);
34 }
35
36 return executionContext.getContextAttribute(executionContextParamName);
37 }
38
39 /**
40 * Constructs and returns new {@link BreakHandler}. This method is invoked break handler has not yet been created in
41 * current execution context.
42 *
43 * @param task the originally executed task
44 * @param executionContext current execution context
45 * @return new instance of {@link BreakHandler}
46 */
47 BreakHandler<R> createNewHandler(Task<R> task, ExecutionContext<R> executionContext);
48
49 /**
50 * Returns execution context parameter name under which produced break handler will be stored.
51 *
52 * @param task the originally executed task
53 * @param executionContext current execution context
54 *
55 * @see ExecutionContext#getContextAttribute(String)
56 * @return a String representing attribute name
57 */
58 default String getOnePerExecutionContextParamName(Task<R> task, ExecutionContext<R> executionContext) {
59 return "one_per_execution_handler_factory_" + this.getClass().getName();
60 }
61 }