001: /*
002: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024:
025: /*
026: * @(#)ExpiringCache.java 1.6 06/10/10
027: */
028:
029: package java.io;
030:
031: import java.util.Iterator;
032: import java.util.Map;
033: import java.util.HashMap;
034: import java.util.Set;
035:
036: class ExpiringCache {
037: private long millisUntilExpiration;
038: private Map map;
039: // Clear out old entries every few queries
040: private int queryCount;
041: private int queryOverflow = 300;
042:
043: static class Entry {
044: private long timestamp;
045: private String val;
046:
047: Entry(long timestamp, String val) {
048: this .timestamp = timestamp;
049: this .val = val;
050: }
051:
052: long timestamp() {
053: return timestamp;
054: }
055:
056: void setTimestamp(long timestamp) {
057: this .timestamp = timestamp;
058: }
059:
060: String val() {
061: return val;
062: }
063:
064: void setVal(String val) {
065: this .val = val;
066: }
067: }
068:
069: ExpiringCache() {
070: this (30000);
071: }
072:
073: ExpiringCache(long millisUntilExpiration) {
074: this .millisUntilExpiration = millisUntilExpiration;
075: map = new HashMap();
076: }
077:
078: synchronized String get(String key) {
079: if (++queryCount >= queryOverflow) {
080: cleanup();
081: }
082: Entry entry = entryFor(key);
083: if (entry != null) {
084: return entry.val();
085: }
086: return null;
087: }
088:
089: synchronized void put(String key, String val) {
090: if (++queryCount >= queryOverflow) {
091: cleanup();
092: }
093: Entry entry = entryFor(key);
094: if (entry != null) {
095: entry.setTimestamp(System.currentTimeMillis());
096: entry.setVal(val);
097: } else {
098: map.put(key, new Entry(System.currentTimeMillis(), val));
099: }
100: }
101:
102: synchronized void clear() {
103: map.clear();
104: }
105:
106: private Entry entryFor(String key) {
107: Entry entry = (Entry) map.get(key);
108: if (entry != null) {
109: long delta = System.currentTimeMillis() - entry.timestamp();
110: if (delta < 0 || delta >= millisUntilExpiration) {
111: map.remove(key);
112: entry = null;
113: }
114: }
115: return entry;
116: }
117:
118: private void cleanup() {
119: Set keySet = map.keySet();
120: // Avoid ConcurrentModificationExceptions
121: String[] keys = new String[keySet.size()];
122: int i = 0;
123: for (Iterator iter = keySet.iterator(); iter.hasNext();) {
124: String key = (String) iter.next();
125: keys[i++] = key;
126: }
127: for (int j = 0; j < keys.length; j++) {
128: entryFor(keys[j]);
129: }
130: queryCount = 0;
131: }
132: }
|