View Javadoc
1   package net.secodo.jcircuitbreaker.breaker.impl;
2   
3   import java.util.concurrent.ConcurrentHashMap;
4   
5   import net.secodo.jcircuitbreaker.breaker.CircuitBreaker;
6   import net.secodo.jcircuitbreaker.breaker.ContextAwareCircuitBreaker;
7   import net.secodo.jcircuitbreaker.breaker.execution.ExecutedTask;
8   import net.secodo.jcircuitbreaker.breaker.execution.ExecutionContext;
9   import net.secodo.jcircuitbreaker.breaker.execution.impl.DefaultExecutionContextImpl;
10  import net.secodo.jcircuitbreaker.breakhandler.BreakHandler;
11  import net.secodo.jcircuitbreaker.breakhandler.exception.BreakHandlerException;
12  import net.secodo.jcircuitbreaker.breakstrategy.BreakStrategy;
13  import net.secodo.jcircuitbreaker.exception.CircuitBreakerException;
14  import net.secodo.jcircuitbreaker.exception.TaskExecutionException;
15  import net.secodo.jcircuitbreaker.task.Task;
16  import net.secodo.jcircuitbreaker.util.TimeUtil;
17  
18  
19  public abstract class AbstractCircuitBreaker<R> implements CircuitBreaker<R>, ContextAwareCircuitBreaker<R> {
20    private final ConcurrentHashMap<String, ExecutedTask<R>> tasksInProgress;
21    private final TimeUtil timeUtil;
22  
23    public AbstractCircuitBreaker() {
24      this.tasksInProgress = new ConcurrentHashMap<>();
25      timeUtil = new TimeUtil();
26    }
27  
28    @Override
29    public <U> R execute(Task<R> task, BreakStrategy<R> breakStrategy, BreakHandler<R> breakHandler,
30                         U userData) throws TaskExecutionException, BreakHandlerException, CircuitBreakerException {
31      DefaultExecutionContextImpl<R> executionContext = new DefaultExecutionContextImpl<>(tasksInProgress, userData);
32  
33      return executeInContext(task, breakStrategy, breakHandler, executionContext);
34    }
35  
36    @Override
37    public R executeInContext(Task<R> task, BreakStrategy<R> breakStrategy, BreakHandler<R> breakHandler,  
38                              ExecutionContext<R> executionContext) 
39        throws TaskExecutionException, BreakHandlerException, CircuitBreakerException {
40      
41      if (!breakStrategy.shouldBreak(task, executionContext)) {
42        // track state asynchronously - not to block by resize operation on possible resize of hashmap
43  
44        R returnedValue = null;
45        String taskKey = "not_existing_task_key"; // prevents possible null pointer in finally clause
46  
47        try {
48          taskKey = String.valueOf(Thread.currentThread().getId()) + "_" + task.hashCode();
49  
50          final ExecutedTask<R> executedTask = new ExecutedTask<R>(task, timeUtil.getCurrentTimeMilis());
51          tasksInProgress.put(taskKey, executedTask);
52  
53          try {
54            returnedValue = task.execute();
55          } catch (Exception ex) {
56            throw new TaskExecutionException("Execution of task: " + task + " failed with exception: " + ex.getMessage(),
57              ex);
58          }
59  
60        } catch (TaskExecutionException ex) {
61          throw ex;
62  
63        } catch (Exception ex) {
64          String taskInfo;
65          try {
66            taskInfo = task.toString();
67          } catch (Throwable th) {
68            taskInfo = "[exception while call task.toString(): " + ex.getMessage() + "]";
69          }
70  
71          throw new CircuitBreakerException("Exception while executing an actual call to task: " + taskInfo, ex);
72  
73        } finally {
74          tasksInProgress.remove(taskKey);
75        }
76  
77  
78        return returnedValue;
79  
80      } else {
81        return breakHandler.onBreak(this, task, breakStrategy, executionContext);
82      }
83  
84    }
85  
86  }