Source code: javatools/util/Cache.java
1 /*
2 Javatools (modified version) - Some useful general classes.
3 Copyright (C) 2002-2003 Chris Bitmead (original) Antonio Petrelli (modified)
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19 Contact me at: brenmcguire@users.sourceforge.net
20 */
21 package javatools.util;
22 import java.util.*;
23
24 /**
25 * General purpose cache class. Acts basically like a weak reference dictionary
26 * except that it also returns null when asked to find an item whose use-by
27 * date has expired. It works with two main data structures: A Dictionary which
28 * provides fast access into the cache, and a Queue which keeps track of the
29 * least recently used items in the cache so that old items can be removed and
30 * limit the cache to a bounded size.
31 *
32 * Modified: 8th March 2003 11:41
33 *
34 * @author Chris Bitmead (Original) Antonio Petrelli (modified)
35 * @created December 13, 2001
36 * @version 0.1.10
37 * @commentedby Antonio Petrelli
38 */
39
40 public class Cache {
41 /**
42 * The fast access dictionary
43 */
44 private Dictionary dictionary;
45
46 /**
47 * The lru (least recently used) queue
48 */
49 private JQueue queue;
50
51 /**
52 * The maximum number of objects in the cache
53 */
54 private int cacheMaxObj = 100;
55
56 /**
57 * The maximum age of items in the cache in milliseconds.
58 */
59 private int cacheMaxAge = -1;
60
61 /** Creates a new Cache object.
62 */
63 public Cache() {
64 dictionary = new Hashtable();
65 queue = new JQueue();
66 }
67
68 /**
69 * Constructor which takes an initial guesstimate of how many items we expect
70 * to store in it
71 *
72 * @param size The initial size.
73 */
74 public Cache(int size) {
75 dictionary = new Hashtable(size);
76 queue = new JQueue(size);
77 }
78
79 /**
80 * Set the maximum number of objects to cache.
81 *
82 * @param n The new cacheMaxObj value
83 * @n the number of objects to cache.
84 */
85 public void setCacheMaxObj(int n) {
86 cacheMaxObj = n;
87 }
88
89 /**
90 * Change the maximum age of items in the cache. Can be changed at any time.
91 *
92 * @param s The new cacheMaxAgeSeconds value
93 * @s maximum age in seconds
94 */
95 public void setCacheMaxAgeSeconds(int s) {
96 cacheMaxAge = s * 1000;
97 }
98
99 /**
100 * Turn off cache expiry based on age
101 */
102 public void setNoCacheMaxAge() {
103 cacheMaxAge = -1;
104 }
105
106 /**
107 * Get an object from the cache. Returns null if the object is not in the
108 * cache.
109 *
110 * @param key The key to use to retrieve the object
111 * @return The needed value.
112 */
113 public Object get(Object key) {
114 CacheItem result = (CacheItem) dictionary.get(key);
115 Object rtn = null;
116 if (result != null) {
117 Date now = null;
118 Date expiration = null;
119 if (0 <= cacheMaxAge) {
120 now = new Date();
121 expiration = new Date(result.time.getTime() +
122 cacheMaxAge);
123 }
124 if (now == null || expiration.after(now)) {
125 // We just used it, so reset the date.
126 result.time = new Date();
127 // Since we just used this item
128 // put it at the front of the lru queue.
129 queue.remove(result.qkey);
130 result.qkey = queue.put(result);
131 rtn = result.item;
132 } else {
133 // It's out of date. Might as well throw it away.
134 // (It would be removed later anyway when it comes
135 // through the queue, but better to do it now).
136 queue.remove(result.qkey);
137 dictionary.remove(key);
138 }
139 }
140 return rtn;
141 }
142
143 /**
144 * Put a key value pair into the cache.
145 *
146 * @param key The key
147 * @param item The value
148 */
149 public void put(Object key, Object item) {
150 CacheItem cacheItem = new CacheItem(key, item);
151 cacheItem.setQueueKey(queue.put(cacheItem));
152 dictionary.put(key, cacheItem);
153 if (cacheMaxObj < queue.size()) {
154 // Don't let the cache grow beyond our limit.
155 CacheItem obj = (CacheItem) queue.get();
156 dictionary.remove(obj.key);
157 }
158 }
159
160 /**
161 * Expire the item in the cache with the given key.
162 *
163 * @param key The key of the object to expire from the cache.
164 */
165 public void expire(Object key) {
166 CacheItem result = (CacheItem) dictionary.get(key);
167 if (result != null) {
168 queue.remove(result.qkey);
169 dictionary.remove(key);
170 }
171 }
172
173 public void clear() {
174 queue.clear();
175 dictionary = new Hashtable(dictionary.size());
176 }
177
178 /**
179 * This is the class we store in our internal data structures.
180 *
181 * @author Chris
182 * @created December 13, 2001
183 */
184 class CacheItem {
185 /**
186 * The time this object was last accessed.
187 */
188 Date time;
189
190 /**
191 * The key
192 */
193 Object key;
194
195 /**
196 * The value
197 */
198 Object item;
199 /** The queue to use to check when to remove an object from the cache.
200 */
201 JQueue.QueueKey qkey;
202
203 /** Adds an item to the cache.
204 * @param theKey The key of the object.
205 * @param theItem The item to add.
206 */
207 public CacheItem(Object theKey, Object theItem) {
208 key = theKey;
209 item = theItem;
210 time = new Date();
211 // now
212 }
213
214 /** Checks if an object equals this one.
215 * @param other The object to compare.
216 * @return <CODE>true</CODE>: they are equal;
217 * <CODE>false</CODE>: they are not equal.
218 */
219 public boolean equals(Object other) {
220 return key.equals(((CacheItem) other).key);
221 }
222
223 /** Returns a hash code for this object.
224 * @return The hash code.
225 */
226 public int hashCode() {
227 return key.hashCode();
228 }
229
230 /** Sets the queue key for this object.
231 * @param q The key.
232 */
233 void setQueueKey(JQueue.QueueKey q) {
234 qkey = q;
235 }
236 }
237 }