/* 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.soap;

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.ejb.EJBObject;

import org.jfox.ejb.EJBHomeMethod;
import org.jfox.ejb.EJBObjectId;
import org.jfox.ejb.EJBObjectMethod;
import org.jfox.ejb.HandleImpl;
import org.jfox.ejb.Invocation;
import org.jfox.ejb.InvocationImpl;
import org.jfox.ejb.connector.ContainerInvokerSupport;
import org.jfox.ejb.connector.ContainerRemote;

/**
 * 工作在客户端，负责将返回的 byte[]转换成 Object
 *
 * @author <a href="mailto:young_yy@hotmail.com">Young Yang</a>
 */

public class SOAPContainerInvoker extends ContainerInvokerSupport {

    public SOAPContainerInvoker(EJBObjectId objectId, ContainerRemote invoker) {
        super(objectId, invoker);
    }

    protected Object invokeHome(Object proxy, Method method, Object[] args) throws Exception {
        Invocation invocation = new InvocationImpl(objectId, new Long(getMethodHash(method)).toString(), args);

        if(method.equals(EJBHomeMethod.GetEJBMetaData)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBHomeMethod.GetHomeHandle)) {
//      String homeClass = objectId.getHomeInterfName();
//      return new HomeHandleImpl(homeClass);
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBHomeMethod.RemoveByHandle)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBHomeMethod.RemoveByPrimaryKey)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else { // create 方法
            byte[] bytes = (byte[]) invoker.invoke(invocation); // obj 是 EJBObject 的 ID
            EJBObjectId objectId = (EJBObjectId) unmarshelledObject(bytes);
            ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
            // get the EJBObject class name
            String remoteInterfaceName = objectId.getRemoteInterfaceName();
            Class remoteInterface = ctxLoader.loadClass(remoteInterfaceName);
            // 构造本地的 EJBObject 代理对象
            return Proxy.newProxyInstance(ctxLoader,
                    new Class[]{remoteInterface},
                    new SOAPContainerInvoker(objectId, invoker));
        }

    }

    protected Object invokeBean(Object proxy, Method method, Object[] args) throws Exception {
        Invocation invocation = new InvocationImpl(objectId, new Long(getMethodHash(method)).toString(), args);
        if(method.equals(EJBObjectMethod.GetEJBHome)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBObjectMethod.GetHandle)) {
            ContainerInvokerSupport invocationHandler = (ContainerInvokerSupport) Proxy.getInvocationHandler(proxy);
            return new HandleImpl(invocationHandler);
        }
        else if(method.equals(EJBObjectMethod.GetPrimaryKey)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBObjectMethod.IsIdentical)) {
            // 把参数 args[0] 转换为　EJBObject 的　ObjectId，服务端只用　ObjectId 来比较
            EJBObject ejbObject = (EJBObject) args[0];
            Object _objectId = ((ContainerInvokerSupport) (Proxy.getInvocationHandler(ejbObject))).getObjectId();
            invocation = new InvocationImpl(objectId, new Long(getMethodHash(method)).toString(), new Object[]{_objectId});
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else if(method.equals(EJBObjectMethod.Remove)) {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
        else {
            return unmarshelledObject((byte[]) invoker.invoke(invocation));
        }
    }

    public static Object unmarshelledObject(byte[] bytes) {
        try {
            ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
            Object obj = in.readObject();
            in.close();
            return obj;
        }
        catch(Exception e) {
            e.printStackTrace();
            return bytes;
        }
    }

    public static void main(String[] args) {

    }
}