package sagan.support.cache;
import org.springframework.cache.Cache;
import org.springframework.cache.support.AbstractCacheManager;
import org.springframework.data.redis.cache.DefaultRedisCachePrefix;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCachePrefix;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.Assert;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* A CacheManager implementation that uses redis as a distributed cache.
* One can configure specific cache regions in order to use them with:
* <ul>
* <li>use a custom expiration value</li>
* <li>use a custom RedisTemplate (with configured Serializers)</li>
* </ul>
* When dealing with a cache region with no custom configuration, this CacheManager is using a default
* {@link org.springframework.data.redis.core.RedisTemplate}.
*/
public class RedisCacheManager extends AbstractCacheManager {
@SuppressWarnings("rawtypes")//
private final RedisConnectionFactory redisConnectionFactory;
private final RedisTemplate defaultTemplate;
private final Map<String, RedisTemplate> templates;
private boolean usePrefix = true;
private RedisCachePrefix cachePrefix = new DefaultRedisCachePrefix();
private boolean dynamic = false;
// 0 - never expire
private long defaultExpiration = 0;
private final Map<String, Long> expires;
public RedisCacheManager(RedisConnectionFactory redisConnectionFactory) {
this.redisConnectionFactory = redisConnectionFactory;
this.defaultTemplate = new RedisTemplate();
this.defaultTemplate.setConnectionFactory(this.redisConnectionFactory);
this.defaultTemplate.afterPropertiesSet();
this.templates = new ConcurrentHashMap<String, RedisTemplate>();
this.expires = new ConcurrentHashMap<String, Long>();
}
public void setUsePrefix(boolean usePrefix) {
this.usePrefix = usePrefix;
}
public void setCachePrefix(RedisCachePrefix cachePrefix) {
this.cachePrefix = cachePrefix;
}
public void setDynamic(boolean dynamic) {
this.dynamic = dynamic;
}
public void setDefaultExpiration(long defaultExpiration) {
this.defaultExpiration = defaultExpiration;
}
public RedisCacheManager withCache(String cacheName, long expiration) {
return withCache(cacheName, this.defaultTemplate, expiration);
}
public RedisCacheManager withCache(String cacheName, RedisTemplate template, long expiration) {
this.templates.put(cacheName, template);
this.expires.put(cacheName, expiration);
RedisCache cache = createCache(cacheName, template, expiration);
addCache(cache);
return this;
}
@Override
public Cache getCache(String name) {
Cache cache = super.getCache(name);
if (cache == null && this.dynamic) {
return createCache(name, this.defaultTemplate, this.defaultExpiration);
}
return cache;
}
protected RedisCache createCache(String cacheName, RedisTemplate template, long expiration) {
return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) : null), template, expiration);
}
@Override
protected Collection<? extends Cache> loadCaches() {
Assert.notNull(this.defaultTemplate, "A redis template is required in order to interact with data store");
return this.getCacheNames().stream().map(name -> getCache(name)).collect(Collectors.toList());
}
}