package de.invesdwin.util.collections.loadingcache.guava.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import javax.annotation.concurrent.ThreadSafe;
import com.google.common.base.Optional;
import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
/**
* This is a workaround to make googles ComputingMap work with null values.
*
* @see <a href="http://code.google.com/p/google-collections/issues/detail?id=166">Source</a>
*
*/
@ThreadSafe
public class OptionalValueWrapperLoadingCache<K, V> implements LoadingCache<K, V> {
private final LoadingCache<K, Optional<V>> delegate;
public OptionalValueWrapperLoadingCache(final LoadingCache<K, Optional<V>> delegate) {
this.delegate = delegate;
}
@SuppressWarnings("unchecked")
@Override
public V getIfPresent(final Object key) {
return maybeGet((K) key, delegate.getIfPresent(key));
}
@Override
public V get(final K key, final Callable<? extends V> valueLoader) throws ExecutionException {
return maybeGet(key, delegate.get(key, new Callable<Optional<V>>() {
@SuppressWarnings("unchecked")
@Override
public Optional<V> call() throws Exception {
return (Optional<V>) Optional.fromNullable(valueLoader.call());
}
}));
}
@Override
public ImmutableMap<K, V> getAllPresent(final Iterable<?> keys) {
final ImmutableMap<K, Optional<V>> allPresent = delegate.getAllPresent(keys);
final Map<K, V> nonnullAllPresent = new HashMap<K, V>();
for (final Entry<K, Optional<V>> e : allPresent.entrySet()) {
final V value = maybeGet(e.getKey(), e.getValue());
if (value != null) {
nonnullAllPresent.put(e.getKey(), value);
}
}
return ImmutableMap.copyOf(nonnullAllPresent);
}
@Override
public void put(final K key, final V value) {
delegate.put(key, Optional.fromNullable(value));
}
@Override
public void putAll(final Map<? extends K, ? extends V> m) {
final Map<K, Optional<V>> newMap = new HashMap<K, Optional<V>>();
for (final Entry<? extends K, ? extends V> e : m.entrySet()) {
final K key = e.getKey();
final V value = e.getValue();
newMap.put(key, Optional.fromNullable(value));
}
delegate.putAll(newMap);
}
@Override
public void invalidate(final Object key) {
delegate.invalidate(key);
}
@Override
public void invalidateAll(final Iterable<?> keys) {
delegate.invalidateAll(keys);
}
@Override
public void invalidateAll() {
delegate.invalidateAll();
}
@Override
public long size() {
return delegate.size();
}
@Override
public CacheStats stats() {
return delegate.stats();
}
@Override
public void cleanUp() {
delegate.cleanUp();
}
@Override
public V get(final K key) throws ExecutionException {
return maybeGet(key, delegate.get(key));
}
@Override
public V getUnchecked(final K key) {
return maybeGet(key, delegate.getUnchecked(key));
}
@Override
public ImmutableMap<K, V> getAll(final Iterable<? extends K> keys) throws ExecutionException {
final ImmutableMap<K, Optional<V>> all = delegate.getAll(keys);
final Map<K, V> nonnullAll = new HashMap<K, V>();
for (final Entry<K, Optional<V>> e : all.entrySet()) {
final V value = maybeGet(e.getKey(), e.getValue());
if (value != null) {
nonnullAll.put(e.getKey(), value);
}
}
return ImmutableMap.copyOf(nonnullAll);
}
@Override
public V apply(final K key) {
return maybeGet(key, delegate.apply(key));
}
@Override
public void refresh(final K key) {
delegate.refresh(key);
}
@Override
public ConcurrentMap<K, V> asMap() {
return new OptionalValueWrapperConcurrentMap<K, V>(delegate.asMap());
}
protected final V maybeGet(final K key, final Optional<V> value) {
if (value != null) {
final V v = value.orNull();
if (!isPutAllowed(key, v)) {
invalidate(key);
}
return v;
} else {
return (V) null;
}
}
protected boolean isPutAllowed(final K key, final V value) {
return true;
}
}