1. /*
  2. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  3. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  4. */
  5. /*
  6. * @(#)ExpiringCache.java 1.5 04/02/13
  7. */
  8. package java.io;
  9. import java.util.Iterator;
  10. import java.util.Map;
  11. import java.util.LinkedHashMap;
  12. import java.util.Set;
  13. class ExpiringCache {
  14. private long millisUntilExpiration;
  15. private Map map;
  16. // Clear out old entries every few queries
  17. private int queryCount;
  18. private int queryOverflow = 300;
  19. private int MAX_ENTRIES = 200;
  20. static class Entry {
  21. private long timestamp;
  22. private String val;
  23. Entry(long timestamp, String val) {
  24. this.timestamp = timestamp;
  25. this.val = val;
  26. }
  27. long timestamp() { return timestamp; }
  28. void setTimestamp(long timestamp) { this.timestamp = timestamp; }
  29. String val() { return val; }
  30. void setVal(String val) { this.val = val; }
  31. }
  32. ExpiringCache() {
  33. this(30000);
  34. }
  35. ExpiringCache(long millisUntilExpiration) {
  36. this.millisUntilExpiration = millisUntilExpiration;
  37. map = new LinkedHashMap() {
  38. protected boolean removeEldestEntry(Map.Entry eldest) {
  39. return size() > MAX_ENTRIES;
  40. }
  41. };
  42. }
  43. synchronized String get(String key) {
  44. if (++queryCount >= queryOverflow) {
  45. cleanup();
  46. }
  47. Entry entry = entryFor(key);
  48. if (entry != null) {
  49. return entry.val();
  50. }
  51. return null;
  52. }
  53. synchronized void put(String key, String val) {
  54. if (++queryCount >= queryOverflow) {
  55. cleanup();
  56. }
  57. Entry entry = entryFor(key);
  58. if (entry != null) {
  59. entry.setTimestamp(System.currentTimeMillis());
  60. entry.setVal(val);
  61. } else {
  62. map.put(key, new Entry(System.currentTimeMillis(), val));
  63. }
  64. }
  65. synchronized void clear() {
  66. map.clear();
  67. }
  68. private Entry entryFor(String key) {
  69. Entry entry = (Entry) map.get(key);
  70. if (entry != null) {
  71. long delta = System.currentTimeMillis() - entry.timestamp();
  72. if (delta < 0 || delta >= millisUntilExpiration) {
  73. map.remove(key);
  74. entry = null;
  75. }
  76. }
  77. return entry;
  78. }
  79. private void cleanup() {
  80. Set keySet = map.keySet();
  81. // Avoid ConcurrentModificationExceptions
  82. String[] keys = new String[keySet.size()];
  83. int i = 0;
  84. for (Iterator iter = keySet.iterator(); iter.hasNext(); ) {
  85. String key = (String) iter.next();
  86. keys[i++] = key;
  87. }
  88. for (int j = 0; j < keys.length; j++) {
  89. entryFor(keys[j]);
  90. }
  91. queryCount = 0;
  92. }
  93. }