package com.anjlab.gae;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import javax.cache.Cache;
import javax.cache.CacheEntry;
import javax.cache.CacheListener;
import javax.cache.CacheStatistics;
import org.datanucleus.util.SoftValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LocalMemorySoftCache implements Cache {
private static final Logger logger = LoggerFactory.getLogger(LocalMemorySoftCache.class);
private final Cache cache;
private final Map<Object, Object> map;
@SuppressWarnings("unchecked")
public LocalMemorySoftCache(Cache cache) {
this.map = new SoftValueMap(100);
this.cache = cache;
}
@Override
public void addListener(CacheListener listener) {
cache.addListener(listener);
}
@Override
public void clear() {
map.clear();
cache.clear();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key)
|| cache.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value)
|| cache.containsValue(value);
}
@SuppressWarnings("rawtypes")
@Override
public Set entrySet() {
return cache.entrySet();
}
@Override
public void evict() {
map.clear();
cache.evict();
}
@Override
public Object get(Object key) {
Object value = map.get(key);
if (value == null) {
value = cache.get(key);
if (value instanceof PartialArrayList) {
((PartialArrayList) value).setCache(cache);
value = ((PartialArrayList) value).get();
}
map.put(key, value);
}
return value;
}
@SuppressWarnings("rawtypes")
@Override
public Map getAll(Collection keys) {
return cache.getAll(keys);
}
@Override
public CacheEntry getCacheEntry(Object key) {
return cache.getCacheEntry(key);
}
@Override
public CacheStatistics getCacheStatistics() {
return cache.getCacheStatistics();
}
@Override
public boolean isEmpty() {
return cache.isEmpty();
}
@SuppressWarnings("rawtypes")
@Override
public Set keySet() {
return cache.keySet();
}
@Override
public void load(Object key) {
cache.load(key);
}
@SuppressWarnings("rawtypes")
@Override
public void loadAll(Collection keys) {
cache.loadAll(keys);
}
@Override
public Object peek(Object key) {
return cache.peek(key);
}
@SuppressWarnings("unchecked")
@Override
public Object put(Object key, Object value) {
map.put(key, value);
try
{
// TODO Partial saving of big lists
ArrayList<?> listValue = value instanceof ArrayList<?> ? (ArrayList<?>) value : null;
if ( listValue != null
&& listValue.size() > 1
&& listValue.get(0) instanceof SerializableEstimations)
{
PartialArrayList list = new PartialArrayList(key, (ArrayList<SerializableEstimations>) value);
list.setCache(cache);
return list.put();
} else {
return cache.put(key, value);
}
} catch (Exception e) {
logger.warn("Error putting value into cache", e);
// A value may be already in cache. We should remove it to avoid
// not synchronous duplicates there and here in local map.
remove(key);
return null;
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void putAll(Map t) {
map.putAll(t);
cache.putAll(t);
}
@Override
public Object remove(Object key) {
map.remove(key);
return cache.remove(key);
}
@Override
public void removeListener(CacheListener listener) {
cache.removeListener(listener);
}
@Override
public int size() {
return cache.size();
}
@SuppressWarnings("rawtypes")
@Override
public Collection values() {
return cache.values();
}
/**
* Reset in-memory cache but leave original cache untouched.
*/
public void reset() {
map.clear();
}
}