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/sun/rmi/server/Util.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/rmi/server/Util.java+461−0
@@ -0,0 +1,461 @@
1+/*
2+ * Copyright (c) 1996, 2008, 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 sun.rmi.server;
26+
27+import java.io.ByteArrayOutputStream;
28+import java.io.IOException;
29+import java.io.DataOutputStream;
30+import java.lang.reflect.Constructor;
31+import java.lang.reflect.InvocationHandler;
32+import java.lang.reflect.InvocationTargetException;
33+import java.lang.reflect.Proxy;
34+import java.lang.reflect.Method;
35+import java.rmi.Remote;
36+import java.rmi.RemoteException;
37+import java.rmi.StubNotFoundException;
38+import java.rmi.registry.Registry;
39+import java.rmi.server.LogStream;
40+import java.rmi.server.ObjID;
41+import java.rmi.server.RMIClientSocketFactory;
42+import java.rmi.server.RemoteObjectInvocationHandler;
43+import java.rmi.server.RemoteRef;
44+import java.rmi.server.RemoteStub;
45+import java.rmi.server.Skeleton;
46+import java.rmi.server.SkeletonNotFoundException;
47+import java.security.AccessController;
48+import java.security.MessageDigest;
49+import java.security.DigestOutputStream;
50+import java.security.NoSuchAlgorithmException;
51+import java.util.ArrayList;
52+import java.util.Collections;
53+import java.util.Map;
54+import java.util.WeakHashMap;
55+import sun.rmi.registry.RegistryImpl;
56+import sun.rmi.runtime.Log;
57+import sun.rmi.transport.LiveRef;
58+import sun.rmi.transport.tcp.TCPEndpoint;
59+import sun.security.action.GetBooleanAction;
60+import sun.security.action.GetPropertyAction;
61+
62+/**
63+ * A utility class with static methods for creating stubs/proxies and
64+ * skeletons for remote objects.
65+ */
66+public final class Util {
67+
68+ /** "server" package log level */
69+ static final int logLevel = LogStream.parseLevel(
70+ AccessController.doPrivileged(
71+ new GetPropertyAction("sun.rmi.server.logLevel")));
72+
73+ /** server reference log */
74+ public static final Log serverRefLog =
75+ Log.getLog("sun.rmi.server.ref", "transport", Util.logLevel);
76+
77+ /** cached value of property java.rmi.server.ignoreStubClasses */
78+ private static final boolean ignoreStubClasses =
79+ AccessController.doPrivileged(
80+ new GetBooleanAction("java.rmi.server.ignoreStubClasses")).
81+ booleanValue();
82+
83+ /** cache of impl classes that have no corresponding stub class */
84+ private static final Map<Class<?>, Void> withoutStubs =
85+ Collections.synchronizedMap(new WeakHashMap<Class<?>, Void>(11));
86+
87+ /** parameter types for stub constructor */
88+ private static final Class[] stubConsParamTypes = { RemoteRef.class };
89+
90+ private Util() {
91+ }
92+
93+ /**
94+ * Returns a proxy for the specified implClass.
95+ *
96+ * If both of the following criteria is satisfied, a dynamic proxy for
97+ * the specified implClass is returned (otherwise a RemoteStub instance
98+ * for the specified implClass is returned):
99+ *
100+ * a) either the property java.rmi.server.ignoreStubClasses is true or
101+ * a pregenerated stub class does not exist for the impl class, and
102+ * b) forceStubUse is false.
103+ *
104+ * If the above criteria are satisfied, this method constructs a
105+ * dynamic proxy instance (that implements the remote interfaces of
106+ * implClass) constructed with a RemoteObjectInvocationHandler instance
107+ * constructed with the clientRef.
108+ *
109+ * Otherwise, this method loads the pregenerated stub class (which
110+ * extends RemoteStub and implements the remote interfaces of
111+ * implClass) and constructs an instance of the pregenerated stub
112+ * class with the clientRef.
113+ *
114+ * @param implClass the class to obtain remote interfaces from
115+ * @param clientRef the remote ref to use in the invocation handler
116+ * @param forceStubUse if true, forces creation of a RemoteStub
117+ * @throws IllegalArgumentException if implClass implements illegal
118+ * remote interfaces
119+ * @throws StubNotFoundException if problem locating/creating stub or
120+ * creating the dynamic proxy instance
121+ **/
122+ public static Remote createProxy(Class implClass,
123+ RemoteRef clientRef,
124+ boolean forceStubUse)
125+ throws StubNotFoundException
126+ {
127+ Class remoteClass;
128+
129+ try {
130+ remoteClass = getRemoteClass(implClass);
131+ } catch (ClassNotFoundException ex ) {
132+ throw new StubNotFoundException(
133+ "object does not implement a remote interface: " +
134+ implClass.getName());
135+ }
136+
137+ if (forceStubUse ||
138+ !(ignoreStubClasses || !stubClassExists(remoteClass)))
139+ {
140+ return createStub(remoteClass, clientRef);
141+ }
142+
143+ ClassLoader loader = implClass.getClassLoader();
144+ Class[] interfaces = getRemoteInterfaces(implClass);
145+ InvocationHandler handler =
146+ new RemoteObjectInvocationHandler(clientRef);
147+
148+ /* REMIND: private remote interfaces? */
149+
150+ try {
151+ return (Remote) Proxy.newProxyInstance(loader,
152+ interfaces,
153+ handler);
154+ } catch (IllegalArgumentException e) {
155+ throw new StubNotFoundException("unable to create proxy", e);
156+ }
157+ }
158+
159+ /**
160+ * Returns true if a stub class for the given impl class can be loaded,
161+ * otherwise returns false.
162+ *
163+ * @param remoteClass the class to obtain remote interfaces from
164+ */
165+ private static boolean stubClassExists(Class remoteClass) {
166+ if (!withoutStubs.containsKey(remoteClass)) {
167+ try {
168+ Class.forName(remoteClass.getName() + "_Stub",
169+ false,
170+ remoteClass.getClassLoader());
171+ return true;
172+
173+ } catch (ClassNotFoundException cnfe) {
174+ withoutStubs.put(remoteClass, null);
175+ }
176+ }
177+ return false;
178+ }
179+
180+ /*
181+ * Returns the class/superclass that implements the remote interface.
182+ * @throws ClassNotFoundException if no class is found to have a
183+ * remote interface
184+ */
185+ private static Class getRemoteClass(Class cl)
186+ throws ClassNotFoundException
187+ {
188+ while (cl != null) {
189+ Class[] interfaces = cl.getInterfaces();
190+ for (int i = interfaces.length -1; i >= 0; i--) {
191+ if (Remote.class.isAssignableFrom(interfaces[i]))
192+ return cl; // this class implements remote object
193+ }
194+ cl = cl.getSuperclass();
195+ }
196+ throw new ClassNotFoundException(
197+ "class does not implement java.rmi.Remote");
198+ }
199+
200+ /**
201+ * Returns an array containing the remote interfaces implemented
202+ * by the given class.
203+ *
204+ * @param remoteClass the class to obtain remote interfaces from
205+ * @throws IllegalArgumentException if remoteClass implements
206+ * any illegal remote interfaces
207+ * @throws NullPointerException if remoteClass is null
208+ */
209+ private static Class[] getRemoteInterfaces(Class remoteClass) {
210+ ArrayList<Class<?>> list = new ArrayList<Class<?>>();
211+ getRemoteInterfaces(list, remoteClass);
212+ return list.toArray(new Class<?>[list.size()]);
213+ }
214+
215+ /**
216+ * Fills the given array list with the remote interfaces implemented
217+ * by the given class.
218+ *
219+ * @throws IllegalArgumentException if the specified class implements
220+ * any illegal remote interfaces
221+ * @throws NullPointerException if the specified class or list is null
222+ */
223+ private static void getRemoteInterfaces(ArrayList<Class<?>> list, Class cl) {
224+ Class superclass = cl.getSuperclass();
225+ if (superclass != null) {
226+ getRemoteInterfaces(list, superclass);
227+ }
228+
229+ Class[] interfaces = cl.getInterfaces();
230+ for (int i = 0; i < interfaces.length; i++) {
231+ Class intf = interfaces[i];
232+ /*
233+ * If it is a remote interface (if it extends from
234+ * java.rmi.Remote) and is not already in the list,
235+ * then add the interface to the list.
236+ */
237+ if (Remote.class.isAssignableFrom(intf)) {
238+ if (!(list.contains(intf))) {
239+ Method[] methods = intf.getMethods();
240+ for (int j = 0; j < methods.length; j++) {
241+ checkMethod(methods[j]);
242+ }
243+ list.add(intf);
244+ }
245+ }
246+ }
247+ }
248+
249+ /**
250+ * Verifies that the supplied method has at least one declared exception
251+ * type that is RemoteException or one of its superclasses. If not,
252+ * then this method throws IllegalArgumentException.
253+ *
254+ * @throws IllegalArgumentException if m is an illegal remote method
255+ */
256+ private static void checkMethod(Method m) {
257+ Class<?>[] ex = m.getExceptionTypes();
258+ for (int i = 0; i < ex.length; i++) {
259+ if (ex[i].isAssignableFrom(RemoteException.class))
260+ return;
261+ }
262+ throw new IllegalArgumentException(
263+ "illegal remote method encountered: " + m);
264+ }
265+
266+ /**
267+ * Creates a RemoteStub instance for the specified class, constructed
268+ * with the specified RemoteRef. The supplied class must be the most
269+ * derived class in the remote object's superclass chain that
270+ * implements a remote interface. The stub class name is the name of
271+ * the specified remoteClass with the suffix "_Stub". The loading of
272+ * the stub class is initiated from class loader of the specified class
273+ * (which may be the bootstrap class loader).
274+ **/
275+ private static RemoteStub createStub(Class remoteClass, RemoteRef ref)
276+ throws StubNotFoundException
277+ {
278+ String stubname = remoteClass.getName() + "_Stub";
279+
280+ /* Make sure to use the local stub loader for the stub classes.
281+ * When loaded by the local loader the load path can be
282+ * propagated to remote clients, by the MarshalOutputStream/InStream
283+ * pickle methods
284+ */
285+ try {
286+ Class<?> stubcl =
287+ Class.forName(stubname, false, remoteClass.getClassLoader());
288+ Constructor cons = stubcl.getConstructor(stubConsParamTypes);
289+ return (RemoteStub) cons.newInstance(new Object[] { ref });
290+
291+ } catch (ClassNotFoundException e) {
292+ throw new StubNotFoundException(
293+ "Stub class not found: " + stubname, e);
294+ } catch (NoSuchMethodException e) {
295+ throw new StubNotFoundException(
296+ "Stub class missing constructor: " + stubname, e);
297+ } catch (InstantiationException e) {
298+ throw new StubNotFoundException(
299+ "Can't create instance of stub class: " + stubname, e);
300+ } catch (IllegalAccessException e) {
301+ throw new StubNotFoundException(
302+ "Stub class constructor not public: " + stubname, e);
303+ } catch (InvocationTargetException e) {
304+ throw new StubNotFoundException(
305+ "Exception creating instance of stub class: " + stubname, e);
306+ } catch (ClassCastException e) {
307+ throw new StubNotFoundException(
308+ "Stub class not instance of RemoteStub: " + stubname, e);
309+ }
310+ }
311+
312+ /**
313+ * Locate and return the Skeleton for the specified remote object
314+ */
315+ static Skeleton createSkeleton(Remote object)
316+ throws SkeletonNotFoundException
317+ {
318+ Class cl;
319+ try {
320+ cl = getRemoteClass(object.getClass());
321+ } catch (ClassNotFoundException ex ) {
322+ throw new SkeletonNotFoundException(
323+ "object does not implement a remote interface: " +
324+ object.getClass().getName());
325+ }
326+
327+ // now try to load the skeleton based ont he name of the class
328+ String skelname = cl.getName() + "_Skel";
329+ try {
330+ Class skelcl = Class.forName(skelname, false, cl.getClassLoader());
331+
332+ return (Skeleton)skelcl.newInstance();
333+ } catch (ClassNotFoundException ex) {
334+ throw new SkeletonNotFoundException("Skeleton class not found: " +
335+ skelname, ex);
336+ } catch (InstantiationException ex) {
337+ throw new SkeletonNotFoundException("Can't create skeleton: " +
338+ skelname, ex);
339+ } catch (IllegalAccessException ex) {
340+ throw new SkeletonNotFoundException("No public constructor: " +
341+ skelname, ex);
342+ } catch (ClassCastException ex) {
343+ throw new SkeletonNotFoundException(
344+ "Skeleton not of correct class: " + skelname, ex);
345+ }
346+ }
347+
348+ /**
349+ * Compute the "method hash" of a remote method. The method hash
350+ * is a long containing the first 64 bits of the SHA digest from
351+ * the UTF encoded string of the method name and descriptor.
352+ */
353+ public static long computeMethodHash(Method m) {
354+ long hash = 0;
355+ ByteArrayOutputStream sink = new ByteArrayOutputStream(127);
356+ try {
357+ MessageDigest md = MessageDigest.getInstance("SHA");
358+ DataOutputStream out = new DataOutputStream(
359+ new DigestOutputStream(sink, md));
360+
361+ String s = getMethodNameAndDescriptor(m);
362+ if (serverRefLog.isLoggable(Log.VERBOSE)) {
363+ serverRefLog.log(Log.VERBOSE,
364+ "string used for method hash: \"" + s + "\"");
365+ }
366+ out.writeUTF(s);
367+
368+ // use only the first 64 bits of the digest for the hash
369+ out.flush();
370+ byte hasharray[] = md.digest();
371+ for (int i = 0; i < Math.min(8, hasharray.length); i++) {
372+ hash += ((long) (hasharray[i] & 0xFF)) << (i * 8);
373+ }
374+ } catch (IOException ignore) {
375+ /* can't happen, but be deterministic anyway. */
376+ hash = -1;
377+ } catch (NoSuchAlgorithmException complain) {
378+ throw new SecurityException(complain.getMessage());
379+ }
380+ return hash;
381+ }
382+
383+ /**
384+ * Return a string consisting of the given method's name followed by
385+ * its "method descriptor", as appropriate for use in the computation
386+ * of the "method hash".
387+ *
388+ * See section 4.3.3 of The Java Virtual Machine Specification for
389+ * the definition of a "method descriptor".
390+ */
391+ private static String getMethodNameAndDescriptor(Method m) {
392+ StringBuffer desc = new StringBuffer(m.getName());
393+ desc.append('(');
394+ Class[] paramTypes = m.getParameterTypes();
395+ for (int i = 0; i < paramTypes.length; i++) {
396+ desc.append(getTypeDescriptor(paramTypes[i]));
397+ }
398+ desc.append(')');
399+ Class returnType = m.getReturnType();
400+ if (returnType == void.class) { // optimization: handle void here
401+ desc.append('V');
402+ } else {
403+ desc.append(getTypeDescriptor(returnType));
404+ }
405+ return desc.toString();
406+ }
407+
408+ /**
409+ * Get the descriptor of a particular type, as appropriate for either
410+ * a parameter or return type in a method descriptor.
411+ */
412+ private static String getTypeDescriptor(Class type) {
413+ if (type.isPrimitive()) {
414+ if (type == int.class) {
415+ return "I";
416+ } else if (type == boolean.class) {
417+ return "Z";
418+ } else if (type == byte.class) {
419+ return "B";
420+ } else if (type == char.class) {
421+ return "C";
422+ } else if (type == short.class) {
423+ return "S";
424+ } else if (type == long.class) {
425+ return "J";
426+ } else if (type == float.class) {
427+ return "F";
428+ } else if (type == double.class) {
429+ return "D";
430+ } else if (type == void.class) {
431+ return "V";
432+ } else {
433+ throw new Error("unrecognized primitive type: " + type);
434+ }
435+ } else if (type.isArray()) {
436+ /*
437+ * According to JLS 20.3.2, the getName() method on Class does
438+ * return the VM type descriptor format for array classes (only);
439+ * using that should be quicker than the otherwise obvious code:
440+ *
441+ * return "[" + getTypeDescriptor(type.getComponentType());
442+ */
443+ return type.getName().replace('.', '/');
444+ } else {
445+ return "L" + type.getName().replace('.', '/') + ";";
446+ }
447+ }
448+
449+ /**
450+ * Returns the binary name of the given type without package
451+ * qualification. Nested types are treated no differently from
452+ * top-level types, so for a nested type, the returned name will
453+ * still be qualified with the simple name of its enclosing
454+ * top-level type (and perhaps other enclosing types), the
455+ * separator will be '$', etc.
456+ **/
457+ public static String getUnqualifiedName(Class c) {
458+ String binaryName = c.getName();
459+ return binaryName.substring(binaryName.lastIndexOf('.') + 1);
460+ }
461+}