package org.infinispan.spring.provider;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
/**
* Since there are 2 Cache implementation with exactly the same implementation details -
* is it convenient to introduce common abstraction and delegate all the methods.
* This is exactly what happens here.
*
* @author Sebastian Laskawiec
*/
class CacheDelegate implements Cache {
//Implemented as a static holder class for backwards compatibility.
//Imagine a situation where a client has new integration module and old Spring version. In that case
//this exception does not exist. However we can bypass this by using separate class file (which is loaded
//by the JVM when needed...)
private static class ValueRetrievalExceptionResolver {
static RuntimeException throwValueRetrievalException(Object key, Callable<?> loader, Throwable ex) {
return new ValueRetrievalException(key, loader, ex);
}
}
private final org.infinispan.commons.api.BasicCache<Object, Object> nativeCache;
/**
* @param nativeCache underlying cache
*/
public CacheDelegate(final org.infinispan.commons.api.BasicCache<Object, Object> nativeCache) {
Assert.notNull(nativeCache, "A non-null Infinispan cache implementation is required");
this.nativeCache = nativeCache;
}
/**
* @see org.springframework.cache.Cache#getName()
*/
@Override
public String getName() {
return this.nativeCache.getName();
}
/**
* @see org.springframework.cache.Cache#getNativeCache()
*/
@Override
public org.infinispan.commons.api.BasicCache<?, ?> getNativeCache() {
return this.nativeCache;
}
/**
* @see org.springframework.cache.Cache#get(Object)
*/
@Override
public ValueWrapper get(final Object key) {
return toValueWrapper(nativeCache.get(key));
}
@Override
public <T> T get(Object key, Class<T> type) {
Object value = nativeCache.get(key);
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value);
}
return (T) value;
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
return (T) nativeCache.computeIfAbsent(key, keyToBeInserted -> {
try {
return valueLoader.call();
} catch (Exception e) {
throw ValueRetrievalExceptionResolver.throwValueRetrievalException(key, valueLoader, e);
}
});
}
/**
* @see org.springframework.cache.Cache#put(Object, Object)
*/
@Override
public void put(final Object key, final Object value) {
this.nativeCache.put(key, value != null ? value : NullValue.NULL);
}
/**
* @see org.infinispan.commons.api.BasicCache#put(Object, Object, long, TimeUnit)
*/
public void put(Object key, Object value, long lifespan, TimeUnit unit) {
this.nativeCache.put(key, value != null ? value : NullValue.NULL, lifespan, unit);
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
return toValueWrapper(this.nativeCache.putIfAbsent(key, value));
}
/**
* @see org.springframework.cache.Cache#evict(Object)
*/
@Override
public void evict(final Object key) {
this.nativeCache.remove(key);
}
/**
* @see org.springframework.cache.Cache#clear()
*/
@Override
public void clear() {
this.nativeCache.clear();
}
/**
* @see Object#toString()
*/
@Override
public String toString() {
return "InfinispanCache [nativeCache = " + this.nativeCache + "]";
}
private ValueWrapper toValueWrapper(Object value) {
if (value == null) {
return null;
}
if (value == NullValue.NULL) {
return NullValue.NULL;
}
return new SimpleValueWrapper(value);
}
}