/************************************************
 * Copyright (c) Shen Li. All rights reserved.  *
 * http://joyaop.sourceforge.net                *
 * -------------------------------------------- *
 * Distributable under LGPL license.            *
 * See terms of license at gnu.org.             *
 ************************************************/
package net.sf.joyaop.impl;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.List;

/** 
 * @author Shen Li
 */
class CallbackImpl implements MethodInterceptor, Serializable {
//    public static final Object PROXY = new Serializable() {};
    private static final long serialVersionUID = 0;
    private List interceptorInstances;
    private Object targetObject;
    private boolean needThreadLocalInvocation;

    public CallbackImpl(List interceptorInstances, Object targetObject, boolean needThreadLocalInvocation) {
        this.interceptorInstances = interceptorInstances;
        this.targetObject = targetObject;
        this.needThreadLocalInvocation = needThreadLocalInvocation;
    }

    public Object intercept(Object proxy, Method method,
                            Object[] args, MethodProxy methodProxy) throws Throwable {
        Object target = ((targetObject == null) ? proxy : targetObject);
        InvocationImpl invocation = new InvocationImpl(interceptorInstances, target, method, methodProxy, proxy, args);
        InvocationImpl lastInvocation = null;
        if (needThreadLocalInvocation) {
            lastInvocation = InvocationImpl.getCurrentInvocation();             
            if (lastInvocation != null
                    && method.equals(lastInvocation.getMethod())
                    && lastInvocation.isAtInterceptors()) {
                return lastInvocation.proceed();
            }
            InvocationImpl.setCurrentInvocation(invocation);
        }
        try {
            return invocation.proceed();
        } finally {
            if (needThreadLocalInvocation) {
                InvocationImpl.setCurrentInvocation(lastInvocation);
            }
        }
    }
}