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
43
44 R returnedValue = null;
45 String taskKey = "not_existing_task_key";
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 }