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