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: AbsInvocationHandler.java 2010 2007-10-26 13:19:08Z benoitf $
023: * --------------------------------------------------------------------------
024: */package org.ow2.easybeans.proxy.client;
025:
026: import java.io.Serializable;
027: import java.lang.reflect.InvocationHandler;
028: import java.lang.reflect.Method;
029: import java.rmi.Remote;
030: import java.util.HashMap;
031: import java.util.Map;
032:
033: import javax.ejb.EJBException;
034:
035: import org.ow2.easybeans.rpc.api.RPCException;
036:
037: /**
038: * Abstract class used by remote or local invocation handler.
039: * @author Florent Benoit
040: */
041: public abstract class AbsInvocationHandler implements
042: InvocationHandler, Serializable {
043:
044: /**
045: * Bean has been removed.
046: */
047: private boolean removed = false;
048:
049: /**
050: * Container id.
051: */
052: private String containerId = null;
053:
054: /**
055: * Factory name.
056: */
057: private String factoryName = null;
058:
059: /**
060: * Bean id.
061: */
062: private Long beanId = null;
063:
064: /**
065: * Map between method and its hash.
066: */
067: private transient Map<Method, Long> hashedMethods = null;
068:
069: /**
070: * Interface used by this handler.
071: */
072: private String interfaceClassName = null;
073:
074: /**
075: * Boolean used to know if this class extends java.rmi.Remote class.
076: */
077: private boolean isItfExtendingRmiRemote = false;
078:
079: /**
080: * useID true if all instance build with this ref are unique (stateful), false if it references the same object (stateless).
081: */
082: private boolean useID = false;
083:
084: /**
085: * Build a new Invocation handler.
086: * @param containerId the id of the container that will be called on the
087: * remote side.
088: * @param factoryName the name of the remote factory.
089: * @param useID true if all instance build with this ref are unique
090: * (stateful), false if it references the same object (stateless)
091: */
092: public AbsInvocationHandler(final String containerId,
093: final String factoryName, final boolean useID) {
094: this .containerId = containerId;
095: this .factoryName = factoryName;
096: this .useID = useID;
097: this .hashedMethods = new HashMap<Method, Long>();
098: }
099:
100: /**
101: * Manages all methods of java.lang.Object class.
102: * @param method the <code>Method</code> instance corresponding to the
103: * interface method invoked on the proxy instance. The declaring
104: * class of the <code>Method</code> object will be the interface
105: * that the method was declared in, which may be a superinterface of
106: * the proxy interface that the proxy class inherits the method
107: * through.
108: * @param args an array of objects containing the values of the arguments
109: * passed in the method invocation on the proxy instance
110: * @return the value of the called method.
111: */
112: protected Object handleObjectMethods(final Method method,
113: final Object[] args) {
114: String methodName = method.getName();
115:
116: if (methodName.equals("equals")) {
117: return Boolean.valueOf(this .toString().equals(
118: args[0].toString()));
119: } else if (methodName.equals("toString")) {
120: return this .toString();
121: } else if (methodName.equals("hashCode")) {
122: return Integer.valueOf(this .toString().hashCode());
123: } else {
124: throw new IllegalStateException("Method '" + methodName
125: + "' is not present on Object.class.");
126: }
127: }
128:
129: /**
130: * Handle the given throwable and throw the correct exception to the client.
131: * @param originalThrowable the exception that has been thrown on the server side.
132: * @param isApplicationException true if it is an application exception, else false.
133: * @param method the <code>Method</code> instance corresponding to the
134: * interface method invoked on the proxy instance.
135: * @param rpcException the RPC exception if any
136: * @throws Exception the exception that has been wrapped or not for the client.
137: */
138: protected void handleThrowable(final Throwable originalThrowable,
139: final boolean isApplicationException, final Method method,
140: final RPCException rpcException) throws Exception {
141:
142: // Handle the exception
143: // Checked application exception --> throw exception without wrapping it.
144:
145: Class<?>[] exceptions = method.getExceptionTypes();
146: if (exceptions != null) {
147: for (Class<?> clazz : exceptions) {
148: // Is an Exception but not a runtime exception
149: if (clazz.isInstance(originalThrowable)
150: && originalThrowable instanceof Exception
151: && !(originalThrowable instanceof RuntimeException)) {
152: throw (Exception) originalThrowable;
153: }
154: }
155: }
156:
157: // EJBException --> throw exception without wrapping it.
158: if (originalThrowable instanceof EJBException) {
159: throw (EJBException) originalThrowable;
160: }
161:
162: // Runtime Exception :
163: // 1/ It's an application exception : throw exception without wrapping it.
164: // 2/ It's not an application exception : Wrap exception in an EJBException.
165: if (originalThrowable instanceof RuntimeException) {
166: if (isApplicationException) {
167: throw (RuntimeException) originalThrowable;
168: }
169: // not an application exception
170: throw new EJBException((RuntimeException) originalThrowable);
171: }
172:
173: // Exception but not checked (wrap it in an EJBException)
174: if (originalThrowable instanceof Exception) {
175: throw new EJBException((Exception) originalThrowable
176: .getCause());
177: }
178:
179: // Other case (throwable): Wrap throwable in an Exception and then in an EJBException
180: // First wrap is required as EJBException accept only Exception, not throwable
181: if (rpcException != null) {
182: throw new EJBException(rpcException);
183: }
184: // Else use the throwable
185: throw new EJBException(new Exception("Unexpected Exception",
186: originalThrowable));
187:
188: }
189:
190: /**
191: * Sets the id of the bean.
192: * @param beanId the new ID.
193: */
194: protected void setBeanId(final Long beanId) {
195: this .beanId = beanId;
196: }
197:
198: /**
199: * Sets the hashed methods.
200: * @param hashedMethods the hash for each method.
201: */
202: protected void setHashedMethods(
203: final Map<Method, Long> hashedMethods) {
204: this .hashedMethods = hashedMethods;
205: }
206:
207: /**
208: * Gets the bean id.
209: * @return the bean id.
210: */
211: public Long getBeanId() {
212: return beanId;
213: }
214:
215: /**
216: * @return the container id.
217: */
218: protected String getContainerId() {
219: return containerId;
220: }
221:
222: /**
223: * @return the name of the factory.
224: */
225: public String getFactoryName() {
226: return factoryName;
227: }
228:
229: /**
230: * @return the hashes for each method.
231: */
232: protected Map<Method, Long> getHashedMethods() {
233: return hashedMethods;
234: }
235:
236: /**
237: * Sets the container ID.
238: * @param containerId the identifier of the container.
239: */
240: protected void setContainerId(final String containerId) {
241: this .containerId = containerId;
242: }
243:
244: /**
245: * Sets the factory's name.
246: * @param factoryName the name of the factory.
247: */
248: protected void setFactoryName(final String factoryName) {
249: this .factoryName = factoryName;
250: }
251:
252: /**
253: * @return the name of the interface that represents this handler.
254: */
255: public String getInterfaceClassName() {
256: return interfaceClassName;
257: }
258:
259: /**
260: * Sets the name of the interface that represents this handler.
261: * @param interfaceClassName the name of the interface.
262: */
263: protected void setInterfaceClassName(final String interfaceClassName) {
264: this .interfaceClassName = interfaceClassName;
265: }
266:
267: /**
268: * Sets the interface that represents this handler.
269: * @param clz the instance of the interface.
270: */
271: public void setInterfaceClass(final Class<?> clz) {
272: if (Remote.class.isAssignableFrom(clz)) {
273: isItfExtendingRmiRemote = true;
274: }
275: setInterfaceClassName(clz.getName());
276: }
277:
278: /**
279: * Sets the flag if interface is extending java.rmi.Remote.
280: * @param isItfExtendingRmiRemote true if it extending, else false.
281: */
282: public void setExtendingRmiRemote(
283: final boolean isItfExtendingRmiRemote) {
284: this .isItfExtendingRmiRemote = isItfExtendingRmiRemote;
285: }
286:
287: /**
288: * @return true if the interface used by this handler is extending java.rmi.Remote.
289: */
290: public boolean isExtendingRmiRemote() {
291: return isItfExtendingRmiRemote;
292: }
293:
294: /**
295: * Sets the flag if all instance build with this ref are unique or not.
296: * @param useID true : (stateful), false if it references the same object (stateless).
297: */
298: public void setUseID(final boolean useID) {
299: this .useID = useID;
300: }
301:
302: /**
303: * @return true : (stateful), false if it references the same object (stateless).
304: */
305: public boolean isUsingID() {
306: return useID;
307: }
308:
309: /**
310: * Gets a string representation for this handler.
311: * @return a string representation for this handler.
312: */
313: @Override
314: public String toString() {
315: StringBuilder sb = new StringBuilder();
316: sb.append(factoryName);
317: sb.append("_");
318: sb.append(interfaceClassName);
319: sb.append("/");
320: sb.append(containerId);
321: if (useID) {
322: sb.append("@");
323: sb.append(System.identityHashCode(this ));
324: }
325: return sb.toString();
326: }
327:
328: /**
329: * @return true if the bean has been removed
330: */
331: public boolean isRemoved() {
332: return removed;
333: }
334:
335: /**
336: * Sets the removed flag.
337: * @param removed if bean has been removed.
338: */
339: public void setRemoved(final boolean removed) {
340: this.removed = removed;
341: }
342: }
|