001: /*
002: * Copyright 1996-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.rmi.transport;
027:
028: import java.rmi.server.UID;
029: import java.security.AccessController;
030: import java.util.ArrayList;
031: import java.util.Collections;
032: import java.util.HashMap;
033: import java.util.List;
034: import java.util.Map;
035: import java.util.concurrent.Future;
036: import java.util.concurrent.ScheduledExecutorService;
037: import java.util.concurrent.TimeUnit;
038: import sun.rmi.runtime.RuntimeUtil;
039: import sun.security.action.GetLongAction;
040:
041: /**
042: * Holds strong references to a set of remote objects, or live remote
043: * references to remote objects, after they have been marshalled (as
044: * remote references) as parts of the arguments or the result of a
045: * remote invocation. The purpose is to prevent remote objects or
046: * live remote references that might otherwise be determined to be
047: * unreachable in this VM from being locally garbage collected before
048: * the receiver has had an opportunity to register the unmarshalled
049: * remote references for DGC.
050: *
051: * The references are held strongly until an acknowledgment has been
052: * received that the receiver has had an opportunity to process the
053: * remote references or until a timeout has expired. For remote
054: * references sent as parts of the arguments of a remote invocation,
055: * the acknowledgment is the beginning of the response indicating
056: * completion of the remote invocation. For remote references sent as
057: * parts of the result of a remote invocation, a UID is included as
058: * part of the result, and the acknowledgment is a transport-level
059: * "DGCAck" message containing that UID.
060: *
061: * @author Ann Wollrath
062: * @author Peter Jones
063: * @version 1.26, 07/05/05
064: **/
065: public class DGCAckHandler {
066:
067: /** timeout for holding references without receiving an acknowledgment */
068: private static final long dgcAckTimeout = // default 5 minutes
069: AccessController.doPrivileged(new GetLongAction(
070: "sun.rmi.dgc.ackTimeout", 300000));
071:
072: /** thread pool for scheduling delayed tasks */
073: private static final ScheduledExecutorService scheduler = AccessController
074: .doPrivileged(new RuntimeUtil.GetInstanceAction())
075: .getScheduler();
076:
077: /** table mapping ack ID to handler */
078: private static final Map<UID, DGCAckHandler> idTable = Collections
079: .synchronizedMap(new HashMap<UID, DGCAckHandler>());
080:
081: private final UID id;
082: private List<Object> objList = new ArrayList<Object>(); // null if released
083: private Future<?> task = null;
084:
085: /**
086: * Creates a new DGCAckHandler, associated with the specified UID
087: * if the argument is not null.
088: *
089: * References added to this DGCAckHandler will be held strongly
090: * until its "release" method is invoked or (after the
091: * "startTimer" method has been invoked) the timeout has expired.
092: * If the argument is not null, then invoking the static
093: * "received" method with the specified UID is equivalent to
094: * invoking this instance's "release" method.
095: **/
096: DGCAckHandler(UID id) {
097: this .id = id;
098: if (id != null) {
099: assert !idTable.containsKey(id);
100: idTable.put(id, this );
101: }
102: }
103:
104: /**
105: * Adds the specified reference to this DGCAckHandler.
106: **/
107: synchronized void add(Object obj) {
108: if (objList != null) {
109: objList.add(obj);
110: }
111: }
112:
113: /**
114: * Starts the timer for this DGCAckHandler. After the timeout has
115: * expired, the references are released even if the acknowledgment
116: * has not been received.
117: **/
118: synchronized void startTimer() {
119: if (objList != null && task == null) {
120: task = scheduler.schedule(new Runnable() {
121: public void run() {
122: release();
123: }
124: }, dgcAckTimeout, TimeUnit.MILLISECONDS);
125: }
126: }
127:
128: /**
129: * Releases the references held by this DGCAckHandler.
130: **/
131: synchronized void release() {
132: if (task != null) {
133: task.cancel(false);
134: task = null;
135: }
136: objList = null;
137: }
138:
139: /**
140: * Causes the DGCAckHandler associated with the specified UID to
141: * release its references.
142: **/
143: public static void received(UID id) {
144: DGCAckHandler h = idTable.remove(id);
145: if (h != null) {
146: h.release();
147: }
148: }
149: }
|