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

com.github.kaizen4j.shiro.cache.ShiroRedisCache Maven / Gradle / Ivy

The newest version!
package com.github.kaizen4j.shiro.cache;

import com.github.kaizen4j.util.JsonUtils;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.Base64Utils;
import org.springframework.util.ClassUtils;
import org.xerial.snappy.Snappy;

/**
 * @author liuguowen
 */
@SuppressWarnings("unchecked")
public class ShiroRedisCache implements Cache {

    private static final Logger logger = LoggerFactory.getLogger(ShiroRedisCache.class);

    private RedisTemplate redisTemplate;

    private long expireMillis;

    private String cacheKeyPrefix;

    private RedisSerializer objectSerializer = new JdkSerializationRedisSerializer();

    public ShiroRedisCache(RedisTemplate redisTemplate, String cacheKeyPrefix, long expireMillis) {
        this.redisTemplate = redisTemplate;
        this.cacheKeyPrefix = cacheKeyPrefix;
        this.expireMillis = expireMillis;
    }

    @Override
    public V get(K k) {
        String key = getCacheKey(k);
        try {
            ValueOperations valueOperations = redisTemplate.opsForValue();
            String serialized = valueOperations.get(key);
            if (StringUtils.isBlank(serialized)) {
                return null;
            }

            byte[] decodeBytes = Base64Utils.decodeFromString(serialized);
            V value = (V) objectSerializer.deserialize(Snappy.uncompress(decodeBytes));

            if (logger.isDebugEnabled()) {
                logger.debug("ShiroRedisCache [get()] operation of key [{}] value [{}]", key, JsonUtils.toJson(value));
            }
            return value;
        } catch (Exception e) {
            logger.error("ShiroRedisCache [get()] operation failed for key [{}]", key, e);
            return null;
        }
    }

    @Override
    public V put(K k, V v) {
        String key = getCacheKey(k);
        try {
            ValueOperations valueOperations = redisTemplate.opsForValue();
            byte[] serializeBytes = objectSerializer.serialize(v);
            byte[] compressBytes = Snappy.compress(serializeBytes);

            if (logger.isDebugEnabled()) {
                logger.debug("Compress with snappy before size [{}] after size [{}] byte", serializeBytes.length,
                        compressBytes.length);
            }

            String encodeString = Base64Utils.encodeToString(compressBytes);
            valueOperations.set(key, encodeString, Duration.ofMillis(expireMillis));

            if (logger.isDebugEnabled()) {
                logger.debug("ShiroRedisCache [put()] operation of key [{}] value [{}] expireMillis [{}]", key,
                        JsonUtils.toJson(v), expireMillis);
            }
            return v;
        } catch (Exception e) {
            logger.error("ShiroRedisCache [put()] operation failed for key [{}] value [{}]", key, JsonUtils.toJson(v),
                    e);
            return null;
        }
    }

    @Override
    public V remove(K k) {
        String key = getCacheKey(k);
        try {
            V value = get(k);
            boolean result = redisTemplate.delete(key);

            if (logger.isDebugEnabled()) {
                logger.debug("ShiroRedisCache [remove()] operation of key [{}] value [{}] result [{}]", key,
                        JsonUtils.toJson(value), result);
            }
            return value;
        } catch (Exception e) {
            logger.error("ShiroRedisCache [remove()] operation failed for key [{}]", key, e);
            return null;
        }
    }

    @Override
    public void clear() {
        // do nothing...
        logger.warn("Do nothing the operation [clear()] of ShiroRedisCache");
    }

    @Override
    public int size() {
        logger.warn("Do nothing the operation [size()] of ShiroRedisCache");
        return 0;
    }

    @Override
    public Set keys() {
        logger.warn("Do nothing the operation [keys()] of ShiroRedisCache");
        return Collections.emptySet();
    }

    @Override
    public Collection values() {
        logger.warn("Do nothing the operation [values()] of ShiroRedisCache");
        return Collections.emptyList();
    }

    private String getCacheKey(K k) {
        String keyClassName = ClassUtils.getShortName(k.getClass());
        if (k instanceof PrincipalCollection) {
            PrincipalCollection principalCollection = (PrincipalCollection) k;
            Object primaryPrincipal = principalCollection.getPrimaryPrincipal();

            if (primaryPrincipal instanceof String) {
                return String.format(cacheKeyPrefix, keyClassName, primaryPrincipal.toString());
            } else {
                Md5Hash md5Hash = new Md5Hash(primaryPrincipal);
                return String.format(cacheKeyPrefix, keyClassName, md5Hash.toHex());
            }
        }
        return String.format(cacheKeyPrefix, keyClassName, k.toString());
    }

}