001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.server;
023:
024: import java.rmi.Remote;
025: import java.rmi.dgc.VMID;
026: import java.rmi.server.ObjID;
027: import java.rmi.server.Unreferenced;
028: import java.security.AccessController;
029: import java.security.AccessControlContext;
030: import java.security.PrivilegedAction;
031: import java.util.Hashtable;
032:
033: import org.apache.harmony.rmi.common.CreateThreadAction;
034: import org.apache.harmony.rmi.common.RMIUtil;
035: import org.apache.harmony.rmi.remoteref.UnicastServerRef;
036:
037: /**
038: * Holds info characterizing exported remote objects.
039: *
040: * @author Mikhail A. Markov
041: * @version $Revision: 1.1.2.2 $
042: */
043: final class RMIObjectInfo {
044:
045: // Reference to remote object.
046: final RMIReference ref;
047:
048: // Object ID for remote object.
049: final ObjID id;
050:
051: // Stub for remote object.
052: final Remote stub;
053:
054: // Server handle for remote object
055: final UnicastServerRef sref;
056:
057: // AccessControlContext when this Info was created
058: final AccessControlContext acc;
059:
060: // ClassLoader for dispatching calls.
061: final ClassLoader loader;
062:
063: // Table where VMIDs are keys and DGCExpirationInfos are values
064: final Hashtable vmidTable = new Hashtable();
065:
066: /*
067: * Table of VMID's remembered after DGC.clean() call with strong=true.
068: * VMIDs are keys and Long() representing sequence numbers are values.
069: */
070: final Hashtable rememberedTable = new Hashtable();
071:
072: /*
073: * Constructs RemoteObjectInfo holding the specified information.
074: * The ClassLoader for dispatching calls is chosen using the following
075: * rules:
076: * 1) If current thread context ClassLoader is null, then ClassLoader
077: * which loads Class of remote object will be the ClassLoader for
078: * dispatching calls
079: * 2) If ClassLoader which loads Class of remote object is null, then
080: * current thread context ClassLoader will be the ClassLoader for
081: * dispatching calls
082: * 3) If context ClassLoader of the current thread is equal/parent
083: * of the ClassLoader which loads Class of remote object, then
084: * current thread context ClassLoader will be the ClassLoader for for
085: * dispatching calls.
086: * 4) Otherwise ClassLoader which loads Class of remote object will
087: * be the ClassLoader fo dispatching calls.
088: *
089: * @param ref reference to remote object
090: * @param id Object ID for remote object
091: * @param sref UnicastServerRef for dispatching remote calls
092: * @param stub stub for remote object
093: */
094: RMIObjectInfo(RMIReference ref, ObjID id, UnicastServerRef sref,
095: Remote stub) {
096: this .ref = ref;
097: this .id = id;
098: this .sref = sref;
099: this .stub = stub;
100: acc = AccessController.getContext();
101: ClassLoader objCl = ref.get().getClass().getClassLoader();
102: ClassLoader threadCl = Thread.currentThread()
103: .getContextClassLoader();
104:
105: if (threadCl == null) {
106: loader = objCl;
107: } else if (objCl == null
108: || RMIUtil.isParentLoader(threadCl, objCl)) {
109: loader = threadCl;
110: } else {
111: loader = objCl;
112: }
113: }
114:
115: /*
116: * Called by DGC to signal that dirty call received to the object with
117: * such ObjID.
118: */
119: void dgcDirty(VMID vmid, long seqNum, long duration) {
120: synchronized (vmidTable) {
121: DGCExpirationInfo info = (DGCExpirationInfo) vmidTable
122: .get(vmid);
123:
124: if (info != null && info.seqNum >= seqNum) {
125: return;
126: }
127: Long l = (Long) rememberedTable.get(vmid);
128:
129: if (l != null) {
130: if (l.longValue() > seqNum) {
131: return;
132: } else {
133: rememberedTable.remove(vmid);
134: }
135: }
136: ref.makeStrong(true);
137: vmidTable
138: .put(vmid, new DGCExpirationInfo(duration, seqNum));
139: }
140: }
141:
142: /*
143: * Called by DGC to signal that clean call received to the object with
144: * such ObjID.
145: */
146: boolean dgcClean(VMID vmid, long seqNum, boolean strong) {
147: synchronized (vmidTable) {
148: DGCExpirationInfo info = (DGCExpirationInfo) vmidTable
149: .get(vmid);
150:
151: if (info != null && info.seqNum >= seqNum) {
152: return false;
153: }
154: vmidTable.remove(vmid);
155:
156: if (strong) {
157: Long l = (Long) rememberedTable.get(vmid);
158:
159: if (l != null && l.longValue() > seqNum) {
160: return true;
161: }
162: rememberedTable.put(vmid, new Long(seqNum));
163: }
164:
165: if (vmidTable.isEmpty()) {
166: unreferenced();
167: }
168: return true;
169: }
170: }
171:
172: /*
173: * Called by DGC to verify if the given VMID reference expired.
174: */
175: boolean dgcClean(VMID vmid) {
176: synchronized (vmidTable) {
177: DGCExpirationInfo info = (DGCExpirationInfo) vmidTable
178: .get(vmid);
179:
180: if (info != null
181: && info.expTime > System.currentTimeMillis()) {
182: return false;
183: }
184: vmidTable.remove(vmid);
185:
186: if (vmidTable.isEmpty()) {
187: unreferenced();
188: }
189: return true;
190: }
191: }
192:
193: /*
194: * Spawn thread calling unreferenced() method of the object to be
195: * unreferenced and makes the reference to the object as weak.
196: */
197: private synchronized void unreferenced() {
198: final Object obj = ref.get();
199:
200: if (obj instanceof Unreferenced) {
201: /*
202: * Spawn unreferenced thread.
203: * Start this thread with setDaemon(false) to protect VM
204: * from exiting while unreferencing the object.
205: * The thread is started in non-system group
206: * (see comment for CreateThreadAction class).
207: */
208: Thread uThread = ((Thread) AccessController
209: .doPrivileged(new CreateThreadAction(
210: new Runnable() {
211: public void run() {
212: AccessController.doPrivileged(
213: new PrivilegedAction() {
214: public Object run() {
215: ((Unreferenced) obj)
216: .unreferenced();
217: return null;
218: }
219: }, acc);
220: }
221: }, "Unreferenced", false, false))); //$NON-NLS-1$
222: uThread.setContextClassLoader(loader);
223: uThread.start();
224: }
225: ref.makeStrong(false);
226: }
227:
228: /*
229: * Auxiliary class holding expiration time and sequence number when
230: * this expiration was created.
231: */
232: private static class DGCExpirationInfo {
233: // Expiration time in ms.
234: long expTime;
235:
236: // Sequence number.
237: long seqNum;
238:
239: /*
240: * Constructs an empty DGCExpirationInfo.
241: */
242: DGCExpirationInfo() {
243: }
244:
245: /*
246: * Constructs ExpirationInfo class from the given duration and
247: * sequence number.
248: *
249: * @param duration time period after which this entry expires
250: * @param seqNumber Sequence number to handle consecutive calls
251: */
252: DGCExpirationInfo(long duration, long seqNum) {
253: this.expTime = System.currentTimeMillis() + duration;
254: this.seqNum = seqNum;
255: }
256: }
257: }
|