Package org.ow2.easybeans.proxy.client

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

/**
* EasyBeans
* Copyright (C) 2006-2007 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: LocalCallInvocationHandler.java 5369 2010-02-24 14:58:19Z benoitf $
* --------------------------------------------------------------------------
*/

package org.ow2.easybeans.proxy.client;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.lang.reflect.Method;
import java.util.HashMap;

import javax.ejb.EJBLocalObject;
import javax.ejb.NoSuchEJBException;
import javax.ejb.NoSuchObjectLocalException;

import org.ow2.easybeans.api.EZBContainer;
import org.ow2.easybeans.api.EZBServer;
import org.ow2.easybeans.api.EmbeddedManager;
import org.ow2.easybeans.api.Factory;
import org.ow2.easybeans.rpc.EJBLocalRequestImpl;
import org.ow2.easybeans.rpc.api.EJBLocalRequest;
import org.ow2.easybeans.rpc.api.EJBResponse;
import org.ow2.easybeans.rpc.api.RPCException;
import org.ow2.easybeans.rpc.util.Hash;

/**
* Object acting as the proxy for local interfaces calls.
* @author Florent Benoit
*/
public class LocalCallInvocationHandler extends AbsInvocationHandler implements Externalizable {

    /**
     * UID for serialization.
     */
    private static final long serialVersionUID = -4327634481654235615L;

    /**
     * Embedded server ID.
     */
    private Integer embeddedID = null;

    /**
     * Factory for sending requests (build in constructor or when serialization
     * occurs).
     */
    private transient Factory<?, ?> factory = null;

    /**
     * Boolean used to know if this class extends javax.ejb.EJBLocalObject class.
     */
    private boolean isExtendingEJBLocalObject = false;

    /**
     * Build a new Invocation handler.
     * @param embeddedID the Embedded server ID.
     * @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 LocalCallInvocationHandler(final Integer embeddedID, final String containerId, final String factoryName,
            final boolean useID) {
        super(containerId, factoryName, useID);

        // Server ID
        this.embeddedID = embeddedID;

        // Init the factory
        initFactory();
    }

    /**
     * Default constructor (used for serialization).
     */
    public LocalCallInvocationHandler() {
        super(null, null, false);
    }

    /**
     * Initialize the factory object with the given infos.
     */
    private void initFactory() {
        // Get Embedded server
        EZBServer ejb3Server = EmbeddedManager.getEmbedded(this.embeddedID);
        if (ejb3Server == null) {
            throw new IllegalStateException("Cannot find the server with id '" + this.embeddedID + "'.");
        }

        // Get the container
        EZBContainer container = ejb3Server.getContainer(getContainerId());
        if (container == null) {
            throw new IllegalStateException("Cannot find the container with id '" + getContainerId() + "'.");
        }

        this.factory = container.getFactory(getFactoryName());
        if (this.factory == null) {
            throw new IllegalStateException("Cannot find the factory with name '" + getFactoryName() + "'.");
        }
    }

    /**
     * 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);
    }

    /**
     * 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 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.
     */
    public Object invoke(final Object proxy, final Method method, final Object[] args, final Long hashMethod) throws Exception {
        // bean removed ?
        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);
            }
        }

        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;
        }

        // Now, need to invoke the bean
        EJBLocalRequest localRequest = new EJBLocalRequestImpl(hashLong, args, getBeanId(), getInterfaceClassName());
        EJBResponse response = this.factory.localCall(localRequest);
        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());

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




        return response.getValue();

    }

    /**
     * Save our content.
     * @param out the stream to write the object to
     * @throws IOException Includes any I/O exceptions that may occur
     */
    public void writeExternal(final ObjectOutput out) throws IOException {
        // server ID
        out.writeObject(this.embeddedID);
        // Container ID
        out.writeObject(getContainerId());
        // Factory name
        out.writeObject(getFactoryName());
        // interface class name
        out.writeObject(getInterfaceClassName());
        // boolean (extending java.rmi.remote ?)
        out.writeBoolean(isExtendingRmiRemote());
        // boolean (extending javax.ejb.EJBLocalObject ?)
        out.writeBoolean(this.isExtendingEJBLocalObject);

        // boolean (useID flag)
        out.writeBoolean(isUsingID());

        // boolean (removed)
        out.writeBoolean(isRemoved());
    }

    /**
     * Build our content.
     * @param in the stream to read data from in order to restore the object
     * @exception IOException if I/O errors occur
     * @exception ClassNotFoundException If the class for an object being
     *            restored cannot be found.
     */
    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
        // read ServerID
        this.embeddedID = (Integer) in.readObject();
        // read Container id
        setContainerId((String) in.readObject());
        // read factory's name
        setFactoryName((String) in.readObject());

        // interface class name
        setInterfaceClassName((String) in.readObject());

        // boolean flag
        setExtendingRmiRemote(in.readBoolean());

        // boolean (extending javax.ejb.EJBLocalObject ?)
        this.isExtendingEJBLocalObject = (in.readBoolean());

        // useID flag
        setUseID(in.readBoolean());

        // removed flag
        setRemoved(in.readBoolean());

        // init Factory object (transient)
        initFactory();

    }

    /**
     * Gets the embedded ID.
     * @return the embedded ID.
     */
    protected Integer getEmbeddedID() {
        return this.embeddedID;
    }

    /**
     * Sets the interface that represents this handler.
     * @param clz the instance of the interface.
     */
    @Override
    public void setInterfaceClass(final Class<?> clz) {
        super.setInterfaceClass(clz);
        if (EJBLocalObject.class.isAssignableFrom(clz)) {
            this.isExtendingEJBLocalObject = true;
        }
    }

    /**
     * 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.4.2.3 chapter EJB3
        if (this.isExtendingEJBLocalObject && throwable instanceof NoSuchEJBException) {
            NoSuchObjectLocalException ne = new NoSuchObjectLocalException(throwable.getMessage(), (Exception) throwable);
            return ne;
        }
        // no check
        return throwable;
    }

    /**
     * This method has to be used only from the OSGi.
     * @param factory the factory to set
     */
    public void setFactory(final Factory<?, ?> factory) {
        this.factory = factory;
    }

    /**
     * @return the Factory used to execute the requests.
     */
    protected Factory<?, ?> getFactory() {
        return this.factory;
    }
}
TOP

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

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.