KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > rmi > server > RemoteObjectInvocationHandler


1 /*
2  * @(#)RemoteObjectInvocationHandler.java 1.3 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package java.rmi.server;
8
9 import java.io.InvalidObjectException JavaDoc;
10 import java.lang.reflect.InvocationHandler JavaDoc;
11 import java.lang.reflect.Method JavaDoc;
12 import java.lang.reflect.Proxy JavaDoc;
13 import java.rmi.Remote JavaDoc;
14 import java.rmi.UnexpectedException JavaDoc;
15 import java.rmi.activation.Activatable JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.WeakHashMap JavaDoc;
18 import sun.rmi.server.Util;
19 import sun.rmi.server.WeakClassHashMap;
20
21 /**
22  * An implementation of the <code>InvocationHandler</code> interface for
23  * use with Java Remote Method Invocation (Java RMI). This invocation
24  * handler can be used in conjunction with a dynamic proxy instance as a
25  * replacement for a pregenerated stub class.
26  *
27  * <p>Applications are not expected to use this class directly. A remote
28  * object exported to use a dynamic proxy with {@link UnicastRemoteObject}
29  * or {@link Activatable} has an instance of this class as that proxy's
30  * invocation handler.
31  *
32  * @version 1.3, 03/12/19
33  * @author Ann Wollrath
34  * @since 1.5
35  **/

36 public class RemoteObjectInvocationHandler
37     extends RemoteObject JavaDoc
38     implements InvocationHandler JavaDoc
39 {
40     private static final long serialVersionUID = 2L;
41
42     /**
43      * A weak hash map, mapping classes to weak hash maps that map
44      * method objects to method hashes.
45      **/

46     private static final MethodToHash_Maps methodToHash_Maps =
47     new MethodToHash_Maps();
48
49     /**
50      * Creates a new <code>RemoteObjectInvocationHandler</code> constructed
51      * with the specified <code>RemoteRef</code>.
52      *
53      * @param ref the remote ref
54      *
55      * @throws NullPointerException if <code>ref</code> is <code>null</code>
56      **/

57     public RemoteObjectInvocationHandler(RemoteRef JavaDoc ref) {
58     super(ref);
59     if (ref == null) {
60         throw new NullPointerException JavaDoc();
61     }
62     }
63     
64     /**
65      * Processes a method invocation made on the encapsulating
66      * proxy instance, <code>proxy</code>, and returns the result.
67      *
68      * <p><code>RemoteObjectInvocationHandler</code> implements this method
69      * as follows:
70      *
71      * <p>If <code>method</code> is one of the following methods, it
72      * is processed as described below:
73      *
74      * <ul>
75      *
76      * <li>{@link Object#hashCode Object.hashCode}: Returns the hash
77      * code value for the proxy.
78      *
79      * <li>{@link Object#equals Object.equals}: Returns <code>true</code>
80      * if the argument (<code>args[0]</code>) is an instance of a dynamic
81      * proxy class and this invocation handler is equal to the invocation
82      * handler of that argument, and returns <code>false</code> otherwise.
83      *
84      * <li>{@link Object#toString Object.toString}: Returns a string
85      * representation of the proxy.
86      * </ul>
87      *
88      * <p>Otherwise, a remote call is made as follows:
89      *
90      * <ul>
91      * <li>If <code>proxy</code> is not an instance of the interface
92      * {@link Remote}, then an {@link IllegalArgumentException} is thrown.
93      *
94      * <li>Otherwise, the {@link RemoteRef#invoke invoke} method is invoked
95      * on this invocation handler's <code>RemoteRef</code>, passing
96      * <code>proxy</code>, <code>method</code>, <code>args</code>, and the
97      * method hash (defined in section 8.3 of the "Java Remote Method
98      * Invocation (RMI) Specification") for <code>method</code>, and the
99      * result is returned.
100      *
101      * <li>If an exception is thrown by <code>RemoteRef.invoke</code> and
102      * that exception is a checked exception that is not assignable to any
103      * exception in the <code>throws</code> clause of the method
104      * implemented by the <code>proxy</code>'s class, then that exception
105      * is wrapped in an {@link UnexpectedException} and the wrapped
106      * exception is thrown. Otherwise, the exception thrown by
107      * <code>invoke</code> is thrown by this method.
108      * </ul>
109      *
110      * <p>The semantics of this method are unspecified if the
111      * arguments could not have been produced by an instance of some
112      * valid dynamic proxy class containing this invocation handler.
113      *
114      * @param proxy the proxy instance that the method was invoked on
115      * @param method the <code>Method</code> instance corresponding to the
116      * interface method invoked on the proxy instance
117      * @param args an array of objects containing the values of the
118      * arguments passed in the method invocation on the proxy instance, or
119      * <code>null</code> if the method takes no arguments
120      * @return the value to return from the method invocation on the proxy
121      * instance
122      * @throws Throwable the exception to throw from the method invocation
123      * on the proxy instance
124      * @see
125      **/

126     public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
127     throws Throwable JavaDoc
128     {
129     if (method.getDeclaringClass() == Object JavaDoc.class) {
130         return invokeObjectMethod(proxy, method, args);
131     } else {
132         return invokeRemoteMethod(proxy, method, args);
133     }
134     }
135     
136     /**
137      * Handles java.lang.Object methods.
138      **/

139     private Object JavaDoc invokeObjectMethod(Object JavaDoc proxy,
140                       Method JavaDoc method,
141                       Object JavaDoc[] args)
142     {
143     String JavaDoc name = method.getName();
144
145     if (name.equals("hashCode")) {
146         return new Integer JavaDoc(hashCode());
147
148     } else if (name.equals("equals")) {
149         Object JavaDoc obj = args[0];
150         boolean b =
151         proxy == obj ||
152         (obj != null &&
153          Proxy.isProxyClass(obj.getClass()) &&
154          equals(Proxy.getInvocationHandler(obj)));
155         return Boolean.valueOf(b);
156
157     } else if (name.equals("toString")) {
158         return proxyToString(proxy);
159
160     } else {
161         throw new IllegalArgumentException JavaDoc(
162         "unexpected Object method: " + method);
163     }
164     }
165
166     /**
167      * Handles remote methods.
168      **/

169     private Object JavaDoc invokeRemoteMethod(Object JavaDoc proxy,
170                       Method JavaDoc method,
171                       Object JavaDoc[] args)
172     throws Exception JavaDoc
173     {
174     try {
175         if (!(proxy instanceof Remote JavaDoc)) {
176         throw new IllegalArgumentException JavaDoc(
177             "proxy not Remote instance");
178         }
179         return ref.invoke((Remote JavaDoc) proxy, method, args,
180                   getMethodHash(method));
181     } catch (Exception JavaDoc e) {
182         if (!(e instanceof RuntimeException JavaDoc)) {
183         Class JavaDoc cl = proxy.getClass();
184         try {
185             method = cl.getMethod(method.getName(),
186                       method.getParameterTypes());
187         } catch (NoSuchMethodException JavaDoc nsme) {
188             throw (IllegalArgumentException JavaDoc)
189             new IllegalArgumentException JavaDoc().initCause(nsme);
190         }
191         Class JavaDoc[] exTypes = method.getExceptionTypes();
192         Class JavaDoc thrownType = e.getClass();
193         for (int i = 0; i < exTypes.length; i++) {
194             if (exTypes[i].isAssignableFrom(thrownType)) {
195             throw e;
196             }
197         }
198         e = new UnexpectedException JavaDoc("unexpected exception", e);
199         }
200         throw e;
201     }
202     }
203
204     /**
205      * Returns a string representation for a proxy that uses this invocation
206      * handler.
207      **/

208     private String JavaDoc proxyToString(Object JavaDoc proxy) {
209     Class JavaDoc[] interfaces = proxy.getClass().getInterfaces();
210     if (interfaces.length == 0) {
211         return "Proxy[" + this + "]";
212     }
213     String JavaDoc iface = interfaces[0].getName();
214     if (iface.equals("java.rmi.Remote") && interfaces.length > 1) {
215         iface = interfaces[1].getName();
216     }
217     int dot = iface.lastIndexOf('.');
218     if (dot >= 0) {
219         iface = iface.substring(dot + 1);
220     }
221     return "Proxy[" + iface + "," + this + "]";
222     }
223
224     /**
225      * @throws InvalidObjectException unconditionally
226      **/

227     private void readObjectNoData() throws InvalidObjectException JavaDoc {
228         throw new InvalidObjectException JavaDoc("no data in stream; class: " +
229                                          this.getClass().getName());
230     }
231
232     /**
233      * Returns the method hash for the specified method. Subsequent calls
234      * to "getMethodHash" passing the same method argument should be faster
235      * since this method caches internally the result of the method to
236      * method hash mapping. The method hash is calculated using the
237      * "computeMethodHash" method.
238      *
239      * @param method the remote method
240      * @return the method hash for the specified method
241      */

242     private static long getMethodHash(Method JavaDoc method) {
243     Map JavaDoc map = methodToHash_Maps.getMap(method.getDeclaringClass());
244     Long JavaDoc hash = (Long JavaDoc) map.get(method);
245     return hash.longValue();
246     }
247
248     /**
249      * A weak hash map, mapping classes to weak hash maps that map
250      * method objects to method hashes.
251      **/

252     private static class MethodToHash_Maps extends WeakClassHashMap {
253     
254     MethodToHash_Maps() {}
255     
256     protected Map JavaDoc createMap(Class JavaDoc remoteClass) {
257         return new WeakHashMap JavaDoc() {
258         public synchronized Object JavaDoc get(Object JavaDoc key) {
259             Object JavaDoc hash = super.get(key);
260             if (hash == null) {
261             Method JavaDoc method = (Method JavaDoc) key;
262             hash = new Long JavaDoc(Util.computeMethodHash(method));
263             put(method, hash);
264             }
265             return (Long JavaDoc) hash;
266         }
267         };
268     }
269     }
270 }
271
Popular Tags