/* JFox, the OpenSource J2EE Application Server
 *
 * Distributable under GNU LGPL license by gun.org
 * more details please visit http://www.huihoo.org/jfox
 */
package org.jfox.ejb.connector;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.ejb.EJBObject;

import org.jfox.ejb.EJBObjectId;
import org.jfox.ejb.EJBObjectMethod;
import org.jfox.ejb.MethodHasher;
import org.jfox.ejb.ObjectMethod;

/**
 * 所有的基于某个协议的 InvocationHandler 的父类
 *
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public abstract class ContainerInvokerSupport implements ClientContainerInvoker {
    protected EJBObjectId objectId;
    protected ContainerRemote invoker;

    public ContainerInvokerSupport(EJBObjectId objectId, ContainerRemote invoker) {
        this.objectId = objectId;
        this.invoker = invoker;
    }

    public EJBObjectId getObjectId() {
        return objectId;
    }

    public ContainerRemote getInvoker() {
        return invoker;
    }

    /**
     * 接收由 DelegateInvocationHandler 转发来的 invoke 请求
     * <p/>
     * 可以实现通用的 Object 方法，比如：toString, hashCode 等
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.equals(ObjectMethod.ToString)) {
            return ((ClientContainerInvoker) Proxy.getInvocationHandler(proxy)).getObjectId().toString();
        }
        else if(method.equals(ObjectMethod.HashCode)) {
            return new Integer(objectId.hashCode());
        }
        else if(method.getName().equals(ObjectMethod.Equals)) {
            Object obj = args[0];
            if(objectId.isHome()) {
                return new Boolean(objectId.equals(((ContainerInvokerSupport) Proxy.getInvocationHandler(proxy)).getObjectId()));
            }
            else if(obj instanceof EJBObject) {
                return invokeBean(proxy, EJBObjectMethod.IsIdentical, args);
            }
            else {
                return Boolean.FALSE;
            }
        }

        if(objectId.isHome()) { // 一个 EJBHome 方法
            return invokeHome(proxy, method, args);
        }
        else {
            return invokeBean(proxy, method, args);
        }
    }

    /**
     * 来自 EJBHome 的方法
     * 注意：要注意拦截来自 EJBHome 的请求
     * 比如：create，这时，服务端返回的并不是一个 EJBObject 对象，
     * 而是这个 EJBObject 对象的 ObjectId，所以必须在这里手动生成代理对象
     */
    protected abstract Object invokeHome(Object proxy, Method method, Object[] args) throws Exception;

    /**
     * 执行 Bean 的方法
     */
    protected abstract Object invokeBean(Object proxy, Method method, Object[] args) throws Exception;

    /**
     * 得到一个 method 的 hashCode ，可以唯一的标志一个 method
     *
     * @param method
     * @return
     */
    protected static long getMethodHash(Method method) {
        return MethodHasher.getMethodHash(method);
    }

}
