/*
* Copyright © 2014 YAOCHEN Corporation, All Rights Reserved
*/
package com.easyooo.framework.cache.impl;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.alibaba.fastjson.TypeReference;
import com.easyooo.framework.cache.CacheException;
import com.easyooo.framework.cache.CacheManager;
import com.easyooo.framework.cache.ConfigurationException;
import com.easyooo.framework.cache.KeyBuilder;
import com.easyooo.framework.cache.ModInfo;
import com.easyooo.framework.cache.config.CacheBean;
import com.easyooo.framework.cache.config.Configuration;
import com.easyooo.framework.cache.config.MergingBean;
import com.easyooo.framework.cache.config.impl.AnnotationConfiguration;
import com.easyooo.framework.cache.seriaziler.JsonSeriaziler;
import com.easyooo.framework.cache.seriaziler.SerializationException;
import com.easyooo.framework.cache.seriaziler.SeriazilerFactory;
import com.easyooo.framework.cache.storage.ICache;
import com.easyooo.framework.cache.util.CacheUtil;
import com.easyooo.framework.common.util.CglibUtil;
import com.easyooo.framework.common.util.MapUtil;
/**
*
* 缓存的核心管理器实现
*
* @author Killer
*/
public class CacheManagerImpl implements CacheManager{
protected CacheChainBuilder cacheChain;
protected Configuration configuration = new AnnotationConfiguration();
private SeriazilerFactory factory = new SeriazilerFactory(new JsonSeriaziler());
public CacheManagerImpl() {
}
public CacheManagerImpl(CacheChainBuilder cacheChain) {
this.cacheChain = cacheChain;
}
@Override
public String insert(Object bean) throws CacheException {
final String cacheKey = buildCacheKey(bean);
String value = seriazile(bean);
if(buildCache(bean).set(cacheKey, value)){
return cacheKey;
}
return null;
}
@Override
public String updateByPrimaryKey(Object newBean) throws CacheException {
final String cacheKey = buildCacheKey(newBean);
String value = seriazile(newBean);
if(buildCache(newBean).mod(cacheKey, value)){
return cacheKey;
}
return null;
}
/**
* 修改部分值时,会从数据库中查找对应的所有的属性值,反序列化成Map,通
* 过比对将要修改的内容覆盖,最后通过重新设置的方式修改缓存
*/
@SuppressWarnings("unchecked")
@Override
public ModInfo updateByPrimaryKeySelective(Object newBean) throws CacheException {
final String cacheKey = buildCacheKey(newBean);
ICache cache = buildCache(newBean);
// get old object
Object oldBean = deserialize(newBean, cache.get(cacheKey));
if(oldBean == null){
return null;
}
Map<String, Object> oldMap = CglibUtil.describe(oldBean);
// new object
Map<String, Object> newMap = CglibUtil.describe(newBean);
// override old map
Map<String, Object> unionMap = MapUtil.overrideExcludeNull(oldMap, newMap);
// mod cache
if(cache.mod(cacheKey, seriazile(unionMap))){
return new ModInfo(cacheKey, oldBean, oldMap, newBean, newMap);
}
return null;
}
@Override
public String deleteByPrimaryKey(Object bean) throws CacheException {
final String cacheKey = buildCacheKey(bean);
Long rows = buildCache(bean).del(cacheKey);
if(rows == 0){
return null;
}
return cacheKey;
}
@SuppressWarnings("unchecked")
@Override
public <T> T selectByPrimaryKey(Object bean) throws CacheException {
// build the Key
final String cacheKey = buildCacheKey(bean);
// get a bean
String value = buildCache(bean).get(cacheKey);
if(value == null || "".equals(value)){
return null;
}
return (T)deserialize(bean, value);
}
/**
* 该方法使用Gets读取所有的成员列表,效率取决于缓存的gets实现
*/
@SuppressWarnings("unchecked")
@Override
public <T> List<T> selectByGroupKey(Object bean, String groupName)
throws CacheException {
String groupCacheKey = buildGroupCacheKey(bean, groupName);
ICache cache = buildCache(bean);
Set<String> memberCacheKeySet = cache.getMembers(groupCacheKey);
if(memberCacheKeySet == null || memberCacheKeySet.size() == 0){
return null;
}
List<T> dataList = new ArrayList<T>();
List<String> memberValueList = cache.gets(memberCacheKeySet
.toArray(new String[] {}));
for (String memberValue : memberValueList) {
dataList.add((T)deserialize(bean, memberValue));
}
return dataList;
}
@Override
public boolean saveSingleGroup(Object bean, List<?> beanList,
String groupName) throws CacheException {
if(beanList == null || beanList.size() == 0){
return true;
}
String groupCacheKey = buildGroupCacheKey(bean, groupName);
String[] keyvalues = new String[beanList.size() * 2];
String[] memberArray = new String[beanList.size()];
for (int i= 0, j = 0; i< beanList.size(); i++, j+=2) {
Object itemBean = beanList.get(i);
String cacheKey = buildCacheKey(itemBean);
memberArray[i] = cacheKey;
keyvalues[j] = cacheKey;
keyvalues[j + 1] = seriazile(itemBean);
}
// set cache
ICache cache = buildCache(bean);
if(cache.sets(keyvalues)){
cache.addMembers(groupCacheKey, memberArray);
return true;
}
return false;
}
/**
* 将多个Bean合并到一个Bean中,如果存在同名的属性则被覆盖,如果合并时,
* 主要的Bean必须存在缓存,否则返回NULL
*/
@Override
public List<Map<String,Object>> selectMergingObjectByPrimaryKey(Object bean, Class<?> dtoClass)
throws CacheException {
if(dtoClass == null)
return null;
CacheBean cacheBean = getCacheBean(bean);
Map<Class<?>, MergingBean> mbean = cacheBean.getMergings();
if(mbean == null)
CacheException.throwe("The entity bean merge no configuration");
MergingBean mb = mbean.get(dtoClass);
if(mb == null)
CacheException.throwe("No configuration mapping bean");
// get from cache
Map<String,Object> masterBean = getCacheAndDeserializeToMap(bean);
List<Object> configBeans = CacheUtil.afterSetKeyRefObjects(masterBean, mb.getRefrences());
// add object
List<Map<String,Object>> target = new ArrayList<>();
target.add(masterBean);
for (Object refBean : configBeans) {
target.add(getCacheAndDeserializeToMap(refBean));
}
return target;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// key build functions
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected List<String> buildCacheKeys(List<Object> configBeans)throws CacheException {
List<String> refCacheKey = new ArrayList<String>();
for (Object bean : configBeans) {
refCacheKey.add(buildCacheKey(bean));
}
return refCacheKey;
}
protected String buildCacheKey(Object bean)throws CacheException {
return buildCacheKey(bean, bean.getClass());
}
protected String buildCacheKey(Object bean, Class<?> cacheClass)throws CacheException {
CacheBean cacheBean = getCacheBean(cacheClass);
KeyBuilder builder = newKeyBuilder(cacheBean);
try {
String[] keyValues = CacheUtil.getKeyValues(bean, cacheBean);
if(!CacheUtil.checkKeyValues(cacheBean, keyValues)){
throw new CacheException("cannot generate the primary key, via the entity bean attribute value");
}
return builder.buildKey(cacheBean, keyValues);
} catch (Exception e) {
throw new CacheException("Unable to generate entity cache key", e);
}
}
protected String buildGroupCacheKey(Object bean, String group)throws CacheException{
CacheBean cacheBean = getCacheBean(bean);
KeyBuilder builder = newKeyBuilder(cacheBean);
if(Configuration.DEFAULT_MINI_TABLE.equals(group)){
return buildMiniTableGroupKey(cacheBean, builder, group);
}
return buildGroupCacheKey(bean, cacheBean, builder, group);
}
protected String buildMiniTableGroupKey(CacheBean cacheBean,
KeyBuilder builder, String group) throws CacheException {
return builder.buildMiniTableKey(cacheBean);
}
protected String buildGroupCacheKey(Object bean,CacheBean cacheBean,
KeyBuilder builder, String group)throws CacheException {
try {
String[] groupValues = CacheUtil.getGroupValues(bean, cacheBean, group);
if(!CacheUtil.checkGroupValues(cacheBean, group, groupValues)){
throw new CacheException("cannot generate the group key, via the entity bean attribute value");
}
return builder.buildGroupKey(cacheBean, group, groupValues);
} catch (Exception e) {
throw new CacheException("Unable to generate group cache key", e);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// important methods
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public CacheBean getCacheBean(Object bean) throws CacheException {
Class<?> cacheClass = null;
if( bean instanceof Class){
cacheClass = (Class<?>) bean;
}else{
cacheClass = bean.getClass();
}
try {
return configuration.get(cacheClass);
} catch (ConfigurationException e) {
throw new CacheException(e);
}
}
private Map<String, Object> getCacheAndDeserializeToMap(Object bean)throws CacheException{
final String cacheKey = buildCacheKey(bean);
// get a map from cache
String value = buildCache(bean).get(cacheKey);
return deserializeToMap(value);
}
protected Map<String,Object> deserializeToMap(String value)throws CacheException{
try {
Type type = new TypeReference<Map<String,Object>>(){}.getType();
return factory.deserializeAsObject(value, type);
} catch (SerializationException e) {
throw new CacheException(e);
}
}
/**
* 从缓存查找将序列化值,再反序列化成对象
*/
protected Object deserialize(Object bean, String value)throws CacheException{
try {
return factory.deserializeAsObject(value, bean.getClass());
} catch (SerializationException e) {
throw new CacheException(e);
}
}
/**
* 将对象序列化
*/
protected String seriazile(Object bean) throws CacheException {
try {
return factory.seriazileAsString(bean);
} catch (SerializationException e) {
throw new CacheException(e);
}
}
protected KeyBuilder newKeyBuilder(CacheBean cacheBean)
throws CacheException {
try {
return cacheBean.getKeyBuilder().newInstance();
} catch (Exception e) {
throw new CacheException("Unable to create the instance of primary key generators", e);
}
}
protected ICache buildCache(Object bean)throws CacheException{
return cacheChain.buildCache(getCacheBean(bean));
}
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
public void setSeriazilerFactory(SeriazilerFactory seriazilerFactory) {
this.factory = seriazilerFactory;
}
}