package com.droidworks.misc;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map.Entry;
public class LruSoftCache<K, V> {
private int maxSize = 100;
public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
protected final HashMap<K, CacheReference<K,V>> cache =
new HashMap<K, CacheReference<K,V>>();
private final ReferenceQueue<V> refQueue
= new ReferenceQueue<V>();
public synchronized void put(K key, V value) {
// if we have hit max size, then we need to
// remove an entry first
if ((cache.size() + 1) > maxSize) {
K oldestEntry = findOldest();
remove(oldestEntry);
}
CacheReference<K, V> ref
= new CacheReference<K,V>(key, value, refQueue);
cache.put(key, ref);
drain();
}
public synchronized V get(K key) {
drain();
CacheReference<K, V> ref = cache.get(key);
if (ref != null) {
ref.lastRead = System.currentTimeMillis();
return ref.get();
}
return null;
}
public synchronized boolean contains(K key) {
return cache.containsKey(key);
}
public synchronized void remove(K key) {
cache.remove(key);
}
public synchronized int size() {
return cache.size();
}
public static class CacheReference<K, V> extends SoftReference<V> {
public final K key;
private long lastRead;
public CacheReference(K key, V value, ReferenceQueue<V> rq) {
super(value, rq);
this.key = key;
lastRead = System.currentTimeMillis();
}
public long getLastRead() {
return lastRead;
}
public void setLastRead(long lastRead) {
this.lastRead = lastRead;
}
}
private synchronized K findOldest() {
long oldestAge = Long.MAX_VALUE;
K oldestKey = null;
for (Entry<K, CacheReference<K,V>> e : cache.entrySet()) {
if (e.getValue().lastRead < oldestAge) {
oldestAge = e.getValue().lastRead;
oldestKey = e.getKey();
}
}
return oldestKey;
}
@SuppressWarnings("all")
private synchronized void drain() {
CacheReference ref = (CacheReference) refQueue.poll();
while (ref != null) {
cache.remove(ref.key);
ref = (CacheReference) refQueue.poll();
}
}
}