package com.walker.cache.tree;
|
|
import com.walker.cache.AbstractCacheProvider;
|
import com.walker.cache.Cachable;
|
import com.walker.cache.Cache;
|
import com.walker.infrastructure.utils.StringUtils;
|
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.Iterator;
|
import java.util.List;
|
import java.util.Map;
|
|
public abstract class AbstractCacheTreeProvider<T> extends AbstractCacheProvider<T>
|
implements CacheTree<T> {
|
|
public static final String SUPER_ROOT_KEY = "cacheTree_super_root_key";
|
|
@Override
|
public List<String> getRootKeys() {
|
// CacheTreeNode node = (CacheTreeNode)this.getCacheData(SUPER_ROOT_KEY);
|
CacheTreeNode node = this.get(SUPER_ROOT_KEY);
|
if(node != null){
|
Collection<CacheTreeNode> rootList = node.getChildren();
|
if(rootList == null || rootList.size() == 0){
|
return null;
|
}
|
List<String> result = new ArrayList<String>(rootList.size());
|
if(rootList != null){
|
for(Iterator<CacheTreeNode> i = rootList.iterator(); i.hasNext();)
|
result.add(i.next().getKey());
|
return result;
|
}
|
}
|
return null;
|
}
|
|
@Override
|
public Collection<CacheTreeNode> getRootList() {
|
// CacheTreeNode node = (CacheTreeNode)this.getCacheData(SUPER_ROOT_KEY);
|
CacheTreeNode node = this.get(SUPER_ROOT_KEY);
|
if(node != null){
|
return node.getChildren();
|
}
|
return null;
|
}
|
|
@Override
|
public CacheTreeNode getOneRootNode(String key) {
|
return searchTreeNode(key);
|
}
|
|
@Override
|
public CacheTreeNode searchTreeNode(String key) {
|
assert (StringUtils.isNotEmpty(key));
|
// CacheTreeNode node = (CacheTreeNode)this.getCacheData(SUPER_ROOT_KEY);
|
CacheTreeNode node = this.get(SUPER_ROOT_KEY);
|
if(node != null){
|
return node.search(key);
|
}
|
return null;
|
}
|
|
public List<CacheTreeNode> searchTreeNodeList(String keyLike){
|
CacheTreeNode node = this.get(SUPER_ROOT_KEY);
|
if(node != null){
|
// String[] keys = StringUtils.stringToArray(keyLike, " ");
|
// if(keys != null && keys.length > 1){
|
// if(logger.isDebugEnabled()){
|
// logger.debug("搜索树,查询条件有多个:" + keys.length);
|
// for(String s : keys){
|
// logger.debug(s);
|
// }
|
// }
|
// return node.searchLike(keys);
|
// } else {
|
// return node.searchLike(keyLike);
|
// }
|
return node.searchLike(keyLike);
|
}
|
return null;
|
}
|
|
public List<CacheTreeNode> searchTreeNodeList(String[] keys){
|
CacheTreeNode node = this.get(SUPER_ROOT_KEY);
|
if(node != null){
|
return node.searchLike(keys);
|
}
|
return null;
|
}
|
|
@Override
|
protected int loadDataToCache(Cache cache) {
|
try{
|
Map<String, CacheTreeNode> rootMap = loadRootList();
|
if(rootMap == null || rootMap.size() == 0){
|
logger.info("no root cache loaded in '" + this.getProviderName() + "'.");
|
cache.put(SUPER_ROOT_KEY, createSuperRoot());
|
return 0;
|
}
|
|
/* 加载其他子节点集合,这些不是树结构,都是平级的子对象,需要组装成树 */
|
Map<String, CacheTreeNode> childMap = loadChildList();
|
addListToCache(rootMap.values().iterator(), cache);
|
|
if(childMap != null && childMap.size() > 0){
|
mountTree(childMap, cache);
|
}
|
|
/* 把之前多个根节点删除,合并为一个超根节点 */
|
CacheTreeNode superRoot = createSuperRoot();
|
for(Iterator<Cachable> i = cache.getIterator(); i.hasNext();){
|
superRoot.addChild((CacheTreeNode)(i.next().getValue()));
|
}
|
cache.clear();
|
cache.put(SUPER_ROOT_KEY, superRoot);
|
|
int total = rootMap.size();
|
|
/* 把所有加载过的业务数据以列表平铺的形式放入缓存,可以分别使用 */
|
addListToCache(rootMap.values().iterator(), cache);
|
if(childMap != null){
|
addListToCache(childMap.values().iterator(), cache);
|
total += childMap.size();
|
}
|
|
return total;
|
|
} catch(Exception ex){
|
throw new Error("failed to loading user cache:" + this.getProviderName(), ex);
|
}
|
}
|
|
private CacheTreeNode createSuperRoot(){
|
return new DefaultCacheTreeNode(SUPER_ROOT_KEY, "superRoot", null, null);
|
}
|
|
private void mountTree(Map<String, CacheTreeNode> childMap, Cache cache){
|
CacheTreeNode _node = null;
|
for(Iterator<CacheTreeNode> i = childMap.values().iterator(); i.hasNext();){
|
_node = i.next();
|
mountMiddleNode(_node, childMap, cache);
|
}
|
}
|
|
private void mountMiddleNode(CacheTreeNode currentNode
|
, Map<String, CacheTreeNode> childMap, Cache cache){
|
// logger.debug("-------------> cache = " + cache);
|
// logger.debug("-------------> currentNode = " + currentNode);
|
CacheTreeNode _parentNode = (CacheTreeNode)cache.get(currentNode.getParentId());
|
if(_parentNode == null){
|
// 没有找到上级根节点,说明是比较靠下的子节点
|
_parentNode = childMap.get(currentNode.getParentId());
|
if(_parentNode == null)
|
throw new NullPointerException("parent node not found, current: " + currentNode);
|
_parentNode.addChild(currentNode);
|
mountMiddleNode(_parentNode, childMap, cache);
|
} else if(parentIsRoot(_parentNode.getParentId())) {
|
// 父对象是根节点
|
_parentNode.addChild(currentNode);
|
// logger.debug("找到了挂在root下的子节点:" + _parentNode);
|
}
|
}
|
|
private void addListToCache(Iterator<CacheTreeNode> iterator, Cache cache){
|
for(Iterator<CacheTreeNode> i = iterator; i.hasNext();)
|
addObjectToCache(i.next(), cache);
|
}
|
private void addObjectToCache(CacheTreeNode node, Cache cache){
|
assert (node != null && node.getSource() != null);
|
cache.put(node.getKey(), node);
|
}
|
|
/**
|
* 从业务中加载根节点,即:第一级节点所有数据。</p>
|
* 注意:在树结构中,没有默认的根节点,第一级节点会存在多个,</br>
|
* 也可以认为存在多个根节点。
|
* @return
|
*/
|
protected abstract Map<String, CacheTreeNode> loadRootList();
|
|
/**
|
* 从业务中加载处了第一级节点之外的所有其他节点数据。</p>
|
* 加载的方式由子类实施各种策略,如:大批量的分段加载等。</br>
|
* 这些集合中的对象不是树结构,只要返回包装为<code>CacheTreeNode</code>类型对象即可。</br>
|
* 由系统负责对树的组装。
|
* @return
|
*/
|
protected abstract Map<String, CacheTreeNode> loadChildList();
|
|
/**
|
* 把实体对象转换成<code>CacheTreeNode</code>,由最终业务实现。
|
* @param entity
|
* @return
|
*/
|
protected abstract CacheTreeNode toCacheTreeNode(T entity);
|
|
@Override
|
public void putCacheData(String key, T data){
|
CacheTreeNode node = toCacheTreeNode(data);
|
if(node == null)
|
throw new AbstractMethodError();
|
CacheTreeNode vRoot = this.get(SUPER_ROOT_KEY);
|
if(vRoot != null){
|
if(StringUtils.isEmpty(node.getParentId()) || parentIsRoot(node.getParentId()))
|
vRoot.addChild(node); // 如果没有上级信息,就加入到虚拟根下边。
|
else {
|
CacheTreeNode _parent = vRoot.search(node.getParentId());
|
if(_parent != null){
|
_parent.addChild(node);
|
} else
|
throw new NullPointerException("not found parent in node: " + node);
|
}
|
} else {
|
// 不存在虚拟根节点,说明是第一个元素
|
throw new NullPointerException("not found virtual Root in '" + getProviderName() + "'.");
|
}
|
getCache().put(key, node);
|
}
|
|
@Override
|
public void removeCacheData(String key) {
|
// TODO Auto-generated method stub
|
getCache().remove(key);
|
// CacheTreeNode vRoot = (CacheTreeNode)this.getCacheData(SUPER_ROOT_KEY);
|
CacheTreeNode vRoot = this.get(SUPER_ROOT_KEY);
|
if(vRoot != null){
|
if(StringUtils.isNotEmpty(key)){
|
CacheTreeNode removed = vRoot.remove(key);
|
logger.debug("removed CacheTreeNode: " + removed);
|
}
|
}
|
}
|
|
@Override
|
public void updateCacheData(String key, T data) {
|
// TODO Auto-generated method stub
|
assert (StringUtils.isNotEmpty(key));
|
assert (data != null);
|
CacheTreeNode node = toCacheTreeNode(data);
|
if(node == null)
|
throw new AbstractMethodError();
|
getCache().replace(key, node);
|
// CacheTreeNode vRoot = (CacheTreeNode)this.getCacheData(SUPER_ROOT_KEY);
|
CacheTreeNode vRoot = this.get(SUPER_ROOT_KEY);
|
if(vRoot != null){
|
CacheTreeNode oldNode = vRoot.search(key);
|
if(oldNode != null){
|
oldNode.cloneProperties(node);
|
}
|
}
|
}
|
|
@SuppressWarnings("unchecked")
|
@Override
|
public T getCacheData(String key) {
|
assert (StringUtils.isNotEmpty(key));
|
CacheTreeNode node = get(key);
|
if(node != null && node.getSource() != null){
|
return (T)node.getSource();
|
}
|
// throw new RuntimeException("not found source in CacheTreeNode, not Class T in getCacheData().");
|
return null;
|
}
|
|
@Override
|
public CacheTreeNode get(String key){
|
return (CacheTreeNode)getCache().get(key);
|
// if(node == null)
|
// throw new NullPointerException("not found cache data: " + key);
|
// return node;
|
}
|
|
/**
|
* 根据上级ID判断上级节点是否根节点,通常根节点为0或root表示。
|
* @param parentId
|
* @return
|
*/
|
private boolean parentIsRoot(String parentId){
|
if(parentId.equalsIgnoreCase(ROOT_FLAG_NAME) || parentId.equals(ROOT_FLAG_ZERO))
|
return true;
|
return false;
|
}
|
}
|