package net.greencoding.thysdrus.circuitbreaker.aspectj;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.greencoding.thysdrus.circuitbreaker.annotation.MonitoredByCircuitBreaker;
import net.greencoding.thysdrus.circuitbreaker.core.handler.CircuitBreakerHandler;
import net.greencoding.thysdrus.circuitbreaker.core.handler.DefaultCircuitBreakerHandler;
import net.greencoding.thysdrus.circuitbreaker.core.model.CircuitBreaker;
import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Nabil Ben Said (nabil.bensaid@gmail.com)
*
*/
public class CircuitBreakerAnnotationDiscoverer implements AnnotationDiscoverer {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private CircuitBreakerHandler cbHandler = DefaultCircuitBreakerHandler.getSingleton();
private Map<String, CircuitBreaker> circuitBreakerToRegister = new HashMap<String, CircuitBreaker>();
//@Override
public void discover() {
Reflections reflections = new Reflections("",new MethodAnnotationsScanner());
Set<Method> methods = reflections.getMethodsAnnotatedWith(MonitoredByCircuitBreaker.class);
logger.info("methods: " + methods);
if (methods == null) {
return;
}
for (Method method : methods){
checkCircuitBreakerAnnotation(method);
}
for (String key : circuitBreakerToRegister.keySet()){
cbHandler.registerCircuitBreaker(circuitBreakerToRegister.get(key));
}
circuitBreakerToRegister.clear();
}
private void checkCircuitBreakerAnnotation(final Method method) {
CircuitBreaker ciruitBreaker = new CircuitBreaker();
String circuitBreakerKey = null;
MonitoredByCircuitBreaker annotation = method.getAnnotation(MonitoredByCircuitBreaker.class);
String circuitBreakerGroup = annotation.groupId().isEmpty() ? null : annotation.groupId();
if (circuitBreakerGroup != null) {
circuitBreakerKey = circuitBreakerGroup;
ciruitBreaker.setCircuitBreakerGroup(circuitBreakerGroup);
} else {
circuitBreakerKey = method.toString();
}
ciruitBreaker.setCircuitBreakerKey(circuitBreakerKey);
List<Method> registeredMethods = null;
CircuitBreaker groupCircuitBreaker = circuitBreakerToRegister.get(circuitBreakerKey);
if (groupCircuitBreaker != null) {
checkGroupCircuitBreaker(groupCircuitBreaker, method.toString(), annotation);
ciruitBreaker = groupCircuitBreaker;
registeredMethods = ciruitBreaker.getRegisteredMethods();
} else {
registeredMethods = new ArrayList<Method>();
}
ciruitBreaker.setFailureIndications(annotation.failureIndications());
ciruitBreaker.setFailureThreshold(annotation.failureThreshold());
ciruitBreaker.setFailureThresholdTimeFrameMs(annotation.failureThresholdTimeFrameMs());
ciruitBreaker.setRetryTimeoutMs(annotation.retryTimeoutMs());
registeredMethods.add(method);
ciruitBreaker.setRegisteredMethods(registeredMethods);
circuitBreakerToRegister.put(circuitBreakerKey, ciruitBreaker);
}
private void checkGroupCircuitBreaker(CircuitBreaker groupCircuitBreaker, String methodSignature, MonitoredByCircuitBreaker annotation) {
if (!Arrays.equals(groupCircuitBreaker.getFailureIndications(), annotation.failureIndications()) ||
groupCircuitBreaker.getFailureThreshold() != annotation.failureThreshold() ||
groupCircuitBreaker.getFailureThresholdTimeFrameMs() != annotation.failureThresholdTimeFrameMs()||
groupCircuitBreaker.getRetryTimeoutMs() != annotation.retryTimeoutMs()) {
logger.error("two circuit breaker with the same groupId {} have different parameters method1:{} method2:{}", new Object[]{groupCircuitBreaker.getCircuitBreakerGroup(), groupCircuitBreaker.getRegisteredMethods().get(0).toString(), methodSignature});
throw new IllegalStateException("two circuit breaker with the same groupId " + groupCircuitBreaker.getCircuitBreakerGroup() +" have different parameters CB1:" + groupCircuitBreaker.getRegisteredMethods().get(0).toString() +" CB2:{}" + methodSignature);
}
}
}