net.greencoding.thysdrus.circuitbreaker.aspect.CircuitBreakerAspect.java Source code

Java tutorial

Introduction

Here is the source code for net.greencoding.thysdrus.circuitbreaker.aspect.CircuitBreakerAspect.java

Source

/*
 * Copyright 2010 Nabil Ben Said.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.greencoding.thysdrus.circuitbreaker.aspect;

import net.greencoding.thysdrus.circuitbreaker.annotation.MonitoredByCircuitBreaker;
import net.greencoding.thysdrus.circuitbreaker.exception.CircuitBreakerMethodExecutionException;
import net.greencoding.thysdrus.circuitbreaker.exception.OpenCircuitException;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author Nabil Ben Said (nabil.bensaid@gmail.com)
 *
 */
@Aspect
public class CircuitBreakerAspect {
    // TODO implement statistics

    private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerAspect.class);

    private static CircuitBreakerMethodRegistry registry = new CircuitBreakerMethodRegistry();

    @Around("execution(@net.greencoding.thysdrus.circuitbreaker.annotation.MonitoredByCircuitBreaker * * (..))")
    public Object breakCircuit(final ProceedingJoinPoint pjp) throws Throwable {
        Object returnObject = null;
        final String method = pjp.getSignature().toLongString();
        CircuitBreakerStatus status = null;
        try {
            final MethodSignature sig = (MethodSignature) pjp.getStaticPart().getSignature();
            final MonitoredByCircuitBreaker cbAnnotation = sig.getMethod()
                    .getAnnotation(MonitoredByCircuitBreaker.class);
            registry.registerMehtodIfnecessary(method, cbAnnotation);
            status = registry.getStatusWithHalfOpenExclusiveLockTry(method);
            if (status.equals(CircuitBreakerStatus.OPEN)) {
                logger.info("CIRCUIT STATUS: OPEN. Method {} can not be executed. try later!", method);
                if (cbAnnotation.isSilientMode()) {
                    return null;
                } else {
                    throw new OpenCircuitException();
                }
            } else if (status.equals(CircuitBreakerStatus.HALF_OPEN)) {
                logger.info(
                        "CIRCUIT STATUS: HALF_OPEN. Another thread has the exclusive lock for half open. Method {} can not be executed.",
                        method);
                if (cbAnnotation.isSilientMode()) {
                    return null;
                } else {
                    throw new OpenCircuitException();
                }
            } else if (status.equals(CircuitBreakerStatus.CLOSED)) {
                logger.info("CIRCUIT STATUS: CLOSED. execute method {}", method);
                returnObject = proceed(pjp);
            } else if (status.equals(CircuitBreakerStatus.HALF_OPEN_EXCLUSIVE)) {
                logger.info(
                        "CIRCUIT STATUS: HALF_OPEN_EXCLUSIVE. This thread win the exclusive lock for the half open call. execute method: {}",
                        method);
                returnObject = proceed(pjp);
                logger.info(
                        "CIRCUIT STATUS: HALF_OPEN_EXCLUSIVE. method execution was successfull. now close circuit for method {}",
                        method);
                registry.closeAndUnlock(method);
            }

        } catch (CircuitBreakerMethodExecutionException e) {
            Throwable throwable = e.getCause();
            for (Class<? extends Throwable> clazz : registry.getfailureIndications(method)) {
                if (clazz.isAssignableFrom(throwable.getClass())) {
                    // detected a failure 
                    logger.info("dectected failure. failure indication: {} \nException:", clazz.getCanonicalName(),
                            throwable);
                    if (status.equals(CircuitBreakerStatus.CLOSED)
                            && registry.sameClosedCycleInLocalAndGlobaleContext(method)) {
                        logger.info("Valid failure: method call and failure are in the same CLOSED cycle.");
                        registry.addFailureAndOpenCircuitIfThresholdAchived(method);
                    } else if (status.equals(CircuitBreakerStatus.HALF_OPEN_EXCLUSIVE)) {
                        registry.keepOpenAndUnlock(method);
                    }
                    throw throwable;
                }
            }
            // thrown exception is not a failureIndication
            if (status.equals(CircuitBreakerStatus.HALF_OPEN_EXCLUSIVE)) {
                logger.info(
                        "CIRCUIT STATUS: HALF_OPEN_EXCLUSIVE. method execution was successfull. now close circuit for method {}",
                        method);
                registry.closeAndUnlock(method);
            }
            // throw the original method execution exception upper to the method invoker
            throw throwable;
        } finally {
            registry.cleanUp(method);
        }
        return returnObject;
    }

    private Object proceed(ProceedingJoinPoint pjp) throws CircuitBreakerMethodExecutionException {
        try {
            return pjp.proceed();
        } catch (Throwable t) {
            logger.debug("Exception while method execution: {}", pjp.getSignature().toLongString());
            throw new CircuitBreakerMethodExecutionException(t);
        }
    }

    protected static void setRegistry(CircuitBreakerMethodRegistry registry) {
        CircuitBreakerAspect.registry = registry;
    }

}