J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package sun.rmi.transport; |
| 27 | |
| 28 | import java.rmi.server.UID; |
| 29 | import java.security.AccessController; |
| 30 | import java.util.ArrayList; |
| 31 | import java.util.Collections; |
| 32 | import java.util.HashMap; |
| 33 | import java.util.List; |
| 34 | import java.util.Map; |
| 35 | import java.util.concurrent.Future; |
| 36 | import java.util.concurrent.ScheduledExecutorService; |
| 37 | import java.util.concurrent.TimeUnit; |
| 38 | import sun.rmi.runtime.RuntimeUtil; |
| 39 | import sun.security.action.GetLongAction; |
| 40 | |
| 41 | /** |
| 42 | * Holds strong references to a set of remote objects, or live remote |
| 43 | * references to remote objects, after they have been marshalled (as |
| 44 | * remote references) as parts of the arguments or the result of a |
| 45 | * remote invocation. The purpose is to prevent remote objects or |
| 46 | * live remote references that might otherwise be determined to be |
| 47 | * unreachable in this VM from being locally garbage collected before |
| 48 | * the receiver has had an opportunity to register the unmarshalled |
| 49 | * remote references for DGC. |
| 50 | * |
| 51 | * The references are held strongly until an acknowledgment has been |
| 52 | * received that the receiver has had an opportunity to process the |
| 53 | * remote references or until a timeout has expired. For remote |
| 54 | * references sent as parts of the arguments of a remote invocation, |
| 55 | * the acknowledgment is the beginning of the response indicating |
| 56 | * completion of the remote invocation. For remote references sent as |
| 57 | * parts of the result of a remote invocation, a UID is included as |
| 58 | * part of the result, and the acknowledgment is a transport-level |
| 59 | * "DGCAck" message containing that UID. |
| 60 | * |
| 61 | * @author Ann Wollrath |
| 62 | * @author Peter Jones |
| 63 | **/ |
| 64 | public class DGCAckHandler { |
| 65 | |
| 66 | /** timeout for holding references without receiving an acknowledgment */ |
| 67 | private static final long dgcAckTimeout = // default 5 minutes |
| 68 | AccessController.doPrivileged( |
| 69 | new GetLongAction("sun.rmi.dgc.ackTimeout", 300000)); |
| 70 | |
| 71 | /** thread pool for scheduling delayed tasks */ |
| 72 | private static final ScheduledExecutorService scheduler = |
| 73 | AccessController.doPrivileged( |
| 74 | new RuntimeUtil.GetInstanceAction()).getScheduler(); |
| 75 | |
| 76 | /** table mapping ack ID to handler */ |
| 77 | private static final Map<UID,DGCAckHandler> idTable = |
| 78 | Collections.synchronizedMap(new HashMap<UID,DGCAckHandler>()); |
| 79 | |
| 80 | private final UID id; |
| 81 | private List<Object> objList = new ArrayList<Object>(); // null if released |
| 82 | private Future<?> task = null; |
| 83 | |
| 84 | /** |
| 85 | * Creates a new DGCAckHandler, associated with the specified UID |
| 86 | * if the argument is not null. |
| 87 | * |
| 88 | * References added to this DGCAckHandler will be held strongly |
| 89 | * until its "release" method is invoked or (after the |
| 90 | * "startTimer" method has been invoked) the timeout has expired. |
| 91 | * If the argument is not null, then invoking the static |
| 92 | * "received" method with the specified UID is equivalent to |
| 93 | * invoking this instance's "release" method. |
| 94 | **/ |
| 95 | DGCAckHandler(UID id) { |
| 96 | this.id = id; |
| 97 | if (id != null) { |
| 98 | assert !idTable.containsKey(id); |
| 99 | idTable.put(id, this); |
| 100 | } |
| 101 | } |
| 102 | |
| 103 | /** |
| 104 | * Adds the specified reference to this DGCAckHandler. |
| 105 | **/ |
| 106 | synchronized void add(Object obj) { |
| 107 | if (objList != null) { |
| 108 | objList.add(obj); |
| 109 | } |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Starts the timer for this DGCAckHandler. After the timeout has |
| 114 | * expired, the references are released even if the acknowledgment |
| 115 | * has not been received. |
| 116 | **/ |
| 117 | synchronized void startTimer() { |
| 118 | if (objList != null && task == null) { |
| 119 | task = scheduler.schedule(new Runnable() { |
| 120 | public void run() { |
| 121 | release(); |
| 122 | } |
| 123 | }, dgcAckTimeout, TimeUnit.MILLISECONDS); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * Releases the references held by this DGCAckHandler. |
| 129 | **/ |
| 130 | synchronized void release() { |
| 131 | if (task != null) { |
| 132 | task.cancel(false); |
| 133 | task = null; |
| 134 | } |
| 135 | objList = null; |
| 136 | } |
| 137 | |
| 138 | /** |
| 139 | * Causes the DGCAckHandler associated with the specified UID to |
| 140 | * release its references. |
| 141 | **/ |
| 142 | public static void received(UID id) { |
| 143 | DGCAckHandler h = idTable.remove(id); |
| 144 | if (h != null) { |
| 145 | h.release(); |
| 146 | } |
| 147 | } |
| 148 | } |