1 package com.vipan.util; 2 3 import java.util.*; 4 import org.apache.log4j.*; 5 import org.apache.commons.collections.map.LRUMap; 6 import org.apache.commons.collections.MapIterator; 7 8 9 18 public class ExpiringCache { 19 20 static Category logger = Category.getInstance(ExpiringCache.class); 21 22 public static final long DEFAULT_TIME_TO_LIVE = 10 * 60 * 1000; 23 public static final long DEFAULT_ACCESS_TIMEOUT = 5 * 60 * 1000; 24 public static final long DEFAULT_TIMER_INTERVAL = 2 * 60 * 1000; 25 26 long ttl = DEFAULT_TIME_TO_LIVE; 27 long ato = DEFAULT_ACCESS_TIMEOUT; 28 long tiv = DEFAULT_TIMER_INTERVAL; 29 30 LRUMap cacheMap; 31 Timer cacheManager; 32 33 34 protected void finalize() throws Throwable { 35 if (cacheManager != null) cacheManager.cancel(); 36 } 37 38 public ExpiringCache() { 39 cacheMap = new LRUMap(); 40 initialize(); 41 } 42 43 public ExpiringCache(long timeToLive, long accessTimeout, 45 int maximumCachedQuantity, long timerInterval 46 ) { 47 ttl = timeToLive; 48 ato = accessTimeout; 49 cacheMap = new LRUMap(maximumCachedQuantity); 50 tiv = timerInterval; 51 initialize(); 52 } 53 54 55 public void setTimeToLive(long milliSecs) { 56 ttl = milliSecs; 57 initialize(); 58 } 59 60 61 62 public void setAccessTimeout(long milliSecs) { 63 ato = milliSecs; 64 initialize(); 65 } 66 67 68 69 public void setCleaningInterval(long milliSecs) { 70 tiv = milliSecs; 71 initialize(); 72 } 73 74 75 public void initialize() { 76 if (logger.isDebugEnabled()) logger.debug("initialize() started"); 77 if (cacheManager != null) cacheManager.cancel(); 78 cacheManager = new Timer(true); 79 cacheManager.schedule( 80 new TimerTask() { 81 public void run() { 82 NDC.push("TimerTask"); 83 long now = System.currentTimeMillis(); 84 try { 85 MapIterator itr = cacheMap.mapIterator(); 86 while (itr.hasNext()) { 87 Object key = itr.next(); 88 CachedObject cobj = (CachedObject) itr.getValue(); 89 if (cobj == null || cobj.hasExpired(now)) { 90 if (logger.isDebugEnabled()) logger.debug( 91 "Removing " + key + ": Idle time=" + 92 (now - cobj.timeAccessedLast) + "; Stale time:" + 93 (now - cobj.timeCached)); 94 itr.remove(); 95 Thread.yield(); 96 } 97 } 98 } 99 catch (ConcurrentModificationException cme) { 100 104 if (logger.isDebugEnabled()) logger.debug( 105 "Ignorable ConcurrentModificationException"); 106 } 107 NDC.remove(); 108 } 109 }, 110 0, 111 tiv 112 ); 113 } 114 115 116 117 118 public int howManyObjects() { 119 return cacheMap.size(); 120 } 121 122 123 public void clear() { 124 cacheMap.clear(); 125 } 126 127 135 public Object admit(Object key, Object dataToCache) { 136 139 CachedObject cobj = (CachedObject) cacheMap.get(key); 140 if (cobj == null) { 141 cacheMap.put(key, new CachedObject(dataToCache)); 142 return null; 143 } 144 else { 145 Object obj = cobj.getCachedData(key); 146 if (obj == null) { 147 if (dataToCache == null) { 148 cobj.timeCached = cobj.timeAccessedLast = System.currentTimeMillis(); 151 return null; 152 } 153 else { 154 cacheMap.put(key, new CachedObject(dataToCache)); 155 return null; 156 } 157 } 158 else if (obj.equals(dataToCache)) { 159 cobj.timeCached = cobj.timeAccessedLast = System.currentTimeMillis(); 162 return null; 163 } 164 else { 165 cacheMap.put(key, new CachedObject(dataToCache)); 166 return obj; 167 } 168 } 169 } 170 171 172 173 public Object admit(Object key, Object dataToCache, long objectTimeToLive, long objectIdleTimeout) { 174 177 CachedObject cobj = (CachedObject) cacheMap.get(key); 178 if (cobj == null) { 179 cacheMap.put(key, new CachedObject(dataToCache, objectTimeToLive, objectIdleTimeout)); 180 return null; 181 } 182 else { 183 Object obj = cobj.getCachedData(key); 184 if (obj == null) { 185 if (dataToCache == null) { 186 cobj.timeCached = cobj.timeAccessedLast = System.currentTimeMillis(); 189 cobj.objectTTL = objectTimeToLive; 190 cobj.objectIdleTimeout = objectIdleTimeout; 191 cobj.userTimeouts = true; 192 return null; 193 } 194 else { 195 cacheMap.put(key, new CachedObject(dataToCache, objectTimeToLive, objectIdleTimeout)); 196 return null; 197 } 198 } 199 else if (obj.equals(dataToCache)) { 200 cobj.timeCached = cobj.timeAccessedLast = System.currentTimeMillis(); 203 cobj.objectTTL = objectTimeToLive; 204 cobj.objectIdleTimeout = objectIdleTimeout; 205 cobj.userTimeouts = true; 206 return null; 207 } 208 else { 209 cacheMap.put(key, new CachedObject(dataToCache, objectTimeToLive, objectIdleTimeout)); 210 return obj; 211 } 212 } 213 } 214 215 216 217 public Object recover(Object key) { 218 CachedObject cobj = (CachedObject) cacheMap.get(key); 219 if (cobj == null) return null; 220 else return cobj.getCachedData(key); 221 } 222 223 224 public void discard(Object key) { 225 cacheMap.remove(key); 226 } 227 228 229 public long whenCached(Object key) { 230 CachedObject cobj = (CachedObject) cacheMap.get(key); 231 if (cobj == null) return 0; 232 return cobj.timeCached; 233 } 234 235 236 public long whenLastAccessed(Object key) { 237 CachedObject cobj = (CachedObject) cacheMap.get(key); 238 if (cobj == null) return 0; 239 return cobj.timeAccessedLast; 240 } 241 242 243 public int howManyTimesAccessed(Object key) { 244 CachedObject cobj = (CachedObject) cacheMap.get(key); 245 if (cobj == null) return 0; 246 return cobj.numberOfAccesses; 247 } 248 249 250 254 protected class CachedObject { 255 Object cachedData; 256 long timeCached; 257 long timeAccessedLast; 258 int numberOfAccesses; 259 long objectTTL; 260 long objectIdleTimeout; 261 boolean userTimeouts; 262 263 264 CachedObject(Object cachedData) { 265 long now = System.currentTimeMillis(); 266 this.cachedData = cachedData; 267 timeCached = now; 268 timeAccessedLast = now; 269 ++numberOfAccesses; 270 } 271 272 CachedObject(Object cachedData, long timeToLive, long idleTimeout) { 273 long now = System.currentTimeMillis(); 274 this.cachedData = cachedData; 275 objectTTL = timeToLive; 276 objectIdleTimeout = idleTimeout; 277 userTimeouts = true; 278 timeCached = now; 279 timeAccessedLast = now; 280 ++numberOfAccesses; 281 } 282 283 284 Object getCachedData(Object key) { 285 long now = System.currentTimeMillis(); 286 if (hasExpired(now)) { 287 cachedData = null; 288 cacheMap.remove(key); 289 return null; 290 } 291 timeAccessedLast = now; 292 ++numberOfAccesses; 293 return cachedData; 294 } 295 296 boolean hasExpired(long now) { 297 long usedTTL = userTimeouts?objectTTL:ttl; 298 long usedATO = userTimeouts?objectIdleTimeout:ato; 299 300 if (now > timeAccessedLast + usedATO || 301 now > timeCached + usedTTL 302 ) { 303 return true; 304 } 305 else return false; 306 } 307 308 309 } 310 311 312 313 } 315 316 | Popular Tags |