package com.datdo.mobilib.cache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import junit.framework.Assert;
import com.datdo.mobilib.util.MblUtils;
/**
* Cache objects in memory until they are expired. Obviously all accesses to cached object must be thread-safe.
* @param <T> class of object being cached
*/
public class MblMemCache<T> {
private static class CacheItem<T> {
T mObject;
long mPutAt;
CacheItem(T object, long putAt) {
mObject = object;
mPutAt = putAt;
}
}
/**
* Interface to iterate through all object of this cache.
* @see #iterateWithCallback(com.datdo.mobilib.cache.MblMemCache.IterateCallback)
*/
public static interface IterateCallback<T> {
public void onInterate(T object);
}
private final Map<String, CacheItem<T>> mMap = new HashMap<String, CacheItem<T>>();
private long mDuration;
/**
* Constructor.
* @param duration time in milliseconds before an object become expired
*/
public MblMemCache(long duration) {
mDuration = duration;
}
/**
* Put an object to cache.
* @param id key
* @param object value
*/
public void put(String id, T object) {
put(id, object, System.currentTimeMillis());
}
/**
* Put an object to cache and specify when the object was retrieved
* @param id key
* @param object value
* @param putAt when the object was retrieved (in milliseconds)
*/
public void put(String id, T object, long putAt) {
synchronized (this) {
CacheItem<T> cacheItem = mMap.get(id);
if (cacheItem == null) {
cacheItem = new CacheItem<T>(object, putAt);
} else {
cacheItem.mObject = object;
cacheItem.mPutAt = putAt;
}
mMap.put(id, cacheItem);
}
}
/**
* Get an object from cache by its id.
* @param id key
* @return object if it exists in cache and not expired, otherwise return nul
*/
public T get(String id) {
synchronized (this) {
CacheItem<T> cacheItem = mMap.get(id);
if (cacheItem == null) {
return null;
} else {
if (mDuration <= 0 || System.currentTimeMillis() - cacheItem.mPutAt < mDuration) {
return cacheItem.mObject;
} else {
mMap.remove(id);
return null;
}
}
}
}
/**
* Like {@link #get(String)}, but for multiple ids.
*/
public List<T> get(List<String> ids) {
if (MblUtils.isEmpty(ids)) {
return new ArrayList<T>();
}
synchronized (this) {
List<T> ret = new ArrayList<T>();
for (String id : ids) {
T object = get(id);
if (object != null) {
ret.add(object);
}
}
return ret;
}
}
/**
* Remove an object from cache by its id.
* @param id key
* @return removed object if it exists in cache, otherwise null
*/
public T remove(String id) {
synchronized (this) {
CacheItem<T> cacheItem = mMap.get(id);
if (cacheItem == null) {
return null;
} else {
mMap.remove(id);
return cacheItem.mObject;
}
}
}
/**
* Like {@link #remove(String)}, but for multiple ids.
*/
public List<T> remove(List<String> ids) {
synchronized (this) {
List<T> ret = new ArrayList<T>();
for (String id : ids) {
T object = remove(id);
if (object != null) {
ret.add(object);
}
}
return ret;
}
}
/**
* iterate through all object of this cache.
* @see com.datdo.mobilib.cache.MblMemCache.IterateCallback
*/
public void iterateWithCallback(IterateCallback<T> callback) {
Assert.assertNotNull(callback);
synchronized (this) {
Set<String> ids = new HashSet<String>(mMap.keySet());
for (String id : ids) {
T o = get(id);
if (o != null) {
callback.onInterate(o);
}
}
}
}
/**
* Check if object exists in cache by its id.
* @param id key
* @return true if object exists in cache
*/
public boolean containsKey(String id) {
synchronized (this) {
return get(id) != null;
}
}
/**
* Remove all objects.
*/
public void clear() {
synchronized (this) {
mMap.clear();
}
}
/**
* Get time in milliseconds before an object become expired.
*/
public long getDuration() {
return mDuration;
}
/**
* Set time in milliseconds before an object become expired
*/
public void setDuration(long duration) {
mDuration = duration;
}
}