1/*
2 * Copyright (c) 1996, 2012, Oracle and/or its affiliates. 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25package sun.rmi.transport;
26
27import java.lang.ref.*;
28import sun.rmi.runtime.Log;
29
30/**
31 * WeakRef objects are used by the RMI runtime to hold potentially weak
32 * references to exported remote objects in the local object table.
33 *
34 * This class extends the functionality of java.lang.ref.WeakReference in
35 * several ways.  The methods pin() and unpin() can be used to set
36 * whether the contained reference is strong or weak (it is weak upon
37 * construction).  The hashCode() and equals() methods are overridden so
38 * that WeakRef objects hash and compare to each other according to the
39 * object identity of their referents.
40 *
41 * @author  Ann Wollrath
42 * @author  Peter Jones
43 */
44class WeakRef extends WeakReference<Object> {
45
46    /** value of the referent's "identity" hash code */
47    private int hashValue;
48
49    /** strong reference to the referent, for when this WeakRef is "pinned" */
50    private Object strongRef = null;
51
52    /**
53     * Create a new WeakRef to the given object.
54     */
55    public WeakRef(Object obj) {
56        super(obj);
57        setHashValue(obj);      // cache object's "identity" hash code
58    }
59
60    /**
61     * Create a new WeakRef to the given object, registered with a queue.
62     */
63    public WeakRef(Object obj, ReferenceQueue<Object> q) {
64        super(obj, q);
65        setHashValue(obj);      // cache object's "identity" hash code
66    }
67
68    /**
69     * Pin the contained reference (make this a strong reference).
70     */
71    public synchronized void pin() {
72        if (strongRef == null) {
73            strongRef = get();
74
75            if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
76                DGCImpl.dgcLog.log(Log.VERBOSE,
77                                   "strongRef = " + strongRef);
78            }
79        }
80    }
81
82    /**
83     * Unpin the contained reference (make this a weak reference).
84     */
85    public synchronized void unpin() {
86        if (strongRef != null) {
87            if (DGCImpl.dgcLog.isLoggable(Log.VERBOSE)) {
88                DGCImpl.dgcLog.log(Log.VERBOSE,
89                                   "strongRef = " + strongRef);
90            }
91
92            strongRef = null;
93        }
94    }
95
96    /*
97     * Cache referent's "identity" hash code (so that we still have the
98     * value after the referent gets cleared).
99     *
100     * We cannot use the value from the object's hashCode() method, since
101     * if the object is of a remote class not extended from RemoteObject
102     * and it is trying to implement hashCode() and equals() so that it
103     * can be compared to stub objects, its own hash code could not have
104     * been initialized yet (see bugid 4102938).  Also, object table keys
105     * based on server objects are indeed matched on object identity, so
106     * this is the correct hash technique regardless.
107     */
108    private void setHashValue(Object obj) {
109        if (obj != null) {
110            hashValue = System.identityHashCode(obj);
111        } else {
112            hashValue = 0;
113        }
114    }
115
116    /**
117     * Always return the "identity" hash code of the original referent.
118     */
119    public int hashCode() {
120        return hashValue;
121    }
122
123    /**
124     * Return true if "obj" is this identical WeakRef object, or, if the
125     * contained reference has not been cleared, if "obj" is another WeakRef
126     * object with the identical non-null referent.  Otherwise, return false.
127     */
128    public boolean equals(Object obj) {
129        if (obj instanceof WeakRef) {
130            if (obj == this)
131                return true;
132
133            Object referent = get();
134            return (referent != null) && (referent == ((WeakRef) obj).get());
135        } else {
136            return false;
137        }
138    }
139}
140