Package org.ow2.easybeans.proxy.client

Source Code of org.ow2.easybeans.proxy.client.ClientRPCInvocationHandler

/**
* EasyBeans
* Copyright (C) 2006 Bull S.A.S.
* Contact: easybeans@ow2.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA
*
* --------------------------------------------------------------------------
* $Id: ClientRPCInvocationHandler.java 5369 2010-02-24 14:58:19Z benoitf $
* --------------------------------------------------------------------------
*/

package org.ow2.easybeans.proxy.client;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.NoSuchObjectException;
import java.util.HashMap;
import java.util.Hashtable;

import javax.ejb.EJBException;
import javax.ejb.EJBObject;
import javax.ejb.EJBTransactionRequiredException;
import javax.ejb.Handle;
import javax.ejb.NoSuchEJBException;
import javax.transaction.TransactionRequiredException;

import org.ow2.easybeans.container.svc.EasyBeansHandle;
import org.ow2.easybeans.rpc.EJBRemoteRequestImpl;
import org.ow2.easybeans.rpc.RPC;
import org.ow2.easybeans.rpc.api.ClientRPC;
import org.ow2.easybeans.rpc.api.EJBRemoteRequest;
import org.ow2.easybeans.rpc.api.EJBResponse;
import org.ow2.easybeans.rpc.api.RPCException;
import org.ow2.easybeans.rpc.util.Hash;



/**
* This class sends an EJB request to the server and send back to the client the
* response.
* @author Florent Benoit
*/
public class ClientRPCInvocationHandler extends AbsInvocationHandler {

    /**
     * Id for serializable class.
     */
    private static final long serialVersionUID = 1852625501781836250L;

    /**
     * Flag used to recreate EasyBeans Proxy on the client side as with IIOP/JacORB the dynamic proxy serialization is failing.
     */
    private static final boolean RECREATE_DYNAMIC_PROXY = Boolean.getBoolean("easybeans.recreate.dynamic.proxy");

    /**
     * Environment used by the client when lookup on proxy object has be done.
     * This will be set by the Remote Factory.
     */
    private Hashtable<?, ?> rmiClientEnvironment = null;

    /**
     * Build a new Invocation handler.
     * @param containerId the id of the container that will be called on the
     *        remote side.
     * @param factoryName the name of the remote factory.
     * @param useID true if all instance build with this ref are unique
     *        (stateful), false if it references the same object (stateless)
     */
    public ClientRPCInvocationHandler(final String containerId, final String factoryName, final boolean useID) {
        super(containerId, factoryName, useID);
    }


    /**
     * Processes a method invocation on a proxy instance and returns the result.
     * This method will be invoked on an invocation handler when a method is
     * invoked on a proxy instance that it is associated with.
     * @param proxy the proxy instance that the method was invoked on
     * @param method the <code>Method</code> instance corresponding to the
     *        interface method invoked on the proxy instance. The declaring
     *        class of the <code>Method</code> object will be the interface
     *        that the method was declared in, which may be a superinterface of
     *        the proxy interface that the proxy class inherits the method
     *        through.
     * @param args an array of objects containing the values of the arguments
     *        passed in the method invocation on the proxy instance, or
     *        <code>null</code> if interface method takes no arguments.
     *        Arguments of primitive types are wrapped in instances of the
     *        appropriate primitive wrapper class, such as
     *        <code>java.lang.Integer</code> or <code>java.lang.Boolean</code>.
     * @return the value to return from the method invocation on the proxy
     *         instance.
     * @throws Exception the exception to throw from the method invocation on
     *         the proxy instance.
     */
    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {
        return invoke(proxy, method, args, null, null);

    }


    /**
     * Processes a method invocation on a proxy instance and returns the result.
     * This method will be invoked on an invocation handler when a method is
     * invoked on a proxy instance that it is associated with.
     * @param proxy the proxy instance that the method was invoked on
     * @param method the <code>Method</code> instance corresponding to the
     *        interface method invoked on the proxy instance. The declaring
     *        class of the <code>Method</code> object will be the interface
     *        that the method was declared in, which may be a superinterface of
     *        the proxy interface that the proxy class inherits the method
     *        through.
     * @param args an array of objects containing the values of the arguments
     *        passed in the method invocation on the proxy instance, or
     *        <code>null</code> if interface method takes no arguments.
     *        Arguments of primitive types are wrapped in instances of the
     *        appropriate primitive wrapper class, such as
     *        <code>java.lang.Integer</code> or <code>java.lang.Boolean</code>.
     * @param methodName the name of the method
     * @param hashMethod the hash of the method
     * @return the value to return from the method invocation on the proxy
     *         instance.
     * @throws Exception the exception to throw from the method invocation on
     *         the proxy instance.
     */
    protected Object invoke(final Object proxy, final Method method, final Object[] args, final String methodName,
            final Long hashMethod) throws Exception {

        // Bean removed, no methods are allowed
        if (isRemoved()) {
            handleThrowable(convertThrowable(new NoSuchEJBException("The bean has been removed")), false, method, null);
        }

        // Methods on the Object.class are not send on the remote side
        if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
            // for stateful bean, let the first call to toString go to the remote side in order to initialize the bean ID
            if (!isUsingID() || getBeanId() != null || !method.getName().equals("toString")) {
                return handleObjectMethods(method, args);
            }
        }

        // getHandle method (ejb 2.1) view
        if ("getHandle".equals(method.getName()) && Handle.class.equals(method.getReturnType())) {
            // In this case, return an handle based on the proxy
            return new EasyBeansHandle((EJBObject) proxy);
        }


        ClientRPC client = RPC.getClient(this.rmiClientEnvironment);

        if (getHashedMethods() == null) {
            setHashedMethods(new HashMap<Method, Long>());
        }

        Long hashLong = null;
        if (hashMethod == null) {
            hashLong = getHashedMethods().get(method);
            if (hashLong == null) {
                hashLong = Long.valueOf(Hash.hashMethod(method));
                getHashedMethods().put(method, hashLong);
            }
        } else {
            // Reuse given hashCode
            hashLong = hashMethod;
        }

        // Get or reuse method name
        String mName = null;
        if (methodName != null) {
            mName = methodName;
        } else {
            mName = method.getName();
        }

        EJBRemoteRequest request = new EJBRemoteRequestImpl(mName, hashLong, args, getContainerId(), getFactoryName(),
                getBeanId(), getInterfaceClassName());

        // send response
        EJBResponse response;
        try {
            response = client.sendEJBRequest(request);
        } catch (RuntimeException e) {
            // Exception due to protocol
            throw new EJBException("Error while sending a request", e);
        }
        // Sets the bean ID
        setBeanId(response.getBeanId());

        // toString() call on the remote side for initializing the bean id is done
        // so we return toString() computing
        if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
            if (getBeanId() != null && method.getName().equals("toString")) {
                return handleObjectMethods(method, args);
            }
        }


        // bean removed ?
        setRemoved(response.isRemoved());

        // Handle exception
        RPCException rpcException = response.getRPCException();
        if (rpcException != null) {
            handleThrowable(convertThrowable(rpcException.getCause()), rpcException.isApplicationException(), method,
                    rpcException);
        }

        // Needs to rebuild the proxy as we only have the invocation handler
        if (RECREATE_DYNAMIC_PROXY) {
            Object value = response.getValue();
            if (value != null) {
                if (value instanceof ClientRPCInvocationHandler) {
                    ClientRPCInvocationHandler invocationHandler = (ClientRPCInvocationHandler) value;
                    if (invocationHandler.isBusinessObjectMode()) {
                        Class<?> interfaceClass = Thread.currentThread().getContextClassLoader().loadClass(
                                invocationHandler.getInterfaceClassName());
                        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                                new Class[] {interfaceClass}, invocationHandler);
                    }
                }
            }
        }


        return response.getValue();
    }

    /**
     * Convert the received exception to the correct type for the remote case.
     * @param throwable the exception to analyze.
     * @return the converted exception or the original exception
     */
    protected Throwable convertThrowable(final Throwable throwable) {
        // see 14.3.9 chapter EJB3
        if (isExtendingRmiRemote() && throwable instanceof NoSuchEJBException) {
            NoSuchObjectException ne = new NoSuchObjectException(throwable.getMessage());
            ne.detail = throwable;
            return ne;
        }

        // see 14.4.2.2 chapter EJB3
        if (throwable instanceof javax.ejb.TransactionRequiredLocalException) {
            if (isExtendingRmiRemote()) {
                TransactionRequiredException tre = new TransactionRequiredException(throwable.getMessage());
                tre.detail = throwable;
                return tre;
            }
            // else
            EJBTransactionRequiredException ejbTransRequiredException = new EJBTransactionRequiredException(throwable
                    .getMessage());
            ejbTransRequiredException.initCause(throwable);
            return ejbTransRequiredException;
        }
        return throwable;
    }

    /**
     * Set the RMI environment used by the client when the lookup has been done.
     * @param rmiClientEnvironment the given environment.
     */
    public void setRMIEnv(final Hashtable<?, ?> rmiClientEnvironment) {
        this.rmiClientEnvironment = rmiClientEnvironment;
    }

    /**
     * Get the RMI environment used by the client when the lookup has been done.
     * @return RMI env.
     */
    public Hashtable<?, ?> getRMIEnv() {
        return  this.rmiClientEnvironment;
    }

}
TOP

Related Classes of org.ow2.easybeans.proxy.client.ClientRPCInvocationHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.