/*
* Copyright © 2014 YAOCHEN Corporation, All Rights Reserved
*/
package com.easyooo.framework.cache.impl;
import static com.easyooo.framework.cache.impl.CascadeOperation.getDeleteOps;
import static com.easyooo.framework.cache.impl.CascadeOperation.getInsertOps;
import static com.easyooo.framework.cache.impl.CascadeOperation.getUpdateOps;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.easyooo.framework.cache.CacheException;
import com.easyooo.framework.cache.ModInfo;
import com.easyooo.framework.cache.config.CacheBean;
import com.easyooo.framework.cache.config.GroupBean;
import com.easyooo.framework.cache.storage.ICache;
import com.easyooo.framework.common.util.CglibUtil;
/**
* 缓存的级联管理, 主要维护组的级联关系
* @author Killer
*/
public class CascadeCacheManager extends CacheManagerImpl{
Logger logger = LoggerFactory.getLogger(getClass());
public CascadeCacheManager(){
}
public CascadeCacheManager(CacheChainBuilder cacheChain) {
super(cacheChain);
}
@Override
public String insert(Object bean) throws CacheException {
final String cacheKey = super.insert(bean);
if(cacheKey == null)
return cacheKey;
// check has more groups
Map<String, List<GroupBean>> groups = getGroups(bean);
if(groups == null || groups.size() == 0)
return cacheKey;
doCascadeOps(cacheKey, bean, null, getInsertOps(groups));
return cacheKey;
}
/**
* @see super{@link #updateByPrimaryKey(Object)}
* 如果修改的缓存数据存在分组信息并且分组属性值也需要修改,
* 这个时候就必须保证分组缓存数据的正确性
*/
@SuppressWarnings("unchecked")
@Override
public String updateByPrimaryKey(Object newBean) throws CacheException {
// check has more groups
Map<String, List<GroupBean>> groups = getGroups(newBean);
if(groups == null || groups.size() == 0){
return super.updateByPrimaryKey(newBean);
}
// exist groups
Object oldBean = selectByPrimaryKey(newBean);
String cacheKey = super.updateByPrimaryKey(newBean);
if(cacheKey == null || oldBean == null){
return null;
}
Map<String, Object> oldMap = CglibUtil.describe(oldBean);
Map<String, Object> newMap = CglibUtil.describe(newBean);
ModInfo mod = new ModInfo(cacheKey, oldBean, oldMap, newBean, newMap);
return updateGroupObject(mod, groups, false).getCacheKey();
}
/**
* @see #updateByPrimaryKey(Object) 排除分组属性值为null的分组
*/
@Override
public ModInfo updateByPrimaryKeySelective(Object newBean) throws CacheException {
ModInfo mod = super.updateByPrimaryKeySelective(newBean);
if(mod == null){
return null;
}
// check groups & get default group cacheKey by parameter bean
Map<String, List<GroupBean>> groups = getGroups(newBean);
if(groups == null || groups.size() == 0){
return mod;
}
return updateGroupObject(mod, groups, true);
}
/**
* 级联修改对象,selectiveMode 是否选择性的去修改
*/
private ModInfo updateGroupObject(ModInfo mod, Map<String, List<GroupBean>> groups, boolean selectiveMode)throws CacheException{
Map<String, Object> oldMap = mod.getOldMap();
Map<String, Object> newMap = mod.getNewMap();
final String cacheKey = mod.getCacheKey();
Object newBean = mod.getNewBean();
Object oldBean = mod.getOldBean();
List<CascadeOperation> operationList = getUpdateOps(groups,
oldMap, newMap, selectiveMode);
// cascade
doCascadeOps(cacheKey, newBean, oldBean, operationList);
return mod;
}
/**
* <p>删除缓存数据并清除分组信息</p>
* <p>如果存在分组,此时就会从缓存中查找到这些值,触发额外的1次Socket</p>
*/
@Override
public String deleteByPrimaryKey(Object bean) throws CacheException {
// check groups & get default group cacheKey by parameter bean
Map<String, List<GroupBean>> groups = getGroups(bean);
if(groups == null)
return super.deleteByPrimaryKey(bean);
// exist groups
Object oldBean = this.selectByPrimaryKey(bean);
// remove
final String cacheKey = super.deleteByPrimaryKey(bean);
if(cacheKey == null || oldBean == null)
return cacheKey;
// cascade
doCascadeOps(cacheKey, bean, oldBean, getDeleteOps(groups));
return cacheKey;
}
/**
* 级联操作实现
*/
protected void doCascadeOps(String cacheKey, Object newBean, Object oldBean,
List<CascadeOperation> cascades) throws CacheException {
if(cascades == null || cascades.size() == 0){
return ;
}
ICache cache = buildCache(newBean);
for (CascadeOperation op : cascades) {
try{
String group = op.getGroup();
switch (op.getOperation()) {
case DELETE:
cache.delMembers(buildGroupCacheKey(oldBean, group), cacheKey);
break;
case DELETE_INSERT:
cache.delMembers(buildGroupCacheKey(oldBean, group), cacheKey);
// 执行完不跳出,继续执行INSERT CASE
case INSERT:
String groupKey = buildGroupCacheKey(newBean, group);
if(existGroup(cache, groupKey)){
cache.addMembers(groupKey, cacheKey);
}
break;
default:
break;
}
}catch(CacheException e){
logger.error("Cascade operation failed", e);
}
}
}
private boolean existGroup(ICache cache, String groupKey)throws CacheException{
Set<String> mems = cache.getMembers(groupKey);
return mems == null || mems.size() == 0 ? false : true;
}
private Map<String, List<GroupBean>> getGroups(Object bean)throws CacheException{
CacheBean cacheBean = getCacheBean(bean);
Map<String, List<GroupBean>> groups = cacheBean.getGroups();
if (groups == null || groups.size() == 0) {
return null;
}
return groups;
}
}