package restx.security; import com.google.common.base.Optional; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import restx.security.RestxSession.Definition.CachedEntry; import restx.security.RestxSession.Definition.Entry; import restx.security.RestxSession.Definition.EntryCacheManager; import java.util.concurrent.ExecutionException; /** * A restx session entry cache manager based on guava cache. * * You can override the cache settings by overriding the getCacheBuilder() method. * * Note that Guava Cache is not distributed, so be very careful with cache invalidation * when using this cache. * * This is the default EntryCacheManager, see SecurityModule which provides one. */ public class GuavaEntryCacheManager implements EntryCacheManager { @Override public <T> CachedEntry<T> getCachedEntry(Entry<T> entry) { return new GuavaCacheSessionDefinitionEntry<T>(entry.getKey(), getLoadingCacheFor(entry)); } protected <T> LoadingCache<String, T> getLoadingCacheFor(final Entry<T> entry) { return getCacheBuilder(entry).build(getCacheLoaderFor(entry)); } protected <T> CacheLoader<String, T> getCacheLoaderFor(final Entry<T> entry) { return new CacheLoader<String, T>() { @Override public T load(String key) throws Exception { return entry.getValueForId(key).orNull(); } }; } protected <T> CacheBuilder<Object, Object> getCacheBuilder(Entry<T> entry) { return CacheBuilder.newBuilder().maximumSize(1000); } /** * A session definition entry implementation using Guava Cache. */ public static class GuavaCacheSessionDefinitionEntry<T> implements CachedEntry<T> { private final LoadingCache<String, T> loadingCache; private final String key; public GuavaCacheSessionDefinitionEntry(String key, LoadingCache<String, T> loadingCache) { this.key = key; this.loadingCache = loadingCache; } @Override public String getKey() { return key; } @Override public Optional<T> getValueForId(String valueId) { try { return Optional.fromNullable(loadingCache.get(valueId)); } catch (CacheLoader.InvalidCacheLoadException e) { // this exception is raised when cache loader returns null, which may happen if the object behind the key // is deleted. Therefore we just return an absent value return Optional.absent(); } catch (ExecutionException e) { throw new RuntimeException( "impossible to load object from cache using valueid " + valueId + " for " + key + ": " + e.getMessage(), e); } } @Override public void invalidateCacheFor(String valueId) { loadingCache.invalidate(valueId); } @Override public void invalidateCache() { loadingCache.invalidateAll(); } } }