1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.onemind.commons.java.datastructure;
22
23 import java.util.*;
24 import java.util.logging.Level;
25 import java.util.logging.Logger;
26 /***
27 * A lookup cache implements simple lookup caching algorithm for looking up things. The derived class simply implement the
28 * produce(Object key) method which is assumed an expensive operation and the results will be cached by the lookup cache
29 * implementation. There's no public method on lookup cache, the developer should provide application specific lookup interface.
30 * @author TiongHiang Lee (thlee@onemindsoft.org)
31 * @version $Id: LookupCache.java,v 1.4 2004/09/30 13:26:26 thlee Exp $ $Name: $
32 */
33 public abstract class LookupCache
34 {
35
36 /*** the logger * */
37 private static final Logger _logger = Logger.getLogger(LookupCache.class.getName());
38
39 /*** the hit cache * */
40 private Map _cache = new HashMap();
41
42 /*** the negative cache * */
43 private Set _negCache;
44
45 /*** indicate whether to do negative caching * */
46 private boolean _doNegCache = true;
47
48 /***
49 * {@inheritDoc}
50 */
51 public LookupCache()
52 {
53 this(true);
54 }
55
56 /***
57 * {@inheritDoc}
58 * @param doNegCache whether to do negative caching
59 */
60 public LookupCache(boolean doNegCache)
61 {
62 setDoNegativeCache(doNegCache);
63 }
64
65 /***
66 * The main lookup method. The developer should provide another application specific method that call this method to return what
67 * the application wants
68 * @param key the key
69 * @return the object or null
70 * @todo add synchronization when lookup the same key to avoid double loading
71 */
72 protected final Object lookup(Object key)
73 {
74 if (_doNegCache)
75 {
76 if (_negCache.contains(key))
77 {
78 if (_logger.isLoggable(Level.FINEST))
79 {
80 _logger.finest("Returning negative cache hit");
81 }
82 return null;
83 }
84 }
85 Object o = _cache.get(key);
86 if (o == null)
87 {
88
89 o = produce(key);
90 if (o != null)
91 {
92 if (_logger.isLoggable(Level.FINEST))
93 {
94 _logger.finest("Put hit of " + key + " to cache");
95 }
96 _cache.put(key, o);
97 } else
98 {
99 if (_doNegCache)
100 {
101 _logger.finest("Put negative hit of " + key + " to cache");
102 _negCache.add(key);
103 }
104 }
105 } else
106 {
107 if (_logger.isLoggable(Level.FINEST))
108 {
109 _logger.finest("Returning positive cache hit of " + key);
110 }
111 }
112 return o;
113 }
114
115 /***
116 * Produce the object given the key. This is assumed to be an expensive operation and it will be called by the lookup method.
117 * The result will be cached by the lookup method and negative result also will be cached to if the doNegCache is turned on.
118 * @param key the key
119 * @return the result or null if no result
120 */
121 protected abstract Object produce(Object key);
122
123 /***
124 * Turn on/off the negative cache
125 * @param b true to turn on the neg cache
126 */
127 protected void setDoNegativeCache(boolean b)
128 {
129 _doNegCache = b;
130 if (b && (_negCache == null))
131 {
132 _negCache = new HashSet();
133 }
134 }
135
136 /***
137 * Get whether the object is in negative cache
138 * @param o the object
139 * @return true if is in negative cache
140 */
141 protected boolean isInNegCache(Object o)
142 {
143 return _negCache.contains(o);
144 }
145
146 /***
147 * Test if the key is in cache
148 * @param o the object
149 * @return true if is in cache
150 */
151 protected boolean isInCache(Object o)
152 {
153 return _cache.containsKey(o);
154 }
155
156 /***
157 * Clear all the negative cache
158 */
159 protected void clearNegCache()
160 {
161 if (_negCache != null)
162 {
163 _negCache.clear();
164 }
165 }
166 }