Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/sun/rmi/transport/Target.java
+++ new/src/share/classes/sun/rmi/transport/Target.java
1 1 /*
2 2 * Copyright (c) 1996, 2008, 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 package sun.rmi.transport;
26 26
27 27 import java.rmi.Remote;
28 28 import java.rmi.NoSuchObjectException;
29 29 import java.rmi.dgc.VMID;
30 30 import java.rmi.server.ObjID;
31 31 import java.rmi.server.Unreferenced;
32 32 import java.security.AccessControlContext;
33 33 import java.security.AccessController;
34 34 import java.util.*;
35 35 import sun.rmi.runtime.Log;
36 36 import sun.rmi.runtime.NewThreadAction;
37 37 import sun.rmi.server.Dispatcher;
38 38
39 39 /**
40 40 * A target contains information pertaining to a remote object that
41 41 * resides in this address space. Targets are located via the
42 42 * ObjectTable.
43 43 */
44 44 public final class Target {
45 45 /** object id for target */
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
46 46 private final ObjID id;
47 47 /** flag indicating whether target is subject to collection */
48 48 private final boolean permanent;
49 49 /** weak reference to remote object implementation */
50 50 private final WeakRef weakImpl;
51 51 /** dispatcher for remote object */
52 52 private volatile Dispatcher disp;
53 53 /** stub for remote object */
54 54 private final Remote stub;
55 55 /** set of clients that hold references to this target */
56 - private final Vector refSet = new Vector();
56 + private final Vector<VMID> refSet = new Vector<>();
57 57 /** table that maps client endpoints to sequence numbers */
58 - private final Hashtable sequenceTable = new Hashtable(5);
58 + private final Hashtable<VMID, SequenceEntry> sequenceTable =
59 + new Hashtable<>(5);
59 60 /** access control context in which target was created */
60 61 private final AccessControlContext acc;
61 62 /** context class loader in which target was created */
62 63 private final ClassLoader ccl;
63 64 /** number of pending/executing calls */
64 65 private int callCount = 0;
65 66 /** true if this target has been removed from the object table */
66 67 private boolean removed = false;
67 68 /**
68 69 * the transport through which this target was exported and
69 70 * through which remote calls will be allowed
70 71 */
71 72 private volatile Transport exportedTransport = null;
72 73
73 74 /** number to identify next callback thread created here */
74 75 private static int nextThreadNum = 0;
75 76
76 77 /**
77 78 * Construct a Target for a remote object "impl" with
78 79 * a specific object id.
79 80 *
80 81 * If "permanent" is true, then the impl is pinned permanently
81 82 * (the impl will not be collected via distributed and/or local
82 83 * GC). If "on" is false, than the impl is subject to
83 84 * collection. Permanent objects do not keep a server from
84 85 * exiting.
85 86 */
86 87 public Target(Remote impl, Dispatcher disp, Remote stub, ObjID id,
87 88 boolean permanent)
88 89 {
89 90 this.weakImpl = new WeakRef(impl, ObjectTable.reapQueue);
90 91 this.disp = disp;
91 92 this.stub = stub;
92 93 this.id = id;
93 94 this.acc = AccessController.getContext();
94 95
95 96 /*
96 97 * Fix for 4149366: so that downloaded parameter types unmarshalled
97 98 * for this impl will be compatible with types known only to the
98 99 * impl class's class loader (when it's not identical to the
99 100 * exporting thread's context class loader), mark the impl's class
100 101 * loader as the loader to use as the context class loader in the
101 102 * server's dispatch thread while a call to this impl is being
102 103 * processed (unless this exporting thread's context class loader is
103 104 * a child of the impl's class loader, such as when a registry is
104 105 * exported by an application, in which case this thread's context
105 106 * class loader is preferred).
106 107 */
107 108 ClassLoader threadContextLoader =
108 109 Thread.currentThread().getContextClassLoader();
109 110 ClassLoader serverLoader = impl.getClass().getClassLoader();
110 111 if (checkLoaderAncestry(threadContextLoader, serverLoader)) {
111 112 this.ccl = threadContextLoader;
112 113 } else {
113 114 this.ccl = serverLoader;
114 115 }
115 116
116 117 this.permanent = permanent;
117 118 if (permanent) {
118 119 pinImpl();
119 120 }
120 121 }
121 122
122 123 /**
123 124 * Return true if the first class loader is a child of (or identical
124 125 * to) the second class loader. Either loader may be "null", which is
125 126 * considered to be the parent of any non-null class loader.
126 127 *
127 128 * (utility method added for the 1.2beta4 fix for 4149366)
128 129 */
129 130 private static boolean checkLoaderAncestry(ClassLoader child,
130 131 ClassLoader ancestor)
131 132 {
132 133 if (ancestor == null) {
133 134 return true;
134 135 } else if (child == null) {
135 136 return false;
136 137 } else {
137 138 for (ClassLoader parent = child;
138 139 parent != null;
139 140 parent = parent.getParent())
140 141 {
141 142 if (parent == ancestor) {
142 143 return true;
143 144 }
144 145 }
145 146 return false;
146 147 }
147 148 }
148 149
149 150 /** Get the stub (proxy) object for this target
150 151 */
151 152 public Remote getStub() {
152 153 return stub;
153 154 }
154 155
155 156 /**
156 157 * Returns the object endpoint for the target.
157 158 */
158 159 ObjectEndpoint getObjectEndpoint() {
159 160 return new ObjectEndpoint(id, exportedTransport);
160 161 }
161 162
162 163 /**
163 164 * Get the weak reference for the Impl of this target.
164 165 */
165 166 WeakRef getWeakImpl() {
166 167 return weakImpl;
167 168 }
168 169
169 170 /**
170 171 * Returns the dispatcher for this remote object target.
171 172 */
172 173 Dispatcher getDispatcher() {
173 174 return disp;
174 175 }
175 176
176 177 AccessControlContext getAccessControlContext() {
177 178 return acc;
178 179 }
179 180
180 181 ClassLoader getContextClassLoader() {
181 182 return ccl;
182 183 }
183 184
184 185 /**
185 186 * Get the impl for this target.
186 187 * Note: this may return null if the impl has been garbage collected.
187 188 * (currently, there is no need to make this method public)
188 189 */
189 190 Remote getImpl() {
190 191 return (Remote)weakImpl.get();
191 192 }
192 193
193 194 /**
194 195 * Returns true if the target is permanent.
195 196 */
196 197 boolean isPermanent() {
197 198 return permanent;
198 199 }
199 200
200 201 /**
201 202 * Pin impl in target. Pin the WeakRef object so it holds a strong
202 203 * reference to the object to it will not be garbage collected locally.
203 204 * This way there is a single object responsible for the weak ref
204 205 * mechanism.
205 206 */
206 207 synchronized void pinImpl() {
207 208 weakImpl.pin();
208 209 }
209 210
210 211 /**
211 212 * Unpin impl in target. Weaken the reference to impl so that it
212 213 * can be garbage collected locally. But only if there the refSet
213 214 * is empty. All of the weak/strong handling is in WeakRef
214 215 */
215 216 synchronized void unpinImpl() {
216 217 /* only unpin if:
217 218 * a) impl is not permanent, and
218 219 * b) impl is not already unpinned, and
219 220 * c) there are no external references (outside this
220 221 * address space) for the impl
221 222 */
222 223 if (!permanent && refSet.isEmpty()) {
223 224 weakImpl.unpin();
224 225 }
225 226 }
226 227
227 228 /**
228 229 * Enable the transport through which remote calls to this target
229 230 * are allowed to be set if it has not already been set.
230 231 */
231 232 void setExportedTransport(Transport exportedTransport) {
232 233 if (this.exportedTransport == null) {
233 234 this.exportedTransport = exportedTransport;
↓ open down ↓ |
165 lines elided |
↑ open up ↑ |
234 235 }
235 236 }
236 237
237 238 /**
238 239 * Add an endpoint to the remembered set. Also adds a notifier
239 240 * to call back if the address space associated with the endpoint
240 241 * dies.
241 242 */
242 243 synchronized void referenced(long sequenceNum, VMID vmid) {
243 244 // check sequence number for vmid
244 - SequenceEntry entry = (SequenceEntry) sequenceTable.get(vmid);
245 + SequenceEntry entry = sequenceTable.get(vmid);
245 246 if (entry == null) {
246 247 sequenceTable.put(vmid, new SequenceEntry(sequenceNum));
247 248 } else if (entry.sequenceNum < sequenceNum) {
248 249 entry.update(sequenceNum);
249 250 } else {
250 251 // late dirty call; ignore.
251 252 return;
252 253 }
253 254
254 255 if (!refSet.contains(vmid)) {
255 256 /*
256 257 * A Target must be pinned while its refSet is not empty. It may
257 258 * have become unpinned if external LiveRefs only existed in
258 259 * serialized form for some period of time, or if a client failed
259 260 * to renew its lease due to a transient network failure. So,
260 261 * make sure that it is pinned here; this fixes bugid 4069644.
261 262 */
262 263 pinImpl();
263 264 if (getImpl() == null) // too late if impl was collected
264 265 return;
265 266
266 267 if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
267 268 DGCImpl.dgcLog.log(Log.VERBOSE, "add to dirty set: " + vmid);
268 269 }
269 270
270 271 refSet.addElement(vmid);
271 272
272 273 DGCImpl.getDGCImpl().registerTarget(vmid, this);
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
273 274 }
274 275 }
275 276
276 277 /**
277 278 * Remove endpoint from remembered set. If set becomes empty,
278 279 * remove server from Transport's object table.
279 280 */
280 281 synchronized void unreferenced(long sequenceNum, VMID vmid, boolean strong)
281 282 {
282 283 // check sequence number for vmid
283 - SequenceEntry entry = (SequenceEntry) sequenceTable.get(vmid);
284 + SequenceEntry entry = sequenceTable.get(vmid);
284 285 if (entry == null || entry.sequenceNum > sequenceNum) {
285 286 // late clean call; ignore
286 287 return;
287 288 } else if (strong) {
288 289 // strong clean call; retain sequenceNum
289 290 entry.retain(sequenceNum);
290 291 } else if (entry.keep == false) {
291 292 // get rid of sequence number
292 293 sequenceTable.remove(vmid);
293 294 }
294 295
295 296 if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
296 297 DGCImpl.dgcLog.log(Log.VERBOSE, "remove from dirty set: " + vmid);
297 298 }
298 299
299 300 refSetRemove(vmid);
300 301 }
301 302
302 303 /**
303 304 * Remove endpoint from the reference set.
304 305 */
305 306 synchronized private void refSetRemove(VMID vmid) {
306 307 // remove notification request
307 308 DGCImpl.getDGCImpl().unregisterTarget(vmid, this);
308 309
309 310 if (refSet.removeElement(vmid) && refSet.isEmpty()) {
310 311 // reference set is empty, so server can be garbage collected.
311 312 // remove object from table.
312 313 if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
313 314 DGCImpl.dgcLog.log(Log.VERBOSE,
314 315 "reference set is empty: target = " + this);
315 316 }
316 317
317 318 /*
318 319 * If the remote object implements the Unreferenced interface,
319 320 * invoke its unreferenced callback in a separate thread.
320 321 */
321 322 Remote obj = getImpl();
322 323 if (obj instanceof Unreferenced) {
323 324 final Unreferenced unrefObj = (Unreferenced) obj;
324 325 final Thread t =
325 326 java.security.AccessController.doPrivileged(
326 327 new NewThreadAction(new Runnable() {
327 328 public void run() {
328 329 unrefObj.unreferenced();
329 330 }
330 331 }, "Unreferenced-" + nextThreadNum++, false, true));
331 332 // REMIND: access to nextThreadNum not synchronized; you care?
332 333 /*
333 334 * We must manually set the context class loader appropriately
334 335 * for threads that may invoke user code (see bugid 4171278).
335 336 */
336 337 java.security.AccessController.doPrivileged(
337 338 new java.security.PrivilegedAction<Void>() {
338 339 public Void run() {
339 340 t.setContextClassLoader(ccl);
340 341 return null;
341 342 }
342 343 });
343 344
344 345 t.start();
345 346 }
346 347
347 348 unpinImpl();
348 349 }
349 350 }
350 351
351 352 /**
352 353 * Mark this target as not accepting new calls if any of the
353 354 * following conditions exist: a) the force parameter is true,
354 355 * b) the target's call count is zero, or c) the object is already
355 356 * not accepting calls. Returns true if target is marked as not
356 357 * accepting new calls; returns false otherwise.
357 358 */
358 359 synchronized boolean unexport(boolean force) {
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
359 360
360 361 if ((force == true) || (callCount == 0) || (disp == null)) {
361 362 disp = null;
362 363 /*
363 364 * Fix for 4331349: unpin object so that it may be gc'd.
364 365 * Also, unregister all vmids referencing this target
365 366 * so target can be gc'd.
366 367 */
367 368 unpinImpl();
368 369 DGCImpl dgc = DGCImpl.getDGCImpl();
369 - Enumeration enum_ = refSet.elements();
370 + Enumeration<VMID> enum_ = refSet.elements();
370 371 while (enum_.hasMoreElements()) {
371 - VMID vmid = (VMID) enum_.nextElement();
372 + VMID vmid = enum_.nextElement();
372 373 dgc.unregisterTarget(vmid, this);
373 374 }
374 375 return true;
375 376 } else {
376 377 return false;
377 378 }
378 379 }
379 380
380 381 /**
381 382 * Mark this target as having been removed from the object table.
382 383 */
383 384 synchronized void markRemoved() {
384 385 if (!(!removed)) { throw new AssertionError(); }
385 386
386 387 removed = true;
387 388 if (!permanent && callCount == 0) {
388 389 ObjectTable.decrementKeepAliveCount();
389 390 }
390 391
391 392 if (exportedTransport != null) {
392 393 exportedTransport.targetUnexported();
393 394 }
394 395 }
395 396
396 397 /**
397 398 * Increment call count.
398 399 */
399 400 synchronized void incrementCallCount() throws NoSuchObjectException {
400 401
401 402 if (disp != null) {
402 403 callCount ++;
403 404 } else {
404 405 throw new NoSuchObjectException("object not accepting new calls");
405 406 }
406 407 }
407 408
408 409 /**
409 410 * Decrement call count.
410 411 */
411 412 synchronized void decrementCallCount() {
412 413
413 414 if (--callCount < 0) {
414 415 throw new Error("internal error: call count less than zero");
415 416 }
416 417
417 418 /*
418 419 * The "keep-alive count" is the number of non-permanent remote
419 420 * objects that are either in the object table or still have calls
420 421 * in progress. Therefore, this state change may affect the
421 422 * keep-alive count: if this target is for a non-permanent remote
422 423 * object that has been removed from the object table and now has a
423 424 * call count of zero, it needs to be decremented.
424 425 */
425 426 if (!permanent && removed && callCount == 0) {
426 427 ObjectTable.decrementKeepAliveCount();
427 428 }
428 429 }
429 430
430 431 /**
431 432 * Returns true if remembered set is empty; otherwise returns
432 433 * false
433 434 */
434 435 boolean isEmpty() {
435 436 return refSet.isEmpty();
436 437 }
437 438
438 439 /**
439 440 * This method is called if the address space associated with the
440 441 * vmid dies. In that case, the vmid should be removed
441 442 * from the reference set.
442 443 */
443 444 synchronized public void vmidDead(VMID vmid) {
444 445 if (DGCImpl.dgcLog.isLoggable(Log.BRIEF)) {
445 446 DGCImpl.dgcLog.log(Log.BRIEF, "removing endpoint " +
446 447 vmid + " from reference set");
447 448 }
448 449
449 450 sequenceTable.remove(vmid);
450 451 refSetRemove(vmid);
451 452 }
452 453 }
453 454
454 455 class SequenceEntry {
455 456 long sequenceNum;
456 457 boolean keep;
457 458
458 459 SequenceEntry(long sequenceNum) {
459 460 this.sequenceNum = sequenceNum;
460 461 keep = false;
461 462 }
462 463
463 464 void retain(long sequenceNum) {
464 465 this.sequenceNum = sequenceNum;
465 466 keep = true;
466 467 }
467 468
468 469 void update(long sequenceNum) {
469 470 this.sequenceNum = sequenceNum;
470 471 }
471 472 }
↓ open down ↓ |
90 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX