MemoryCache.java
biz/hammurapi/cache/MemoryCache.java
Violations
Inspector |
Message |
Severity |
Location |
Java Inspector 048 |
Copyrights information should be present in each file. |
1 |
|
Java Inspector 082 |
Parenthesis are redundant. |
2 |
279:37
|
Java Inspector 089 |
Undocumented field |
2 |
49:9
|
Java Inspector 089 |
Undocumented field |
2 |
50:9
|
Java Inspector 089 |
Undocumented field |
2 |
53:9
|
Java Inspector 089 |
Constructor is not properly documented |
2 |
80:17
|
Java Inspector 089 |
Undocumented parameter key |
2 |
80:17
|
Java Inspector 089 |
Undocumented parameter value |
2 |
80:17
|
Java Inspector 089 |
Undocumented parameter time |
2 |
80:17
|
Java Inspector 089 |
Parameter expires is not documented |
2 |
80:17
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter referent |
2 |
80:17
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter q |
2 |
80:17
|
Java Inspector 089 |
Method is not properly documented |
2 |
92:17
|
Java Inspector 089 |
Undocumented parameter name |
2 |
92:17
|
Java Inspector 089 |
Undocumented parameter value |
2 |
92:17
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter string |
2 |
92:17
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter i |
2 |
92:17
|
Java Inspector 089 |
Javadoc contains tag for non-existent parameter l |
2 |
92:17
|
Java Inspector 089 |
Undocumented method |
2 |
115:17
|
Java Inspector 089 |
Undocumented method |
2 |
136:17
|
Java Inspector 089 |
Undocumented method |
2 |
171:17
|
Java Inspector 089 |
Parameter producer documentation is too short. It is only 1 words. Should be at least 3 words. |
2 |
208:9
|
Java Inspector 089 |
Parameter producer documentation is too short. It is only 1 words. Should be at least 3 words. |
2 |
222:9
|
Java Inspector 089 |
Undocumented method |
2 |
245:9
|
Java Inspector 089 |
Undocumented method |
2 |
271:9
|
Java Inspector 089 |
Undocumented method |
2 |
289:49
|
Java Inspector 089 |
Undocumented method |
2 |
293:49
|
Java Inspector 089 |
Undocumented method |
2 |
297:49
|
Java Inspector 089 |
Undocumented method |
2 |
334:9
|
Java Inspector 089 |
Undocumented method |
2 |
345:9
|
Java Inspector 089 |
Undocumented method |
2 |
356:9
|
Java Inspector 089 |
Undocumented method |
2 |
386:9
|
Java Inspector 089 |
Undocumented method |
2 |
401:9
|
Java Inspector 089 |
Undocumented method |
2 |
408:9
|
Java Inspector 089 |
Undocumented method |
2 |
431:9
|
Java Inspector 089 |
Undocumented exception ConfigurationException |
2 |
438:9
|
Java Inspector 089 |
Undocumented method |
2 |
448:9
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
132:33
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
144:71
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
186:48
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
190:48
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
250:40
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
276:40
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
318:48
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
326:48
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
352:32
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
373:48
|
Java Inspector 026 |
Avoid hardwired string literals. Allowed literals: [] |
3 |
382:57
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
108:17
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
128:17
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
165:17
|
Java Inspector 051 |
It is good practice to call in any case super() in a constructor. |
3 |
208:9
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package biz.hammurapi.cache;
24
25import java.lang.ref.ReferenceQueue;
26import java.lang.ref.SoftReference;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.Iterator;
30import java.util.LinkedList;
31import java.util.Map;
32import java.util.Set;
33import java.util.Timer;
34import java.util.TimerTask;
35import java.util.WeakHashMap;
36
37import biz.hammurapi.config.Component;
38import biz.hammurapi.config.ConfigurationException;
39import biz.hammurapi.metrics.MeasurementCategory;
40import biz.hammurapi.util.Acceptor;
41
42
43
44
45
46
47
48public class MemoryCache extends AbstractProducer implements Cache, Component {
49 protected Map cache=new HashMap();
50 protected Map reverseCache=new WeakHashMap();
51
52 private ReferenceQueue queue=new ReferenceQueue();
53 protected Producer producer;
54 private Cache fallBack;
55 private MeasurementCategory measurementCategory;
56
57 private void addMeasurement(String name, double value, long time) {
58 if (measurementCategory!=null) {
59 measurementCategory.addMeasurement(name, value, time);
60 }
61 }
62
63 private void addMeasurement(String name, double value) {
64 if (measurementCategory!=null) {
65 measurementCategory.addMeasurement(name, value, 0);
66 }
67 }
68
69 private class CacheReference extends SoftReference {
70
71 private Object key;
72 private long expires;
73 private long time;
74
75
76
77
78
79
80 public CacheReference(Object key, Object value, long time, long expires) {
81 super(value, queue);
82 this.key=key;
83 this.expires=expires;
84 this.time=time;
85 }
86
87
88
89
90
91
92 public void addMeasurement(String name, double value) {
93 MemoryCache.this.addMeasurement(name, value);
94 }
95 }
96
97
98
99
100
101
102 private class FallBackEntry {
103 Object value;
104 private long expires;
105 private long time;
106 private Object key;
107
108 FallBackEntry(Object key, Object value, long time, long expires) {
109 this.key=key;
110 this.value=value;
111 this.expires=expires;
112 this.time=time;
113 }
114
115 protected void finalize() throws Throwable {
116 if (fallBack.isActive() && (expires<=0 || System.currentTimeMillis()<expires)) {
117 fallBack.put(key, value, time, expires);
118 }
119
120 super.finalize();
121 }
122 }
123
124 private static class ReferenceThread extends Thread {
125 private ReferenceQueue queue;
126 private Map cache;
127
128 private ReferenceThread(ReferenceQueue queue, Map cache) {
129 this.queue=queue;
130 this.cache=cache;
131 setDaemon(true);
132 setName("Removes cleared entries");
133 start();
134 }
135
136 public void run() {
137 try {
138 while (true) {
139 CacheReference cacheReference = (CacheReference) queue.remove();
140 Object key=cacheReference.key;
141 synchronized (cache) {
142 cache.remove(key);
143 }
144 cacheReference.addMeasurement("garbage collected", 1);
145 }
146 } catch (InterruptedException e) {
147 return;
148 }
149 }
150 }
151
152 private Thread referenceThread=new ReferenceThread(queue, cache);
153
154 private static class JanitorTask extends TimerTask {
155 private Map cache;
156 private MeasurementCategory measurementCategory;
157 private Map reverseCache;
158
159 private void addMeasurement(String name, double value, long time) {
160 if (measurementCategory!=null) {
161 measurementCategory.addMeasurement(name, value, time);
162 }
163 }
164
165 private JanitorTask(Map cache, Map reverseCache, MeasurementCategory measurementCategory) {
166 this.cache=cache;
167 this.reverseCache=reverseCache;
168 this.measurementCategory=measurementCategory;
169 }
170
171 public void run() {
172 long now=System.currentTimeMillis();
173 int expired=0;
174 synchronized (cache) {
175 Iterator it=new LinkedList(cache.keySet()).iterator();
176 while (it.hasNext()) {
177 Object key=it.next();
178 CacheReference cacheReference = (CacheReference) cache.get(key);
179 long expires = (cacheReference).expires;
180 if (expires>0 && expires<now) {
181 cache.remove(key);
182 reverseCache.remove(cacheReference.get());
183 expired++;
184 }
185 }
186 addMeasurement("size", cache.size(), now);
187 }
188
189 if (expired>0) {
190 addMeasurement("expired", expired, now);
191 }
192 }
193 }
194
195 private TimerTask janitorTask;
196
197
198
199
200 public static final long CLEANUP_INTERVAL=60000;
201
202
203
204
205
206
207
208 public MemoryCache(Producer producer, Cache fallBack, MeasurementCategory measurementCategory) {
209 this(producer, fallBack, measurementCategory, null, CLEANUP_INTERVAL);
210 }
211
212
213
214
215
216
217
218
219
220
221
222 public MemoryCache(Producer producer, Cache fallBack, MeasurementCategory measurementCategory, Timer timer, long cleanupInterval) {
223 super();
224
225 this.producer=producer;
226 if (producer!=null) {
227 producer.addCache(this);
228 }
229
230 this.fallBack=fallBack;
231 if (fallBack!=null) {
232 addCache(fallBack);
233 }
234
235 this.measurementCategory=measurementCategory;
236 this.timer=timer;
237
238 this.cleanupInterval=cleanupInterval;
239 }
240
241 private boolean isOwnTimer;
242 private Timer timer;
243 private long cleanupInterval;
244
245 public void put(Object key, Object value, long time, long expirationTime) {
246 checkShutdown();
247 synchronized (cache) {
248 cache.put(key, new CacheReference(key, toValue(key, value, time, expirationTime), time, expirationTime));
249 reverseCache.put(value, key);
250 addMeasurement("put", 1, time);
251 }
252 }
253
254
255
256
257
258
259
260 private Object toValue(Object key, Object value, long time, long expirationTime) {
261 return fallBack==null ? value : new FallBackEntry(key, value, time, expirationTime);
262 }
263
264 private Object fromValue(Object object) {
265 if (object instanceof FallBackEntry) {
266 return ((FallBackEntry) object).value;
267 }
268 return object;
269 }
270
271 public Entry get(Object key) {
272 checkShutdown();
273 synchronized (cache) {
274 CacheReference cr=(CacheReference) cache.get(key);
275 long now = System.currentTimeMillis();
276 addMeasurement("get", 1, now);
277 boolean doFallBack=true;
278 if (cr!=null) {
279 if ((cr.expires>0 && cr.expires<now) || cr.get()==null) {
280 cache.remove(key);
281 reverseCache.remove(fromValue(cr.get()));
282 doFallBack=false;
283 } else {
284 final Object o=fromValue(cr.get());
285 final long et=cr.expires;
286 final long time=cr.time;
287 return new Entry() {
288
289 public long getExpirationTime() {
290 return et;
291 }
292
293 public long getTime() {
294 return time;
295 }
296
297 public Object get() {
298 return o;
299 }
300
301 };
302 }
303 }
304
305 if (doFallBack && fallBack!=null) {
306 Entry entry = fallBack.get(key);
307 if (entry!=null) {
308 cache.put(key, new CacheReference(key, toValue(key, entry.get(), entry.getTime(), entry.getExpirationTime()), entry.getTime(), entry.getExpirationTime()));
309 reverseCache.put(entry.get(), key);
310 return entry;
311 }
312 }
313
314 if (key instanceof ProducingKey) {
315 Entry entry = ((ProducingKey) key).get();
316 cache.put(key, new CacheReference(key, toValue(key, entry.get(), entry.getTime(), entry.getExpirationTime()), entry.getTime(), entry.getExpirationTime()));
317 reverseCache.put(entry.get(),key);
318 addMeasurement("produce", 1, now);
319 return entry;
320 }
321
322 if (producer!=null) {
323 Entry entry = producer.get(key);
324 cache.put(key, new CacheReference(key, toValue(key, entry.get(), entry.getTime(), entry.getExpirationTime()), entry.getTime(), entry.getExpirationTime()));
325 reverseCache.put(entry.get(),key);
326 addMeasurement("produce", 1, now);
327 return entry;
328 }
329
330 return null;
331 }
332 }
333
334 public void clear() {
335 synchronized (cache) {
336 cache.clear();
337 reverseCache.clear();
338
339 if (fallBack!=null) {
340 fallBack.clear();
341 }
342 }
343 }
344
345 public void remove(Object key) {
346 synchronized (cache) {
347 CacheReference cr = (CacheReference) cache.remove(key);
348 if (cr!=null) {
349 reverseCache.remove(fromValue(cr.get()));
350 }
351 }
352 addMeasurement("remove", 1);
353 onRemove(key);
354 }
355
356 public void remove(Acceptor acceptor) {
357 synchronized (cache) {
358 Iterator it=cache.keySet().iterator();
359 int removed=0;
360 while (it.hasNext()) {
361 Object key=it.next();
362 if (acceptor.accept(key)) {
363 Entry entry=(Entry) cache.get(key);
364 if (entry!=null) {
365 reverseCache.remove(fromValue(entry.get()));
366 }
367 it.remove();
368 removed++;
369 onRemove(key);
370 }
371 }
372 if (removed>0) {
373 addMeasurement("remove", removed);
374 }
375 }
376 }
377
378 private boolean shutDown=false;
379
380 private void checkShutdown() {
381 if (shutDown) {
382 throw new IllegalStateException("Shut down");
383 }
384 }
385
386 public void stop() {
387 if (!shutDown) {
388 cache.clear();
389 reverseCache.clear();
390 referenceThread.interrupt();
391 if (janitorTask!=null) {
392 janitorTask.cancel();
393 }
394 if (isOwnTimer && timer!=null) {
395 timer.cancel();
396 }
397 shutDown=true;
398 }
399 }
400
401 protected void finalize() throws Throwable {
402 if (isActive()) {
403 stop();
404 }
405 super.finalize();
406 }
407
408 public Set keySet() {
409 HashSet ret = new HashSet();
410 synchronized (cache) {
411 ret.addAll(cache.keySet());
412 }
413
414 if (producer!=null) {
415 Set pkeys=producer.keySet();
416 if (pkeys!=null) {
417 ret.addAll(pkeys);
418 }
419 }
420
421 if (fallBack!=null) {
422 Set fkeys=fallBack.keySet();
423 if (fkeys!=null) {
424 ret.addAll(fkeys);
425 }
426 }
427
428 return ret;
429 }
430
431 public boolean isActive() {
432 return !shutDown;
433 }
434
435
436
437
438 public void start() throws ConfigurationException {
439 if (timer==null) {
440 timer=new Timer(true);
441 isOwnTimer=true;
442 }
443
444 janitorTask=new JanitorTask(cache, reverseCache, measurementCategory);
445 timer.schedule(janitorTask, cleanupInterval, cleanupInterval);
446 }
447
448 public void setOwner(Object owner) {
449
450 }
451}
452
453
454