package org.mockejb.interceptor;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.*;

/**
 * Creates dynamic proxy and acts as an InvocationHandler for 
 * this proxy. During invocation, obtains relevant interceptors from
 * AspectSystem and makes them part of the invocation chain.
 * Uses Cglib internally.
 * 
 * Use this class when you have an interface/class and a single implementation class
 * for this interface. 
 * Usage example:
 * <code>(Context) InterceptableProxy.create( 
 *                   Context.class, new MockContext() );
 * </code>
 * 
 * You can also create proxies for classes (including using the same class
 * as the intercepted and target class) :
 * <code>
 * InterceptableTestClass proxy = (InterceptableTestClass) 
 *           InterceptableProxy.create( TestImpl.class, new TestImpl() );
 * </code> 
 * Note that implementation classes don't have to be public (cglib feature).
 * 
 * @author Alexander Ananiev
 */
public class InterceptableProxy implements MethodInterceptor {
    
    private Class ifaceClass;
    private Object implObj;

    private InterceptorInvoker interceptorInvoker = new InterceptorInvoker();
    
    public static Object create( Class ifaceClass, Object implObj ){
        Enhancer e = new Enhancer();
        e.setSuperclass( ifaceClass );
       
        e.setCallback( new InterceptableProxy( ifaceClass, implObj ) );
        
        return e.create();
        
    }

    InterceptableProxy( Class ifaceClass, Object implObj ){
        this.ifaceClass = ifaceClass;
        this.implObj = implObj;
    }
        
    public Object intercept(Object obj, Method proxyMethod, Object[] paramVals,
            MethodProxy proxy) throws Throwable {
        
        Method implMethod = implObj.getClass().getMethod( proxyMethod.getName(), 
                proxyMethod.getParameterTypes() );
        
        return  interceptorInvoker.invoke( obj, proxyMethod, implObj, implMethod, paramVals );
        
    }
    

}