001: /**
002: * EasyBeans
003: * Copyright (C) 2006 Bull S.A.S.
004: * Contact: easybeans@ow2.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: ClientRPCInvocationHandler.java 2010 2007-10-26 13:19:08Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.proxy.client;
025:
026: import java.lang.reflect.Method;
027: import java.rmi.NoSuchObjectException;
028: import java.util.HashMap;
029: import java.util.Hashtable;
030:
031: import javax.ejb.EJBException;
032: import javax.ejb.EJBObject;
033: import javax.ejb.EJBTransactionRequiredException;
034: import javax.ejb.Handle;
035: import javax.ejb.NoSuchEJBException;
036: import javax.transaction.TransactionRequiredException;
037:
038: import org.ow2.easybeans.container.svc.EasyBeansHandle;
039: import org.ow2.easybeans.rpc.JEJBRequest;
040: import org.ow2.easybeans.rpc.RPC;
041: import org.ow2.easybeans.rpc.api.ClientRPC;
042: import org.ow2.easybeans.rpc.api.EJBRequest;
043: import org.ow2.easybeans.rpc.api.EJBResponse;
044: import org.ow2.easybeans.rpc.api.RPCException;
045: import org.ow2.easybeans.rpc.util.Hash;
046:
047: /**
048: * This class sends an EJB request to the server and send back to the client the
049: * response.
050: * @author Florent Benoit
051: */
052: public class ClientRPCInvocationHandler extends AbsInvocationHandler {
053:
054: /**
055: * Id for serializable class.
056: */
057: private static final long serialVersionUID = 1852625501781836250L;
058:
059: /**
060: * Environment used by the client when lookup on proxy object has be done.
061: * This will be set by the Remote Factory.
062: */
063: private Hashtable<?, ?> rmiClientEnvironment = null;
064:
065: /**
066: * Build a new Invocation handler.
067: * @param containerId the id of the container that will be called on the
068: * remote side.
069: * @param factoryName the name of the remote factory.
070: * @param useID true if all instance build with this ref are unique
071: * (stateful), false if it references the same object (stateless)
072: */
073: public ClientRPCInvocationHandler(final String containerId,
074: final String factoryName, final boolean useID) {
075: super (containerId, factoryName, useID);
076: }
077:
078: /**
079: * Processes a method invocation on a proxy instance and returns the result.
080: * This method will be invoked on an invocation handler when a method is
081: * invoked on a proxy instance that it is associated with.
082: * @param proxy the proxy instance that the method was invoked on
083: * @param method the <code>Method</code> instance corresponding to the
084: * interface method invoked on the proxy instance. The declaring
085: * class of the <code>Method</code> object will be the interface
086: * that the method was declared in, which may be a superinterface of
087: * the proxy interface that the proxy class inherits the method
088: * through.
089: * @param args an array of objects containing the values of the arguments
090: * passed in the method invocation on the proxy instance, or
091: * <code>null</code> if interface method takes no arguments.
092: * Arguments of primitive types are wrapped in instances of the
093: * appropriate primitive wrapper class, such as
094: * <code>java.lang.Integer</code> or <code>java.lang.Boolean</code>.
095: * @return the value to return from the method invocation on the proxy
096: * instance.
097: * @throws Exception the exception to throw from the method invocation on
098: * the proxy instance.
099: */
100: public Object invoke(final Object proxy, final Method method,
101: final Object[] args) throws Exception {
102:
103: // Bean removed, no methods are allowed
104: if (isRemoved()) {
105: handleThrowable(convertThrowable(new NoSuchEJBException(
106: "The bean has been removed")), false, method, null);
107: }
108:
109: // Methods on the Object.class are not send on the remote side
110: if (method.getDeclaringClass().getName().equals(
111: "java.lang.Object")) {
112: // for stateful bean, let the first call to toString go to the remote side in order to initialize the bean ID
113: if (!isUsingID() || getBeanId() != null
114: || !method.getName().equals("toString")) {
115: return handleObjectMethods(method, args);
116: }
117: }
118:
119: // getHandle method (ejb 2.1) view
120: if ("getHandle".equals(method.getName())
121: && Handle.class.equals(method.getReturnType())) {
122: // In this case, return an handle based on the proxy
123: return new EasyBeansHandle((EJBObject) proxy);
124: }
125:
126: ClientRPC client = RPC.getClient(rmiClientEnvironment);
127:
128: if (getHashedMethods() == null) {
129: setHashedMethods(new HashMap<Method, Long>());
130: }
131:
132: Long hashLong = getHashedMethods().get(method);
133: if (hashLong == null) {
134: hashLong = Long.valueOf(Hash.hashMethod(method));
135: getHashedMethods().put(method, hashLong);
136: }
137:
138: long hash = hashLong.longValue();
139:
140: EJBRequest request = new JEJBRequest(method.getName(), hash,
141: args, getContainerId(), getFactoryName(), getBeanId());
142:
143: // send response
144: EJBResponse response;
145: try {
146: response = client.sendEJBRequest(request);
147: } catch (RuntimeException e) {
148: // Exception due to protocol
149: throw new EJBException("Error while sending a request", e);
150: }
151: // Sets the bean ID
152: setBeanId(response.getBeanId());
153:
154: // bean removed ?
155: setRemoved(response.isRemoved());
156:
157: // Handle exception
158: RPCException rpcException = response.getRPCException();
159: if (rpcException != null) {
160: handleThrowable(convertThrowable(rpcException.getCause()),
161: rpcException.isApplicationException(), method,
162: rpcException);
163: }
164:
165: return response.getValue();
166: }
167:
168: /**
169: * Convert the received exception to the correct type for the remote case.
170: * @param throwable the exception to analyze.
171: * @return the converted exception or the original exception
172: */
173: protected Throwable convertThrowable(final Throwable throwable) {
174: // see 14.3.9 chapter EJB3
175: if (isExtendingRmiRemote()
176: && throwable instanceof NoSuchEJBException) {
177: NoSuchObjectException ne = new NoSuchObjectException(
178: throwable.getMessage());
179: ne.detail = throwable;
180: return ne;
181: }
182:
183: // see 14.4.2.2 chapter EJB3
184: if (throwable instanceof javax.ejb.TransactionRequiredLocalException) {
185: if (isExtendingRmiRemote()) {
186: TransactionRequiredException tre = new TransactionRequiredException(
187: throwable.getMessage());
188: tre.detail = throwable;
189: return tre;
190: }
191: // else
192: EJBTransactionRequiredException ejbTransRequiredException = new EJBTransactionRequiredException(
193: throwable.getMessage());
194: ejbTransRequiredException.initCause(throwable);
195: return ejbTransRequiredException;
196: }
197: return throwable;
198: }
199:
200: /**
201: * Set the RMI environment used by the client when the lookup has been done.
202: * @param rmiClientEnvironment the given environment.
203: */
204: public void setRMIEnv(final Hashtable<?, ?> rmiClientEnvironment) {
205: this .rmiClientEnvironment = rmiClientEnvironment;
206: }
207:
208: /**
209: * Get the RMI environment used by the client when the lookup has been done.
210: * @return RMI env.
211: */
212: public Hashtable<?, ?> getRMIEnv() {
213: return rmiClientEnvironment;
214: }
215:
216: }
|