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 // Android-changed: Qualified ExpiringCache.Entry to distinguish from Map.Entry. 69 // There seems to be a compiler difference between javac and jack here; 70 // Map.Entry<String,Entry> doesn't work on jack since the latter "Entry" gets 71 // interpreted as referring to Map.Entry rather than ExpiringCache.Entry. 72 // protected boolean removeEldestEntry(Map.Entry<String,Entry> eldest) { 73 protected boolean removeEldestEntry(Map.Entry<String,ExpiringCache.Entry> eldest) { 74 return size() > MAX_ENTRIES; 75 } 76 }; 77 } 78 get(String key)79 synchronized String get(String key) { 80 if (++queryCount >= queryOverflow) { 81 cleanup(); 82 } 83 Entry entry = entryFor(key); 84 if (entry != null) { 85 return entry.val(); 86 } 87 return null; 88 } 89 put(String key, String val)90 synchronized void put(String key, String val) { 91 if (++queryCount >= queryOverflow) { 92 cleanup(); 93 } 94 Entry entry = entryFor(key); 95 if (entry != null) { 96 entry.setTimestamp(System.currentTimeMillis()); 97 entry.setVal(val); 98 } else { 99 map.put(key, new Entry(System.currentTimeMillis(), val)); 100 } 101 } 102 clear()103 synchronized void clear() { 104 map.clear(); 105 } 106 entryFor(String key)107 private Entry entryFor(String key) { 108 Entry entry = map.get(key); 109 if (entry != null) { 110 long delta = System.currentTimeMillis() - entry.timestamp(); 111 if (delta < 0 || delta >= millisUntilExpiration) { 112 map.remove(key); 113 entry = null; 114 } 115 } 116 return entry; 117 } 118 cleanup()119 private void cleanup() { 120 Set<String> keySet = map.keySet(); 121 // Avoid ConcurrentModificationExceptions 122 String[] keys = new String[keySet.size()]; 123 int i = 0; 124 for (String key: keySet) { 125 keys[i++] = key; 126 } 127 for (int j = 0; j < keys.length; j++) { 128 entryFor(keys[j]); 129 } 130 queryCount = 0; 131 } 132 } 133