You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

308 lines
8.9 KiB

package org.crazycake.shiro;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.crazycake.shiro.exception.CacheManagerPrincipalIdNotAssignedException;
import org.crazycake.shiro.exception.PrincipalIdNullException;
import org.crazycake.shiro.exception.PrincipalInstanceException;
import org.crazycake.shiro.exception.SerializationException;
import org.crazycake.shiro.serializer.RedisSerializer;
import org.crazycake.shiro.serializer.StringSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* Used for setting/getting authorization information from Redis
* @param <K>
* @param <V>
*/
public class RedisCache<K, V> implements Cache<K, V> {
private static Logger logger = LoggerFactory.getLogger(RedisCache.class);
private RedisSerializer keySerializer;
private RedisSerializer valueSerializer;
private IRedisManager redisManager;
private String keyPrefix = RedisCacheManager.DEFAULT_CACHE_KEY_PREFIX;
private int expire;
private String principalIdFieldName = RedisCacheManager.DEFAULT_PRINCIPAL_ID_FIELD_NAME;
/**
*
* @param redisManager redisManager
* @param keySerializer keySerializer
* @param valueSerializer valueSerializer
* @param prefix authorization prefix
* @param expire expire
* @param principalIdFieldName id field name of principal object
*/
public RedisCache(IRedisManager redisManager, RedisSerializer keySerializer, RedisSerializer valueSerializer, String prefix, int expire, String principalIdFieldName) {
if (redisManager == null) {
throw new IllegalArgumentException("redisManager cannot be null.");
}
this.redisManager = redisManager;
if (keySerializer == null) {
throw new IllegalArgumentException("keySerializer cannot be null.");
}
this.keySerializer = keySerializer;
if (valueSerializer == null) {
throw new IllegalArgumentException("valueSerializer cannot be null.");
}
this.valueSerializer = valueSerializer;
if (prefix != null && !"".equals(prefix)) {
this.keyPrefix = prefix;
}
this.expire = expire;
if (principalIdFieldName != null) {
this.principalIdFieldName = principalIdFieldName;
}
}
/**
* get shiro authorization redis key-value
* @param key key
* @return value
* @throws CacheException get cache exception
*/
@Override
public V get(K key) throws CacheException {
logger.debug("get key [" + key + "]");
if (key == null) {
return null;
}
try {
Object redisCacheKey = getRedisCacheKey(key);
byte[] rawValue = redisManager.get(keySerializer.serialize(redisCacheKey));
if (rawValue == null) {
return null;
}
V value = (V) valueSerializer.deserialize(rawValue);
return value;
} catch (SerializationException e) {
throw new CacheException(e);
}
}
@Override
public V put(K key, V value) throws CacheException {
if (key == null) {
logger.warn("Saving a null key is meaningless, return value directly without call Redis.");
return value;
}
try {
Object redisCacheKey = getRedisCacheKey(key);
logger.debug("put key [" + redisCacheKey + "]");
redisManager.set(keySerializer.serialize(redisCacheKey), value != null ? valueSerializer.serialize(value) : null, expire);
return value;
} catch (SerializationException e) {
throw new CacheException(e);
}
}
@Override
public V remove(K key) throws CacheException {
logger.debug("remove key [" + key + "]");
if (key == null) {
return null;
}
try {
Object redisCacheKey = getRedisCacheKey(key);
byte[] rawValue = redisManager.get(keySerializer.serialize(redisCacheKey));
V previous = (V) valueSerializer.deserialize(rawValue);
redisManager.del(keySerializer.serialize(redisCacheKey));
return previous;
} catch (SerializationException e) {
throw new CacheException(e);
}
}
/**
* get the full Redis key including prefix by Redis key
* @param key
* @return
*/
private Object getRedisCacheKey(K key) {
if (key == null) {
return null;
}
if (keySerializer instanceof StringSerializer) {
return this.keyPrefix + getStringRedisKey(key);
}
return key;
}
/**
* get Redis key (not including prefix)
* @param key
* @return
*/
private String getStringRedisKey(K key) {
String redisKey;
if (key instanceof PrincipalCollection) {
redisKey = getRedisKeyFromPrincipalIdField((PrincipalCollection) key);
} else {
redisKey = key.toString();
}
return redisKey;
}
/**
* get the Redis key (not including prefix) by PrincipalCollection
* @param key
* @return
*/
private String getRedisKeyFromPrincipalIdField(PrincipalCollection key) {
Object principalObject = key.getPrimaryPrincipal();
if (principalObject instanceof String) {
return principalObject.toString();
}
Method pincipalIdGetter = getPrincipalIdGetter(principalObject);
return getIdObj(principalObject, pincipalIdGetter);
}
private String getIdObj(Object principalObject, Method pincipalIdGetter) {
String redisKey;
try {
Object idObj = pincipalIdGetter.invoke(principalObject);
if (idObj == null) {
throw new PrincipalIdNullException(principalObject.getClass(), this.principalIdFieldName);
}
redisKey = idObj.toString();
} catch (IllegalAccessException e) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
} catch (InvocationTargetException e) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName, e);
}
return redisKey;
}
private Method getPrincipalIdGetter(Object principalObject) {
Method pincipalIdGetter = null;
String principalIdMethodName = this.getPrincipalIdMethodName();
try {
pincipalIdGetter = principalObject.getClass().getMethod(principalIdMethodName);
} catch (NoSuchMethodException e) {
throw new PrincipalInstanceException(principalObject.getClass(), this.principalIdFieldName);
}
return pincipalIdGetter;
}
private String getPrincipalIdMethodName() {
if (this.principalIdFieldName == null || "".equals(this.principalIdFieldName)) {
throw new CacheManagerPrincipalIdNotAssignedException();
}
return "get" + this.principalIdFieldName.substring(0, 1).toUpperCase() + this.principalIdFieldName.substring(1);
}
@Override
public void clear() throws CacheException {
logger.debug("clear cache");
Set<byte[]> keys = null;
try {
keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
} catch (SerializationException e) {
logger.error("get keys error", e);
}
if (keys == null || keys.size() == 0) {
return;
}
for (byte[] key: keys) {
redisManager.del(key);
}
}
/**
* get all authorization key-value quantity
* @return key-value size
*/
@Override
public int size() {
Long longSize = 0L;
try {
longSize = new Long(redisManager.dbSize(keySerializer.serialize(this.keyPrefix + "*")));
} catch (SerializationException e) {
logger.error("get keys error", e);
}
return longSize.intValue();
}
@SuppressWarnings("unchecked")
@Override
public Set<K> keys() {
Set<byte[]> keys = null;
try {
keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
} catch (SerializationException e) {
logger.error("get keys error", e);
return Collections.emptySet();
}
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}
Set<K> convertedKeys = new HashSet<K>();
for (byte[] key:keys) {
try {
convertedKeys.add((K) keySerializer.deserialize(key));
} catch (SerializationException e) {
logger.error("deserialize keys error", e);
}
}
return convertedKeys;
}
@Override
public Collection<V> values() {
Set<byte[]> keys = null;
try {
keys = redisManager.keys(keySerializer.serialize(this.keyPrefix + "*"));
} catch (SerializationException e) {
logger.error("get values error", e);
return Collections.emptySet();
}
if (CollectionUtils.isEmpty(keys)) {
return Collections.emptySet();
}
List<V> values = new ArrayList<V>(keys.size());
for (byte[] key : keys) {
V value = null;
try {
value = (V) valueSerializer.deserialize(redisManager.get(key));
} catch (SerializationException e) {
logger.error("deserialize values= error", e);
}
if (value != null) {
values.add(value);
}
}
return Collections.unmodifiableList(values);
}
public String getKeyPrefix() {
return keyPrefix;
}
public void setKeyPrefix(String keyPrefix) {
this.keyPrefix = keyPrefix;
}
public String getPrincipalIdFieldName() {
return principalIdFieldName;
}
public void setPrincipalIdFieldName(String principalIdFieldName) {
this.principalIdFieldName = principalIdFieldName;
}
}