mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
17.24.2013 70f4956fbfdf4f2a8e92dad53d4886a318261e7a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
 * or http://forgerock.org/license/CDDLv1.0.html.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at legal-notices/CDDLv1_0.txt.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *      Copyright 2013 ForgeRock AS.
 */
 
package com.forgerock.opendj.util;
 
/**
 * An object which is lazily created when first referenced, and destroyed when
 * the last reference is released.
 *
 * @param <T>
 *            The type of referenced object.
 */
public abstract class ReferenceCountedObject<T> {
 
    /**
     * A reference to the reference counted object which will automatically be
     * released during garbage collection.
     */
    public final class Reference {
        /*
         * The value will be accessed by the finalizer thread so it needs to be
         * volatile in order to ensure that updates are published.
         */
        private volatile T value;
 
        private Reference(final T value) {
            this.value = value;
        }
 
        /**
         * Returns the referenced object.
         *
         * @return The referenced object.
         * @throws NullPointerException
         *             If the referenced object has already been released.
         */
        public T get() {
            if (value == null) {
                throw new NullPointerException(); // Fail-fast.
            }
            return value;
        }
 
        /**
         * Decrements the reference count for the reference counted object if
         * this reference refers to the reference counted instance. If the
         * reference count drops to zero then the referenced object will be
         * destroyed.
         */
        public void release() {
            T instanceToRelease = null;
            synchronized (lock) {
                if (value != null && instance == value && --refCount == 0) {
                    instanceToRelease = value;
                    instance = null;
 
                    /*
                     * Force NPE for subsequent get() attempts and prevent
                     * multiple releases.
                     */
                    value = null;
                }
            }
 
            if (instanceToRelease != null) {
                destroyInstance(instanceToRelease);
            }
        }
 
        /**
         * Provide a finalizer because reference counting is intended for
         * expensive rarely created resources which should not be accidentally
         * left around.
         */
        @Override
        protected void finalize() {
            release();
        }
    }
 
    private T instance = null;
    private final Object lock = new Object();
    private int refCount = 0;
 
    /**
     * Creates a new referenced object whose reference count is initially zero.
     */
    protected ReferenceCountedObject() {
        // Nothing to do.
    }
 
    /**
     * Returns a reference to the reference counted object.
     *
     * @return A reference to the reference counted object.
     */
    public final Reference acquire() {
        synchronized (lock) {
            if (refCount++ == 0) {
                assert instance == null;
                instance = newInstance();
            }
            assert instance != null;
            return new Reference(instance);
        }
    }
 
    /**
     * Returns a reference to the provided object or, if it is {@code null}, a
     * reference to the reference counted object.
     *
     * @param value
     *            The object to be referenced, or {@code null} if the reference
     *            counted object should be used.
     * @return A reference to the provided object or, if it is {@code null}, a
     *         reference to the reference counted object.
     */
    public final Reference acquireIfNull(final T value) {
        return value != null ? new Reference(value) : acquire();
    }
 
    /**
     * Invoked when a reference is released and the reference count will become
     * zero. Implementations should release any resources associated with the
     * resource and should not return until the resources have been released.
     *
     * @param instance
     *            The instance to be destroyed.
     */
    protected abstract void destroyInstance(T instance);
 
    /**
     * Invoked when a reference is acquired and the current reference count is
     * zero. Implementations should create a new instance as fast as possible.
     *
     * @return The new instance.
     */
    protected abstract T newInstance();
 
}