History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/rmi/server/RemoteObjectInvocationHandler.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/rmi/server/RemoteObjectInvocationHandler.java+283−0
@@ -0,0 +1,283 @@
1+/*
2+ * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package java.rmi.server;
26+
27+import java.io.InvalidObjectException;
28+import java.lang.reflect.InvocationHandler;
29+import java.lang.reflect.Method;
30+import java.lang.reflect.Proxy;
31+import java.rmi.Remote;
32+import java.rmi.UnexpectedException;
33+import java.rmi.activation.Activatable;
34+import java.util.Map;
35+import java.util.WeakHashMap;
36+import sun.rmi.server.Util;
37+import sun.rmi.server.WeakClassHashMap;
38+
39+/**
40+ * An implementation of the <code>InvocationHandler</code> interface for
41+ * use with Java Remote Method Invocation (Java RMI). This invocation
42+ * handler can be used in conjunction with a dynamic proxy instance as a
43+ * replacement for a pregenerated stub class.
44+ *
45+ * <p>Applications are not expected to use this class directly. A remote
46+ * object exported to use a dynamic proxy with {@link UnicastRemoteObject}
47+ * or {@link Activatable} has an instance of this class as that proxy's
48+ * invocation handler.
49+ *
50+ * @author Ann Wollrath
51+ * @since 1.5
52+ **/
53+public class RemoteObjectInvocationHandler
54+ extends RemoteObject
55+ implements InvocationHandler
56+{
57+ private static final long serialVersionUID = 2L;
58+
59+ /**
60+ * A weak hash map, mapping classes to weak hash maps that map
61+ * method objects to method hashes.
62+ **/
63+ private static final MethodToHash_Maps methodToHash_Maps =
64+ new MethodToHash_Maps();
65+
66+ /**
67+ * Creates a new <code>RemoteObjectInvocationHandler</code> constructed
68+ * with the specified <code>RemoteRef</code>.
69+ *
70+ * @param ref the remote ref
71+ *
72+ * @throws NullPointerException if <code>ref</code> is <code>null</code>
73+ **/
74+ public RemoteObjectInvocationHandler(RemoteRef ref) {
75+ super(ref);
76+ if (ref == null) {
77+ throw new NullPointerException();
78+ }
79+ }
80+
81+ /**
82+ * Processes a method invocation made on the encapsulating
83+ * proxy instance, <code>proxy</code>, and returns the result.
84+ *
85+ * <p><code>RemoteObjectInvocationHandler</code> implements this method
86+ * as follows:
87+ *
88+ * <p>If <code>method</code> is one of the following methods, it
89+ * is processed as described below:
90+ *
91+ * <ul>
92+ *
93+ * <li>{@link Object#hashCode Object.hashCode}: Returns the hash
94+ * code value for the proxy.
95+ *
96+ * <li>{@link Object#equals Object.equals}: Returns <code>true</code>
97+ * if the argument (<code>args[0]</code>) is an instance of a dynamic
98+ * proxy class and this invocation handler is equal to the invocation
99+ * handler of that argument, and returns <code>false</code> otherwise.
100+ *
101+ * <li>{@link Object#toString Object.toString}: Returns a string
102+ * representation of the proxy.
103+ * </ul>
104+ *
105+ * <p>Otherwise, a remote call is made as follows:
106+ *
107+ * <ul>
108+ * <li>If <code>proxy</code> is not an instance of the interface
109+ * {@link Remote}, then an {@link IllegalArgumentException} is thrown.
110+ *
111+ * <li>Otherwise, the {@link RemoteRef#invoke invoke} method is invoked
112+ * on this invocation handler's <code>RemoteRef</code>, passing
113+ * <code>proxy</code>, <code>method</code>, <code>args</code>, and the
114+ * method hash (defined in section 8.3 of the "Java Remote Method
115+ * Invocation (RMI) Specification") for <code>method</code>, and the
116+ * result is returned.
117+ *
118+ * <li>If an exception is thrown by <code>RemoteRef.invoke</code> and
119+ * that exception is a checked exception that is not assignable to any
120+ * exception in the <code>throws</code> clause of the method
121+ * implemented by the <code>proxy</code>'s class, then that exception
122+ * is wrapped in an {@link UnexpectedException} and the wrapped
123+ * exception is thrown. Otherwise, the exception thrown by
124+ * <code>invoke</code> is thrown by this method.
125+ * </ul>
126+ *
127+ * <p>The semantics of this method are unspecified if the
128+ * arguments could not have been produced by an instance of some
129+ * valid dynamic proxy class containing this invocation handler.
130+ *
131+ * @param proxy the proxy instance that the method was invoked on
132+ * @param method the <code>Method</code> instance corresponding to the
133+ * interface method invoked on the proxy instance
134+ * @param args an array of objects containing the values of the
135+ * arguments passed in the method invocation on the proxy instance, or
136+ * <code>null</code> if the method takes no arguments
137+ * @return the value to return from the method invocation on the proxy
138+ * instance
139+ * @throws Throwable the exception to throw from the method invocation
140+ * on the proxy instance
141+ **/
142+ public Object invoke(Object proxy, Method method, Object[] args)
143+ throws Throwable
144+ {
145+ if (method.getDeclaringClass() == Object.class) {
146+ return invokeObjectMethod(proxy, method, args);
147+ } else {
148+ return invokeRemoteMethod(proxy, method, args);
149+ }
150+ }
151+
152+ /**
153+ * Handles java.lang.Object methods.
154+ **/
155+ private Object invokeObjectMethod(Object proxy,
156+ Method method,
157+ Object[] args)
158+ {
159+ String name = method.getName();
160+
161+ if (name.equals("hashCode")) {
162+ return hashCode();
163+
164+ } else if (name.equals("equals")) {
165+ Object obj = args[0];
166+ return
167+ proxy == obj ||
168+ (obj != null &&
169+ Proxy.isProxyClass(obj.getClass()) &&
170+ equals(Proxy.getInvocationHandler(obj)));
171+
172+ } else if (name.equals("toString")) {
173+ return proxyToString(proxy);
174+
175+ } else {
176+ throw new IllegalArgumentException(
177+ "unexpected Object method: " + method);
178+ }
179+ }
180+
181+ /**
182+ * Handles remote methods.
183+ **/
184+ private Object invokeRemoteMethod(Object proxy,
185+ Method method,
186+ Object[] args)
187+ throws Exception
188+ {
189+ try {
190+ if (!(proxy instanceof Remote)) {
191+ throw new IllegalArgumentException(
192+ "proxy not Remote instance");
193+ }
194+ return ref.invoke((Remote) proxy, method, args,
195+ getMethodHash(method));
196+ } catch (Exception e) {
197+ if (!(e instanceof RuntimeException)) {
198+ Class<?> cl = proxy.getClass();
199+ try {
200+ method = cl.getMethod(method.getName(),
201+ method.getParameterTypes());
202+ } catch (NoSuchMethodException nsme) {
203+ throw (IllegalArgumentException)
204+ new IllegalArgumentException().initCause(nsme);
205+ }
206+ Class<?> thrownType = e.getClass();
207+ for (Class<?> declaredType : method.getExceptionTypes()) {
208+ if (declaredType.isAssignableFrom(thrownType)) {
209+ throw e;
210+ }
211+ }
212+ e = new UnexpectedException("unexpected exception", e);
213+ }
214+ throw e;
215+ }
216+ }
217+
218+ /**
219+ * Returns a string representation for a proxy that uses this invocation
220+ * handler.
221+ **/
222+ private String proxyToString(Object proxy) {
223+ Class<?>[] interfaces = proxy.getClass().getInterfaces();
224+ if (interfaces.length == 0) {
225+ return "Proxy[" + this + "]";
226+ }
227+ String iface = interfaces[0].getName();
228+ if (iface.equals("java.rmi.Remote") && interfaces.length > 1) {
229+ iface = interfaces[1].getName();
230+ }
231+ int dot = iface.lastIndexOf('.');
232+ if (dot >= 0) {
233+ iface = iface.substring(dot + 1);
234+ }
235+ return "Proxy[" + iface + "," + this + "]";
236+ }
237+
238+ /**
239+ * @throws InvalidObjectException unconditionally
240+ **/
241+ private void readObjectNoData() throws InvalidObjectException {
242+ throw new InvalidObjectException("no data in stream; class: " +
243+ this.getClass().getName());
244+ }
245+
246+ /**
247+ * Returns the method hash for the specified method. Subsequent calls
248+ * to "getMethodHash" passing the same method argument should be faster
249+ * since this method caches internally the result of the method to
250+ * method hash mapping. The method hash is calculated using the
251+ * "computeMethodHash" method.
252+ *
253+ * @param method the remote method
254+ * @return the method hash for the specified method
255+ */
256+ private static long getMethodHash(Method method) {
257+ return methodToHash_Maps.get(method.getDeclaringClass()).get(method);
258+ }
259+
260+ /**
261+ * A weak hash map, mapping classes to weak hash maps that map
262+ * method objects to method hashes.
263+ **/
264+ private static class MethodToHash_Maps
265+ extends WeakClassHashMap<Map<Method,Long>>
266+ {
267+ MethodToHash_Maps() {}
268+
269+ protected Map<Method,Long> computeValue(Class<?> remoteClass) {
270+ return new WeakHashMap<Method,Long>() {
271+ public synchronized Long get(Object key) {
272+ Long hash = super.get(key);
273+ if (hash == null) {
274+ Method method = (Method) key;
275+ hash = Util.computeMethodHash(method);
276+ put(method, hash);
277+ }
278+ return hash;
279+ }
280+ };
281+ }
282+ }
283+}