1 /* 2 * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 */ 28 29 package java.io; 30 31 import java.util.Iterator; 32 import java.util.Map; 33 import java.util.LinkedHashMap; 34 import java.util.Set; 35 36 class ExpiringCache { 37 private long millisUntilExpiration; 38 private Map map; 39 // Clear out old entries every few queries 40 private int queryCount; 41 private int queryOverflow = 300; 42 private int MAX_ENTRIES = 200; 43 44 static class Entry { 45 private long timestamp; 46 private String val; 47 Entry(long timestamp, String val)48 Entry(long timestamp, String val) { 49 this.timestamp = timestamp; 50 this.val = val; 51 } 52 timestamp()53 long timestamp() { return timestamp; } setTimestamp(long timestamp)54 void setTimestamp(long timestamp) { this.timestamp = timestamp; } 55 val()56 String val() { return val; } setVal(String val)57 void setVal(String val) { this.val = val; } 58 } 59 ExpiringCache()60 ExpiringCache() { 61 this(30000); 62 } 63 ExpiringCache(long millisUntilExpiration)64 ExpiringCache(long millisUntilExpiration) { 65 this.millisUntilExpiration = millisUntilExpiration; 66 map = new LinkedHashMap() { 67 protected boolean removeEldestEntry(Map.Entry eldest) { 68 return size() > MAX_ENTRIES; 69 } 70 }; 71 } 72 get(String key)73 synchronized String get(String key) { 74 if (++queryCount >= queryOverflow) { 75 cleanup(); 76 } 77 Entry entry = entryFor(key); 78 if (entry != null) { 79 return entry.val(); 80 } 81 return null; 82 } 83 put(String key, String val)84 synchronized void put(String key, String val) { 85 if (++queryCount >= queryOverflow) { 86 cleanup(); 87 } 88 Entry entry = entryFor(key); 89 if (entry != null) { 90 entry.setTimestamp(System.currentTimeMillis()); 91 entry.setVal(val); 92 } else { 93 map.put(key, new Entry(System.currentTimeMillis(), val)); 94 } 95 } 96 clear()97 synchronized void clear() { 98 map.clear(); 99 } 100 entryFor(String key)101 private Entry entryFor(String key) { 102 Entry entry = (Entry) map.get(key); 103 if (entry != null) { 104 long delta = System.currentTimeMillis() - entry.timestamp(); 105 if (delta < 0 || delta >= millisUntilExpiration) { 106 map.remove(key); 107 entry = null; 108 } 109 } 110 return entry; 111 } 112 cleanup()113 private void cleanup() { 114 Set keySet = map.keySet(); 115 // Avoid ConcurrentModificationExceptions 116 String[] keys = new String[keySet.size()]; 117 int i = 0; 118 for (Iterator iter = keySet.iterator(); iter.hasNext(); ) { 119 String key = (String) iter.next(); 120 keys[i++] = key; 121 } 122 for (int j = 0; j < keys.length; j++) { 123 entryFor(keys[j]); 124 } 125 queryCount = 0; 126 } 127 } 128