001 /* 002 003 ============================================================================ 004 The Apache Software License, Version 1.1 005 ============================================================================ 006 007 Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved. 008 009 Redistribution and use in source and binary forms, with or without modifica- 010 tion, are permitted provided that the following conditions are met: 011 012 1. Redistributions of source code must retain the above copyright notice, 013 this list of conditions and the following disclaimer. 014 015 2. Redistributions in binary form must reproduce the above copyright notice, 016 this list of conditions and the following disclaimer in the documentation 017 and/or other materials provided with the distribution. 018 019 3. The end-user documentation included with the redistribution, if any, must 020 include the following acknowledgment: "This product includes software 021 developed by the Apache Software Foundation (http://www.apache.org/)." 022 Alternately, this acknowledgment may appear in the software itself, if 023 and wherever such third-party acknowledgments normally appear. 024 025 4. The names "Batik" and "Apache Software Foundation" must not be 026 used to endorse or promote products derived from this software without 027 prior written permission. For written permission, please contact 028 apache@apache.org. 029 030 5. Products derived from this software may not be called "Apache", nor may 031 "Apache" appear in their name, without prior written permission of the 032 Apache Software Foundation. 033 034 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, 035 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 036 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 037 APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 038 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- 039 DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 040 OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 041 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 042 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 043 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 044 045 This software consists of voluntary contributions made by many individuals 046 on behalf of the Apache Software Foundation. For more information on the 047 Apache Software Foundation, please see <http://www.apache.org/>. 048 049 */ 050 051 package org.apache.batik.util; 052 053 import java.lang.ref.SoftReference; 054 import java.util.HashMap; 055 056 /** 057 * This class manages a cache of soft references to objects that may 058 * take some time to load or create, such as images loaded from the 059 * network. 060 * 061 * Adding an object is two fold: <br /> 062 * + First you add the key, this lets the cache know that someone is 063 * working on that key. <br /> 064 * + Then when the completed object is ready you put it into the cache.<P> 065 * 066 * If someone requests a key after it has been added but before it has 067 * been put they will be blocked until the put. 068 */ 069 070 public class SoftReferenceCache { 071 HashMap map = new HashMap(); 072 073 /** 074 * Let people create there own caches. 075 */ 076 protected SoftReferenceCache() { } 077 078 079 /** 080 * Let people flush the cache (remove any cached data). Pending 081 * requests will be treated as though clear() was called on the 082 * key, this should cause them to go and re-read the data. 083 */ 084 public synchronized void flush() { 085 map.clear(); 086 this.notifyAll(); 087 } 088 089 /** 090 * Check if <tt>request(key)</tt> will return with an Object 091 * (not putting you on the hook for it). Note that it is possible 092 * that this will return true but between this call and the call 093 * to request the soft-reference will be cleared. So it 094 * is still possible for request to return NULL, just much less 095 * likely (you can always call 'clear' in that case). 096 */ 097 protected final synchronized boolean isPresentImpl(Object key) { Rate098 if (!map.containsKey(key)) 099 return false; 100 101 Object o = map.get(key); 102 if (o == null) 103 // It's been requested but hasn't been 'put' yet. 104 return true; 105 106 // It's been put let's make sure the soft reference hasn't 107 // been cleared. 108 SoftReference sr = (SoftReference)o; 109 o = sr.get(); 110 if (o != null) 111 return true; 112 113 // Soft reference was cleared, so remove our record of key. 114 clearImpl(key); 115 return false; 116 } 117 118 /** 119 * Check if <tt>request(key)</tt> will return immediately with the 120 * Object. Note that it is possible that this will return 121 * true but between this call and the call to request the 122 * soft-reference will be cleared. 123 */ 124 protected final synchronized boolean isDoneImpl(Object key) { 125 Object o = map.get(key); 126 if (o == null) return false; 127 SoftReference sr = (SoftReference)o; 128 o = sr.get(); 129 if (o != null) 130 return true; 131 132 // Soft reference was cleared 133 clearImpl(key); 134 return false; 135 } 136 137 /** 138 * If this returns null then you are now 'on the hook'. 139 * to put the Object associated with key into the 140 * cache. */ 141 protected final synchronized Object requestImpl(Object key) { Rate142 if (map.containsKey(key)) { 143 144 Object o = map.get(key); 145 while(o == null) { 146 try { 147 // When something is cleared or put we will be notified. 148 wait(); 149 } 150 catch (InterruptedException ie) { } 151 152 // check if key was cleared, if so it will most likely 153 // never be 'put'. Rate154 if (!map.containsKey(key)) 155 break; 156 157 // Let's see if it was put... 158 o = map.get(key); 159 } 160 if (o != null) { 161 SoftReference sr = (SoftReference)o; 162 o = sr.get(); 163 if (o != null) 164 return o; 165 } 166 } 167 168 // So now the caller get's the hot potato. 169 map.put(key, null); 170 return null; 171 } 172 173 /** 174 * Clear the entry for key. 175 * This is the easiest way to 'get off the hook'. 176 * if you didn't indend to get on it. 177 */ 178 protected final synchronized void clearImpl(Object key) { 179 map.remove(key); 180 this.notifyAll(); 181 } 182 183 /** 184 * Associate object with key. 'object' is only referenced through 185 * a soft reference so don't rely on the cache to keep it 186 * around. If the map no longer contains our url it was 187 * probably cleared or flushed since we were put on the hook 188 * for it, so in that case we will do nothing. 189 */ 190 protected final synchronized void putImpl(Object key, Object object) { Rate191 if (map.containsKey(key)) { 192 SoftReference ref = new SoftRefKey(object, key); 193 map.put(key, ref); 194 this.notifyAll(); 195 } 196 } 197 198 class SoftRefKey extends CleanerThread.SoftReferenceCleared { 199 Object key; 200 public SoftRefKey(Object o, Object key) { 201 super(o); 202 this.key = key; 203 } 204 205 public void cleared() { 206 SoftReferenceCache cache = SoftReferenceCache.this; 207 if (cache == null) return; // Can't really happen. 208 synchronized (cache) { 209 Object o = cache.map.remove(key); 210 if (this != o) 211 // Must not have been ours put it back... 212 // Can happen if a clear is done. 213 cache.map.put(key, o); 214 } 215 } 216 } 217 }