KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > util > WeakReferenceMonitor


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.util;
18
19 import java.lang.ref.Reference JavaDoc;
20 import java.lang.ref.ReferenceQueue JavaDoc;
21 import java.lang.ref.WeakReference JavaDoc;
22 import java.util.Collections JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Map JavaDoc;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 /**
30  * Track references to arbitrary objects using proxy and weak references. To
31  * monitor a handle, one should call {@link #monitor(Object, ReleaseListener)},
32  * with the given handle object usually being a holder that uses the target
33  * object underneath, and the release listener performing cleanup of the
34  * target object once the handle is not strongly referenced anymore.
35  *
36  * <p>When a given handle becomes weakly reachable, the specified listener
37  * will be called by a background thread. This thread will only be started
38  * lazily and will be stopped once no handles are registered for monitoring
39  * anymore, to be restarted if further handles are added.
40  *
41  * <p>Thanks to Tomasz Wysocki for the suggestion and the original
42  * implementation of this class!
43  *
44  * @author Colin Sampaleanu
45  * @author Juergen Hoeller
46  * @since 1.2
47  * @see #monitor
48  */

49 public class WeakReferenceMonitor {
50
51     private static final Log logger = LogFactory.getLog(WeakReferenceMonitor.class);
52
53     // Queue receiving reachability events
54
private static final ReferenceQueue JavaDoc handleQueue = new ReferenceQueue JavaDoc();
55
56     // All tracked entries (WeakReference => ReleaseListener)
57
private static final Map JavaDoc trackedEntries = Collections.synchronizedMap(new HashMap JavaDoc());
58
59     // Thread polling handleQueue, lazy initialized
60
private static Thread JavaDoc monitoringThread = null;
61
62
63     /**
64      * Start to monitor given handle object for becoming weakly reachable.
65      * When the handle isn't used anymore, the given listener will be called.
66      * @param handle the object that will be monitored
67      * @param listener the listener that will be called upon release of the handle
68      */

69     public static void monitor(Object JavaDoc handle, ReleaseListener listener) {
70         if (logger.isDebugEnabled()) {
71             logger.debug("Monitoring handle [" + handle + "] with release listener [" + listener + "]");
72         }
73
74         // Make weak reference to this handle, so we can say when
75
// handle is not used any more by polling on handleQueue.
76
WeakReference JavaDoc weakRef = new WeakReference JavaDoc(handle, handleQueue);
77
78         // Add monitored entry to internal map of all monitored entries.
79
addEntry(weakRef, listener);
80     }
81
82     /**
83      * Add entry to internal map of tracked entries.
84      * Internal monitoring thread is started if not already running.
85      * @param ref reference to tracked handle
86      * @param entry the associated entry
87      */

88     private static void addEntry(Reference JavaDoc ref, ReleaseListener entry) {
89         // Add entry, the key is given reference.
90
trackedEntries.put(ref, entry);
91
92         // Start monitoring thread lazily.
93
synchronized (WeakReferenceMonitor.class) {
94             if (!isMonitoringThreadRunning()) {
95                 monitoringThread = new Thread JavaDoc(new MonitoringProcess(), WeakReferenceMonitor.class.getName());
96                 monitoringThread.setDaemon(true);
97                 monitoringThread.start();
98             }
99         }
100     }
101
102     /**
103      * Remove entry from internal map of tracked entries.
104      * @param reference the reference that should be removed
105      * @return entry object associated with given reference
106      */

107     private static ReleaseListener removeEntry(Reference JavaDoc reference) {
108         return (ReleaseListener) trackedEntries.remove(reference);
109     }
110
111     /**
112      * Check if monitoring thread is currently running.
113      */

114     private static boolean isMonitoringThreadRunning() {
115         synchronized (WeakReferenceMonitor.class) {
116             return (monitoringThread != null);
117         }
118     }
119
120
121     /**
122      * Thread implementation that performs the actual monitoring.
123      */

124     private static class MonitoringProcess implements Runnable JavaDoc {
125
126         public void run() {
127             logger.debug("Starting reference monitor thread");
128             try {
129                 // Check if there are any tracked entries left.
130
while (!trackedEntries.isEmpty()) {
131                     try {
132                         Reference JavaDoc reference = handleQueue.remove();
133                         // Stop tracking this reference.
134
ReleaseListener entry = removeEntry(reference);
135                         if (entry != null) {
136                             // Invoke listener callback.
137
entry.released();
138                         }
139                     }
140                     catch (InterruptedException JavaDoc ex) {
141                         logger.debug("Reference monitor thread interrupted", ex);
142                         break;
143                     }
144                 }
145             }
146             finally {
147                 logger.debug("Stopping reference monitor thread");
148                 synchronized (WeakReferenceMonitor.class) {
149                     monitoringThread = null;
150                 }
151             }
152         }
153     }
154
155
156     /**
157      * Listener that is notified when the handle is being released.
158      * To be implemented by users of this reference monitor.
159      */

160     public static interface ReleaseListener {
161
162         /**
163          * This callback method is invoked once the associated handle has been released,
164          * i.e. once there are no monitored strong references to the handle anymore.
165          */

166         void released();
167     }
168
169 }
170
Popular Tags