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/UnicastServerRef.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/rmi/server/UnicastServerRef.java+563−0
@@ -0,0 +1,563 @@
1+/*
2+ * Copyright (c) 1996, 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+
26+package sun.rmi.server;
27+
28+import java.io.IOException;
29+import java.io.ObjectInput;
30+import java.io.ObjectOutput;
31+import java.io.PrintStream;
32+import java.lang.reflect.InvocationTargetException;
33+import java.lang.reflect.Method;
34+import java.rmi.MarshalException;
35+import java.rmi.Remote;
36+import java.rmi.RemoteException;
37+import java.rmi.ServerError;
38+import java.rmi.ServerException;
39+import java.rmi.UnmarshalException;
40+import java.rmi.server.ExportException;
41+import java.rmi.server.RemoteCall;
42+import java.rmi.server.RemoteRef;
43+import java.rmi.server.RemoteStub;
44+import java.rmi.server.ServerNotActiveException;
45+import java.rmi.server.ServerRef;
46+import java.rmi.server.Skeleton;
47+import java.rmi.server.SkeletonNotFoundException;
48+import java.security.AccessController;
49+import java.security.PrivilegedAction;
50+import java.util.Collections;
51+import java.util.Date;
52+import java.util.HashMap;
53+import java.util.Map;
54+import java.util.WeakHashMap;
55+import sun.rmi.runtime.Log;
56+import sun.rmi.transport.LiveRef;
57+import sun.rmi.transport.Target;
58+import sun.rmi.transport.tcp.TCPTransport;
59+import sun.security.action.GetBooleanAction;
60+
61+/**
62+ * UnicastServerRef implements the remote reference layer server-side
63+ * behavior for remote objects exported with the "UnicastRef" reference
64+ * type.
65+ *
66+ * @author Ann Wollrath
67+ * @author Roger Riggs
68+ * @author Peter Jones
69+ */
70+public class UnicastServerRef extends UnicastRef
71+ implements ServerRef, Dispatcher
72+{
73+ /** value of server call log property */
74+ public static final boolean logCalls = AccessController.doPrivileged(
75+ new GetBooleanAction("java.rmi.server.logCalls"));
76+
77+ /** server call log */
78+ public static final Log callLog =
79+ Log.getLog("sun.rmi.server.call", "RMI", logCalls);
80+
81+ // use serialVersionUID from JDK 1.2.2 for interoperability
82+ private static final long serialVersionUID = -7384275867073752268L;
83+
84+ /** flag to enable writing exceptions to System.err */
85+ private static final boolean wantExceptionLog =
86+ AccessController.doPrivileged(
87+ new GetBooleanAction("sun.rmi.server.exceptionTrace"));
88+
89+ private boolean forceStubUse = false;
90+
91+ /**
92+ * flag to remove server-side stack traces before marshalling
93+ * exceptions thrown by remote invocations to this VM
94+ */
95+ private static final boolean suppressStackTraces =
96+ AccessController.doPrivileged(
97+ new GetBooleanAction(
98+ "sun.rmi.server.suppressStackTraces"));
99+
100+ /**
101+ * skeleton to dispatch remote calls through, for 1.1 stub protocol
102+ * (may be null if stub class only uses 1.2 stub protocol)
103+ */
104+ private transient Skeleton skel;
105+
106+ /** maps method hash to Method object for each remote method */
107+ private transient Map<Long,Method> hashToMethod_Map = null;
108+
109+ /**
110+ * A weak hash map, mapping classes to hash maps that map method
111+ * hashes to method objects.
112+ **/
113+ private static final WeakClassHashMap<Map<Long,Method>> hashToMethod_Maps =
114+ new HashToMethod_Maps();
115+
116+ /** cache of impl classes that have no corresponding skeleton class */
117+ private static final Map<Class<?>,?> withoutSkeletons =
118+ Collections.synchronizedMap(new WeakHashMap<Class<?>,Void>());
119+
120+ /**
121+ * Create a new (empty) Unicast server remote reference.
122+ */
123+ public UnicastServerRef() {
124+ }
125+
126+ /**
127+ * Construct a Unicast server remote reference for a specified
128+ * liveRef.
129+ */
130+ public UnicastServerRef(LiveRef ref) {
131+ super(ref);
132+ }
133+
134+ /**
135+ * Construct a Unicast server remote reference to be exported
136+ * on the specified port.
137+ */
138+ public UnicastServerRef(int port) {
139+ super(new LiveRef(port));
140+ }
141+
142+ /**
143+ * Constructs a UnicastServerRef to be exported on an
144+ * anonymous port (i.e., 0) and that uses a pregenerated stub class
145+ * (NOT a dynamic proxy instance) if 'forceStubUse' is 'true'.
146+ *
147+ * This constructor is only called by the method
148+ * UnicastRemoteObject.exportObject(Remote) passing 'true' for
149+ * 'forceStubUse'. The UnicastRemoteObject.exportObject(Remote) method
150+ * returns RemoteStub, so it must ensure that the stub for the
151+ * exported object is an instance of a pregenerated stub class that
152+ * extends RemoteStub (instead of an instance of a dynamic proxy class
153+ * which is not an instance of RemoteStub).
154+ **/
155+ public UnicastServerRef(boolean forceStubUse) {
156+ this(0);
157+ this.forceStubUse = forceStubUse;
158+ }
159+
160+ /**
161+ * With the addition of support for dynamic proxies as stubs, this
162+ * method is obsolete because it returns RemoteStub instead of the more
163+ * general Remote. It should not be called. It sets the
164+ * 'forceStubUse' flag to true so that the stub for the exported object
165+ * is forced to be an instance of the pregenerated stub class, which
166+ * extends RemoteStub.
167+ *
168+ * Export this object, create the skeleton and stubs for this
169+ * dispatcher. Create a stub based on the type of the impl,
170+ * initialize it with the appropriate remote reference. Create the
171+ * target defined by the impl, dispatcher (this) and stub.
172+ * Export that target via the Ref.
173+ **/
174+ public RemoteStub exportObject(Remote impl, Object data)
175+ throws RemoteException
176+ {
177+ forceStubUse = true;
178+ return (RemoteStub) exportObject(impl, data, false);
179+ }
180+
181+ /**
182+ * Export this object, create the skeleton and stubs for this
183+ * dispatcher. Create a stub based on the type of the impl,
184+ * initialize it with the appropriate remote reference. Create the
185+ * target defined by the impl, dispatcher (this) and stub.
186+ * Export that target via the Ref.
187+ */
188+ public Remote exportObject(Remote impl, Object data,
189+ boolean permanent)
190+ throws RemoteException
191+ {
192+ Class implClass = impl.getClass();
193+ Remote stub;
194+
195+ try {
196+ stub = Util.createProxy(implClass, getClientRef(), forceStubUse);
197+ } catch (IllegalArgumentException e) {
198+ throw new ExportException(
199+ "remote object implements illegal remote interface", e);
200+ }
201+ if (stub instanceof RemoteStub) {
202+ setSkeleton(impl);
203+ }
204+
205+ Target target =
206+ new Target(impl, this, stub, ref.getObjID(), permanent);
207+ ref.exportObject(target);
208+ hashToMethod_Map = hashToMethod_Maps.get(implClass);
209+ return stub;
210+ }
211+
212+ /**
213+ * Return the hostname of the current client. When called from a
214+ * thread actively handling a remote method invocation the
215+ * hostname of the client is returned.
216+ * @exception ServerNotActiveException If called outside of servicing
217+ * a remote method invocation.
218+ */
219+ public String getClientHost() throws ServerNotActiveException {
220+ return TCPTransport.getClientHost();
221+ }
222+
223+ /**
224+ * Discovers and sets the appropriate skeleton for the impl.
225+ */
226+ public void setSkeleton(Remote impl) throws RemoteException {
227+ if (!withoutSkeletons.containsKey(impl.getClass())) {
228+ try {
229+ skel = Util.createSkeleton(impl);
230+ } catch (SkeletonNotFoundException e) {
231+ /*
232+ * Ignore exception for skeleton class not found, because a
233+ * skeleton class is not necessary with the 1.2 stub protocol.
234+ * Remember that this impl's class does not have a skeleton
235+ * class so we don't waste time searching for it again.
236+ */
237+ withoutSkeletons.put(impl.getClass(), null);
238+ }
239+ }
240+ }
241+
242+ /**
243+ * Call to dispatch to the remote object (on the server side).
244+ * The up-call to the server and the marshalling of return result
245+ * (or exception) should be handled before returning from this
246+ * method.
247+ * @param obj the target remote object for the call
248+ * @param call the "remote call" from which operation and
249+ * method arguments can be obtained.
250+ * @exception IOException If unable to marshal return result or
251+ * release input or output streams
252+ */
253+ public void dispatch(Remote obj, RemoteCall call) throws IOException {
254+ // positive operation number in 1.1 stubs;
255+ // negative version number in 1.2 stubs and beyond...
256+ int num;
257+ long op;
258+
259+ try {
260+ // read remote call header
261+ ObjectInput in;
262+ try {
263+ in = call.getInputStream();
264+ num = in.readInt();
265+ if (num >= 0) {
266+ if (skel != null) {
267+ oldDispatch(obj, call, num);
268+ return;
269+ } else {
270+ throw new UnmarshalException(
271+ "skeleton class not found but required " +
272+ "for client version");
273+ }
274+ }
275+ op = in.readLong();
276+ } catch (Exception readEx) {
277+ throw new UnmarshalException("error unmarshalling call header",
278+ readEx);
279+ }
280+
281+ /*
282+ * Since only system classes (with null class loaders) will be on
283+ * the execution stack during parameter unmarshalling for the 1.2
284+ * stub protocol, tell the MarshalInputStream not to bother trying
285+ * to resolve classes using its superclasses's default method of
286+ * consulting the first non-null class loader on the stack.
287+ */
288+ MarshalInputStream marshalStream = (MarshalInputStream) in;
289+ marshalStream.skipDefaultResolveClass();
290+
291+ Method method = hashToMethod_Map.get(op);
292+ if (method == null) {
293+ throw new UnmarshalException("unrecognized method hash: " +
294+ "method not supported by remote object");
295+ }
296+
297+ // if calls are being logged, write out object id and operation
298+ logCall(obj, method);
299+
300+ // unmarshal parameters
301+ Class[] types = method.getParameterTypes();
302+ Object[] params = new Object[types.length];
303+
304+ try {
305+ unmarshalCustomCallData(in);
306+ for (int i = 0; i < types.length; i++) {
307+ params[i] = unmarshalValue(types[i], in);
308+ }
309+ } catch (java.io.IOException e) {
310+ throw new UnmarshalException(
311+ "error unmarshalling arguments", e);
312+ } catch (ClassNotFoundException e) {
313+ throw new UnmarshalException(
314+ "error unmarshalling arguments", e);
315+ } finally {
316+ call.releaseInputStream();
317+ }
318+
319+ // make upcall on remote object
320+ Object result;
321+ try {
322+ result = method.invoke(obj, params);
323+ } catch (InvocationTargetException e) {
324+ throw e.getTargetException();
325+ }
326+
327+ // marshal return value
328+ try {
329+ ObjectOutput out = call.getResultStream(true);
330+ Class rtype = method.getReturnType();
331+ if (rtype != void.class) {
332+ marshalValue(rtype, result, out);
333+ }
334+ } catch (IOException ex) {
335+ throw new MarshalException("error marshalling return", ex);
336+ /*
337+ * This throw is problematic because when it is caught below,
338+ * we attempt to marshal it back to the client, but at this
339+ * point, a "normal return" has already been indicated,
340+ * so marshalling an exception will corrupt the stream.
341+ * This was the case with skeletons as well; there is no
342+ * immediately obvious solution without a protocol change.
343+ */
344+ }
345+ } catch (Throwable e) {
346+ logCallException(e);
347+
348+ ObjectOutput out = call.getResultStream(false);
349+ if (e instanceof Error) {
350+ e = new ServerError(
351+ "Error occurred in server thread", (Error) e);
352+ } else if (e instanceof RemoteException) {
353+ e = new ServerException(
354+ "RemoteException occurred in server thread",
355+ (Exception) e);
356+ }
357+ if (suppressStackTraces) {
358+ clearStackTraces(e);
359+ }
360+ out.writeObject(e);
361+ } finally {
362+ call.releaseInputStream(); // in case skeleton doesn't
363+ call.releaseOutputStream();
364+ }
365+ }
366+
367+ protected void unmarshalCustomCallData(ObjectInput in)
368+ throws IOException, ClassNotFoundException
369+ {}
370+
371+ /**
372+ * Handle server-side dispatch using the RMI 1.1 stub/skeleton
373+ * protocol, given a non-negative operation number that has
374+ * already been read from the call stream.
375+ *
376+ * @param obj the target remote object for the call
377+ * @param call the "remote call" from which operation and
378+ * method arguments can be obtained.
379+ * @param op the operation number
380+ * @exception IOException if unable to marshal return result or
381+ * release input or output streams
382+ */
383+ public void oldDispatch(Remote obj, RemoteCall call, int op)
384+ throws IOException
385+ {
386+ long hash; // hash for matching stub with skeleton
387+
388+ try {
389+ // read remote call header
390+ ObjectInput in;
391+ try {
392+ in = call.getInputStream();
393+ hash = in.readLong();
394+ } catch (Exception readEx) {
395+ throw new UnmarshalException("error unmarshalling call header",
396+ readEx);
397+ }
398+
399+ // if calls are being logged, write out object id and operation
400+ logCall(obj, skel.getOperations()[op]);
401+ unmarshalCustomCallData(in);
402+ // dispatch to skeleton for remote object
403+ skel.dispatch(obj, call, op, hash);
404+
405+ } catch (Throwable e) {
406+ logCallException(e);
407+
408+ ObjectOutput out = call.getResultStream(false);
409+ if (e instanceof Error) {
410+ e = new ServerError(
411+ "Error occurred in server thread", (Error) e);
412+ } else if (e instanceof RemoteException) {
413+ e = new ServerException(
414+ "RemoteException occurred in server thread",
415+ (Exception) e);
416+ }
417+ if (suppressStackTraces) {
418+ clearStackTraces(e);
419+ }
420+ out.writeObject(e);
421+ } finally {
422+ call.releaseInputStream(); // in case skeleton doesn't
423+ call.releaseOutputStream();
424+ }
425+ }
426+
427+ /**
428+ * Clear the stack trace of the given Throwable by replacing it with
429+ * an empty StackTraceElement array, and do the same for all of its
430+ * chained causative exceptions.
431+ */
432+ public static void clearStackTraces(Throwable t) {
433+ StackTraceElement[] empty = new StackTraceElement[0];
434+ while (t != null) {
435+ t.setStackTrace(empty);
436+ t = t.getCause();
437+ }
438+ }
439+
440+ /**
441+ * Log the details of an incoming call. The method parameter is either of
442+ * type java.lang.reflect.Method or java.rmi.server.Operation.
443+ */
444+ private void logCall(Remote obj, Object method) {
445+ if (callLog.isLoggable(Log.VERBOSE)) {
446+ String clientHost;
447+ try {
448+ clientHost = getClientHost();
449+ } catch (ServerNotActiveException snae) {
450+ clientHost = "(local)"; // shouldn't happen
451+ }
452+ callLog.log(Log.VERBOSE, "[" + clientHost + ": " +
453+ obj.getClass().getName() +
454+ ref.getObjID().toString() + ": " +
455+ method + "]");
456+ }
457+ }
458+
459+ /**
460+ * Log the exception detail of an incoming call.
461+ */
462+ private void logCallException(Throwable e) {
463+ // if calls are being logged, log them
464+ if (callLog.isLoggable(Log.BRIEF)) {
465+ String clientHost = "";
466+ try {
467+ clientHost = "[" + getClientHost() + "] ";
468+ } catch (ServerNotActiveException snae) {
469+ }
470+ callLog.log(Log.BRIEF, clientHost + "exception: ", e);
471+ }
472+
473+ // write exceptions (only) to System.err if desired
474+ if (wantExceptionLog) {
475+ java.io.PrintStream log = System.err;
476+ synchronized (log) {
477+ log.println();
478+ log.println("Exception dispatching call to " +
479+ ref.getObjID() + " in thread \"" +
480+ Thread.currentThread().getName() +
481+ "\" at " + (new Date()) + ":");
482+ e.printStackTrace(log);
483+ }
484+ }
485+ }
486+
487+ /**
488+ * Returns the class of the ref type to be serialized.
489+ */
490+ public String getRefClass(ObjectOutput out) {
491+ return "UnicastServerRef";
492+ }
493+
494+ /**
495+ * Return the client remote reference for this remoteRef.
496+ * In the case of a client RemoteRef "this" is the answer.
497+ * For a server remote reference, a client side one will have to
498+ * found or created.
499+ */
500+ protected RemoteRef getClientRef() {
501+ return new UnicastRef(ref);
502+ }
503+
504+ /**
505+ * Write out external representation for remote ref.
506+ */
507+ public void writeExternal(ObjectOutput out) throws IOException {
508+ }
509+
510+ /**
511+ * Read in external representation for remote ref.
512+ * @exception ClassNotFoundException If the class for an object
513+ * being restored cannot be found.
514+ */
515+ public void readExternal(ObjectInput in)
516+ throws IOException, ClassNotFoundException
517+ {
518+ // object is re-exported elsewhere (e.g., by UnicastRemoteObject)
519+ ref = null;
520+ skel = null;
521+ }
522+
523+
524+ /**
525+ * A weak hash map, mapping classes to hash maps that map method
526+ * hashes to method objects.
527+ **/
528+ private static class HashToMethod_Maps
529+ extends WeakClassHashMap<Map<Long,Method>>
530+ {
531+ HashToMethod_Maps() {}
532+
533+ protected Map<Long,Method> computeValue(Class<?> remoteClass) {
534+ Map<Long,Method> map = new HashMap<Long,Method>();
535+ for (Class<?> cl = remoteClass;
536+ cl != null;
537+ cl = cl.getSuperclass())
538+ {
539+ for (Class<?> intf : cl.getInterfaces()) {
540+ if (Remote.class.isAssignableFrom(intf)) {
541+ for (Method method : intf.getMethods()) {
542+ final Method m = method;
543+ /*
544+ * Set this Method object to override language
545+ * access checks so that the dispatcher can invoke
546+ * methods from non-public remote interfaces.
547+ */
548+ AccessController.doPrivileged(
549+ new PrivilegedAction<Void>() {
550+ public Void run() {
551+ m.setAccessible(true);
552+ return null;
553+ }
554+ });
555+ map.put(Util.computeMethodHash(m), m);
556+ }
557+ }
558+ }
559+ }
560+ return map;
561+ }
562+ }
563+}