package example.common.interceptor;

import java.lang.reflect.Method;

import javax.annotation.Resource;
import javax.ejb.EJBContext;
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import example.common.exception.ApplicationException;

public class ServiceInterceptor {

    @Resource
    EJBContext ejbContext;

    static ThreadLocal<Integer> level = new ThreadLocal<Integer>() {
        protected Integer initialValue() { return 0; }
    };

    static Logger logger = LoggerFactory.getLogger(ServiceInterceptor.class);

    @AroundInvoke
    public Object invoke(InvocationContext context) throws Exception {
        try {
            incLevel();
            try {
                return context.proceed();
            } finally {
                decLevel();
            }
        } catch (RuntimeException e) {
            setRollbackOnly(e, context);
            throw e;
        } catch (ApplicationException e) {
            if (e.isRollbackOnly()) {
                setRollbackOnly(e, context);
            }
            throw e;
        }
    }

    static void incLevel() {
        level.set(level.get() + 1);
    }

    static void decLevel() {
        level.set(level.get() - 1);
    }

    void setRollbackOnly(Exception e, InvocationContext context) {
        if (logger.isInfoEnabled()) {
            StringBuilder sb = new StringBuilder();
            sb.append(e.getClass().getName());
            sb.append(" was thrown.\n    at ");
            Method method = context.getMethod();
            sb.append(method.getDeclaringClass().getName());
            sb.append('#');
            sb.append(method.getName());
            logger.info(sb.toString());
        }
        boolean rollbackOnly = ejbContext.getRollbackOnly();
        if (logger.isDebugEnabled()) {
            logger.debug("rollbackOnly = " + rollbackOnly);
        }
        if (level.get() == 0 && !rollbackOnly) {
            logger.info("setRollbackOnly!");
            ejbContext.setRollbackOnly();
        }
    }

}
