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