1 /* 2 * Copyright (c) 2002, 2011, 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<String,Entry> 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 64 @SuppressWarnings("serial") ExpiringCache(long millisUntilExpiration)65 ExpiringCache(long millisUntilExpiration) { 66 this.millisUntilExpiration = millisUntilExpiration; 67 map = new LinkedHashMap<String,Entry>() { 68 @Override 69 protected boolean removeEldestEntry(Map.Entry eldest) { 70 return size() > MAX_ENTRIES; 71 } 72 }; 73 } 74 get(String key)75 synchronized String get(String key) { 76 if (++queryCount >= queryOverflow) { 77 cleanup(); 78 } 79 Entry entry = entryFor(key); 80 if (entry != null) { 81 return entry.val(); 82 } 83 return null; 84 } 85 put(String key, String val)86 synchronized void put(String key, String val) { 87 if (++queryCount >= queryOverflow) { 88 cleanup(); 89 } 90 Entry entry = entryFor(key); 91 if (entry != null) { 92 entry.setTimestamp(System.currentTimeMillis()); 93 entry.setVal(val); 94 } else { 95 map.put(key, new Entry(System.currentTimeMillis(), val)); 96 } 97 } 98 clear()99 synchronized void clear() { 100 map.clear(); 101 } 102 entryFor(String key)103 private Entry entryFor(String key) { 104 Entry entry = map.get(key); 105 if (entry != null) { 106 long delta = System.currentTimeMillis() - entry.timestamp(); 107 if (delta < 0 || delta >= millisUntilExpiration) { 108 map.remove(key); 109 entry = null; 110 } 111 } 112 return entry; 113 } 114 cleanup()115 private void cleanup() { 116 Set<String> keySet = map.keySet(); 117 // Avoid ConcurrentModificationExceptions 118 String[] keys = new String[keySet.size()]; 119 int i = 0; 120 for (String key: keySet) { 121 keys[i++] = key; 122 } 123 for (int j = 0; j < keys.length; j++) { 124 entryFor(keys[j]); 125 } 126 queryCount = 0; 127 } 128 } 129