package example.common.interceptor;

import java.lang.reflect.Method;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;

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

public class TraceInterceptor {

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

    @AroundInvoke
    public Object invoke(InvocationContext context) throws Exception {
        if (!logger.isDebugEnabled()) {
            return context.proceed();
        }
        String signature = getSignature(context);
        logger.debug("BEGIN " + signature);
        StringBuilder sb = new StringBuilder();
        sb.append(signature);
        try {
            Object result = context.proceed();
            sb.append(" => ");
            appendObject(sb, result);
            logger.debug("END " + sb);
            return result;
        } catch (Throwable t) {
            sb.append(" => throw ").append(t);
            logger.debug("END " + sb);
            if (t instanceof Error) {
                throw (Error) t;
            }
            throw (Exception) t;
        }
    }

    protected String getSignature(InvocationContext context) {
        StringBuilder sb = new StringBuilder();
        Method method = context.getMethod();
        sb.append(method.getDeclaringClass().getName());
        sb.append('#');
        sb.append(method.getName());
        sb.append('(');
        Object[] args = context.getParameters();
        if (args.length > 0) {
            appendObject(sb, args[0]);
            for (int i = 1; i < args.length; ++i) {
                sb.append(", ");
                appendObject(sb, args[i]);
            }
        }
        sb.append(')');
        return sb.toString();
    }

    protected void appendObject(StringBuilder sb, Object value) {
        sb.append(value);
    }

}
