package dk.thoerup.circuitbreaker; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import dk.thoerup.circuitbreaker.config.BreakerConfig; import dk.thoerup.circuitbreaker.config.StaticConfig; import dk.thoerup.circuitbreaker.notification.NotiferHelper; import dk.thoerup.circuitbreaker.notification.Notifier; import dk.thoerup.circuitbreaker.notification.NullNotifier; /* Simple CircuitBreaker implementation - snipped from http://www.jroller.com/kenwdelong/entry/circuit_breaker_in_java * * example of how it can be used private CircuitBreaker cb = new CircuitBreaker("test", 5, 10000); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { class TestInvocation implements CircuitInvocation { String url; public TestInvocation(String url) { this.url = url; } public Object proceed() throws Exception{ URL u = new URL(url); URLConnection c = u.openConnection(); c.connect(); InputStream in = c.getInputStream(); in.close(); return "hello"; } } try { String s = (String) cb.invoke(new TestInvocation("http://rafiki/test")); response.getWriter().print(s); } catch (Exception e) { logger.warning( e.getMessage() ); response.sendError(500); return; } } */ public class CircuitBreaker{ private volatile CircuitBreakerState currentState; private final OpenState open = new OpenState(); private final HalfOpenState halfOpen = new HalfOpenState(); private final ClosedState closed = new ClosedState(); private String name; private ExecutorService executor = null; private Notifier notifier = new NullNotifier(); @Deprecated public CircuitBreaker(String name, int threshold, int timeoutMS) { this(name, new StaticConfig(threshold, timeoutMS) ); } public CircuitBreaker(String name, BreakerConfig config) { closed.setThreshold(config); open.setTimeout(config); this.name = name; //set correct intial state internalReset(); } public synchronized void shutdown() { if (executor != null) { executor.shutdown(); } } public Object invoke(CircuitInvocation invocation) throws Exception { Object result = null; try { getState().preInvoke(this); result = invocation.proceed(); getState().postInvoke(this); } catch(Exception e) { getState().onError(this, e); throw e; } return result; } public void tripBreaker() { commonTripBreaker(Notifier.Event.BreakerTripped); } //a re-trip should basically do the same as a normal trip, but it is here just to differentiate the two different events public void retripBreaker() { commonTripBreaker(Notifier.Event.BreakerRetripped); } private void commonTripBreaker(Notifier.Event event) { synchronized(this) { if (currentState != open) { // TODO:Is this conditional necessary ?? open.trip(); currentState = open; notifier.sendNotification(this, event); } } } public void attemptReset() { synchronized(this) { if (currentState != halfOpen) { // TODO:Is this conditional necessary ?? currentState = halfOpen; notifier.sendNotification(this, Notifier.Event.BreakerAttemptReset); } } } public void reset() { synchronized(this) { if (currentState != closed) { // TODO: Is this conditional necessary ?? internalReset(); notifier.sendNotification(this, Notifier.Event.BreakerReset); } } } //This one actually sets the correct closed/reset state private void internalReset() { closed.resetFailureCount(); currentState = closed; } private CircuitBreakerState getState() { synchronized(this) { return currentState; } } public boolean isClosed() { return (getState() == closed); } public boolean isOpen() { return (getState() == open); } public String getName() { return name; } public String getStateName() { return getState().getName(); } public int getThreshold() { return closed.getThreshold(); } public int getTimeout() { return (int)open.getTimeout(); } public int getFailureCount() { if (getState() == closed) { return closed.getFailureCount(); } else { return -1; } } public long getElapsed() { if (getState() == open) { return open.getElapsed(); } else { return -1; } } public void setNotifier(Notifier notifier) { this.notifier = notifier; } public String getNotifierName() { return NotiferHelper.getName(notifier); } public synchronized ExecutorService getExecutor() { if (executor == null) { executor = Executors.newFixedThreadPool(1); } return executor; } }