1
25
26
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
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
48 Entry(long timestamp, String val) {
49 this.timestamp = timestamp;
50 this.val = val;
51 }
52
53 long timestamp() { return timestamp; }
54 void setTimestamp(long timestamp) { this.timestamp = timestamp; }
55
56 String val() { return val; }
57 void setVal(String val) { this.val = val; }
58 }
59
60 ExpiringCache() {
61 this(30000);
62 }
63
64 @SuppressWarnings("serial")
65 ExpiringCache(long millisUntilExpiration) {
66 this.millisUntilExpiration = millisUntilExpiration;
67 map = new LinkedHashMap<>() {
68 protected boolean removeEldestEntry(Map.Entry<String,Entry> eldest) {
69 return size() > MAX_ENTRIES;
70 }
71 };
72 }
73
74 synchronized String get(String key) {
75 if (++queryCount >= queryOverflow) {
76 cleanup();
77 }
78 Entry entry = entryFor(key);
79 if (entry != null) {
80 return entry.val();
81 }
82 return null;
83 }
84
85 synchronized void put(String key, String val) {
86 if (++queryCount >= queryOverflow) {
87 cleanup();
88 }
89 Entry entry = entryFor(key);
90 if (entry != null) {
91 entry.setTimestamp(System.currentTimeMillis());
92 entry.setVal(val);
93 } else {
94 map.put(key, new Entry(System.currentTimeMillis(), val));
95 }
96 }
97
98 synchronized void clear() {
99 map.clear();
100 }
101
102 private Entry entryFor(String key) {
103 Entry entry = map.get(key);
104 if (entry != null) {
105 long delta = System.currentTimeMillis() - entry.timestamp();
106 if (delta < 0 || delta >= millisUntilExpiration) {
107 map.remove(key);
108 entry = null;
109 }
110 }
111 return entry;
112 }
113
114 private void cleanup() {
115 Set<String> keySet = map.keySet();
116
117 String[] keys = new String[keySet.size()];
118 int i = 0;
119 for (String key: keySet) {
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