All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bazaarvoice.emodb.auth.shiro.GuavaCacheManager Maven / Gradle / Ivy

There is a newer version: 6.5.190
Show newest version
package com.bazaarvoice.emodb.auth.shiro;

import com.bazaarvoice.emodb.cachemgr.api.CacheHandle;
import com.bazaarvoice.emodb.cachemgr.api.CacheRegistry;
import com.bazaarvoice.emodb.cachemgr.api.InvalidationScope;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheBuilderSpec;
import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import static java.util.Objects.requireNonNull;

/**
 * Implementation of {@link org.apache.shiro.cache.CacheManager} which uses a Guava Cache for storage.
 */
public class GuavaCacheManager extends AbstractCacheManager implements InvalidatableCacheManager {
    private static Logger _log = LoggerFactory.getLogger(GuavaCacheManager.class);

    private final static String DEFAULT_CACHE_BUILDER_SPEC = "maximumSize=500";

    private CacheBuilderSpec _spec;

    private final ConcurrentMap _allAvailableCaches = new ConcurrentHashMap<>();
    private final CacheRegistry _cacheRegistry; // already backed by ConcurrentMap

    public GuavaCacheManager(CacheRegistry cacheRegistry, String cacheBuilderSpec) {
        _spec = CacheBuilderSpec.parse(requireNonNull(cacheBuilderSpec));
        _cacheRegistry = cacheRegistry;
    }

    public GuavaCacheManager(CacheRegistry cacheRegistry) {
        this(cacheRegistry, DEFAULT_CACHE_BUILDER_SPEC);
    }

    @Override
    protected org.apache.shiro.cache.Cache createCache(String name) throws CacheException {
        // name will be e.g.: "EmoDB.authorizationCache", "EmoDB.authenticationCache"
        Cache cache = CacheBuilder.from(_spec).build();

        GuavaCache managedCache = _allAvailableCaches.get(name);
        if (managedCache != null) {
            _log.debug("Returned existing {} named {}", cache.getClass().getName(), name);
        } else {
            GuavaCache newCache = new GuavaCache(name, cache);
            managedCache = _allAvailableCaches.putIfAbsent(name, newCache);

            if (managedCache == null) {
                // First time registering this cache
                _log.debug("Created {} named {}", cache.getClass().getName(), name);
                if (_cacheRegistry != null) {
                    _cacheRegistry.register(name, cache, true);
                }
                managedCache = newCache;
            } else {
               _log.debug("Returned existing {} named {}", cache.getClass().getName(), name);
            }
        }

        return managedCache;
    }

    @Override
    public void invalidateAll() {
        if(_cacheRegistry != null) {
            for(String name : _allAvailableCaches.keySet()) {
                // There is a potential race condition here since the cache is added to _allAvailableCaches
                // then subsequently added to _cacheRegistry in createCache(), making it possible for a value to
                // be cached but not invalidated on this call.  However, to avoid this issue all caches used by
                // this manager are pre-created in ApiKeyRealm.onInit(), so in practice this can never happen.
                CacheHandle cacheHandle = _cacheRegistry.lookup(name, false);
                cacheHandle.invalidateAll(InvalidationScope.GLOBAL);
            }
        } else {
            for(GuavaCache cache : _allAvailableCaches.values()) {
                cache.clear();
            }
        }
    }

    private class GuavaCache implements org.apache.shiro.cache.Cache {
        private final String _name;
        private final Cache _cache;

        private GuavaCache(String name, Cache cache) {
            _name = name;
            _cache = cache;
        }

        @Override
        public Object get(Object key)
                throws CacheException {
            if(key == null) return null;
            String stringKey = extractStringKey(key);
            Object hit = _cache.getIfPresent(stringKey);
            _log.debug("{} cache hit for key {} in {}", hit == null ? "No " : "Got ", key, _name);
            return hit;
        }

        private String extractStringKey(Object key) {
            if(key instanceof SimplePrincipalCollection) {
                SimplePrincipalCollection coll = (SimplePrincipalCollection) key;
                return "SimplePrincipalCollection:" + coll.getPrimaryPrincipal();
            } else {
                return key.toString();
            }
        }

        @Override
        public Object put(Object key, Object value)
                throws CacheException {
            String stringKey = extractStringKey(key);
            Object oldValue = _cache.getIfPresent(stringKey);
            _cache.put(stringKey, value);
            return oldValue;
        }

        @Override
        public Object remove(Object key)
                throws CacheException {
            String stringKey = extractStringKey(key);
            Object oldValue = _cache.getIfPresent(stringKey);
            _cache.invalidate(key);
            return oldValue;
        }

        @Override
        public void clear()
                throws CacheException {
            _cache.invalidateAll();
        }

        @Override
        public int size() {
            return (int) _cache.size();
        }

        @Override
        public Set keys() {
            return _cache.asMap().keySet();
        }

        @Override
        public Collection values() {
            return _cache.asMap().values();
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy