Преглед изворни кода

patch_ncc2005_UFOE树形档案访问器错误编码导致取不到数_集团赵亮_阳东波_集团老师赵亮合并20220620_V1.0

wenfx пре 3 година
родитељ
комит
37134011f1
1 измењених фајлова са 654 додато и 0 уклоњено
  1. 654 0
      baseapp_patch/src/public/nc/vo/bd/accessor/HierachicalDataAccessor.java

+ 654 - 0
baseapp_patch/src/public/nc/vo/bd/accessor/HierachicalDataAccessor.java

@@ -0,0 +1,654 @@
+package nc.vo.bd.accessor;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+
+import nc.pubitf.bd.accessor.IAccessorQueryService;
+import nc.pubitf.bd.accessor.IAccessorVisibleUtil;
+import nc.pubitf.bd.accessor.IGeneralAccessor;
+import nc.vo.bd.access.tree.AbastractTreeCreateStrategy;
+import nc.vo.bd.access.tree.BDTreeCreator;
+import nc.vo.bd.pub.BDCacheFactory;
+import nc.vo.bd.pub.BDCacheMiscUtil;
+import nc.vo.cache.ICache;
+import nc.vo.pub.BusinessException;
+
+import nccloud.commons.collections.CollectionUtils;
+import nccloud.commons.lang.StringUtils;
+
+/**
+ * 树型结构的数据访问器
+ * 
+ * @author liujian
+ * 
+ */
+public class HierachicalDataAccessor implements IGeneralAccessor {
+
+	static class CoreData implements Serializable{
+		private static final long serialVersionUID = 1L;
+
+		private Set<String> cachedOrgs = new HashSet<String>();
+
+		private DefaultTreeModel model;
+
+		private Map<String, DefaultMutableTreeNode> pk_treenode_map = new HashMap<String, DefaultMutableTreeNode>();
+
+		private String version;
+
+		CoreData(List<IBDData> datas, String version) {
+			// 构造树结构
+			model = BDTreeCreator.createTree(datas.toArray(new IBDData[0]),
+					new TreeStrategy());
+			// 构造主键_树结点_map, 并记录组织集合
+			pk_treenode_map = hashlizeTreeModel(model);
+			this.version = version;
+
+		}
+
+		/**
+		 * 返回所有缓存的IHierachicalData数据.
+		 * 
+		 * @return
+		 */
+		List<IBDData> extractDatas() {
+			Map<String, DefaultMutableTreeNode> map = pk_treenode_map;
+			Collection<DefaultMutableTreeNode> vs = map.values();
+			List<IBDData> datas = new ArrayList<IBDData>();
+
+			for (DefaultMutableTreeNode node : vs) {
+				datas.add((IBDData) node.getUserObject());
+			}
+			return datas;
+		}
+
+		DefaultTreeModel getModel() {
+			return model;
+		}
+
+		/**
+		 * 根据主键查询树结点
+		 * 
+		 * @param pk
+		 * @return
+		 */
+		DefaultMutableTreeNode getNodeByPk(String pk) {
+			DefaultMutableTreeNode node = pk_treenode_map.get(pk);
+			return node;
+		}
+
+		String getVersion() {
+			return version;
+		}
+
+		/**
+		 * 构造主键_树结点_map, 并记录组织集合
+		 * 
+		 * @param m
+		 * @return
+		 */
+		@SuppressWarnings("unchecked")
+		private Map<String, DefaultMutableTreeNode> hashlizeTreeModel(
+				DefaultTreeModel m) {
+			DefaultMutableTreeNode root = (DefaultMutableTreeNode) m.getRoot();
+
+			Enumeration<DefaultMutableTreeNode> e = root.preorderEnumeration();
+			e.nextElement();
+			Map<String, DefaultMutableTreeNode> result = new HashMap<String, DefaultMutableTreeNode>();
+			while (e.hasMoreElements()) {
+				DefaultMutableTreeNode node = e.nextElement();
+				if (node.getUserObject() instanceof IBDData) {
+					IBDData data = (IBDData) node.getUserObject();
+					data.setLevel(node.getLevel());
+					// data.setLeaf(node.isLeaf());
+					result.put(data.getPk(), node);
+					cachedOrgs.add(data.getPk_org());
+				}
+			}
+			return result;
+		}
+
+		/**
+		 * 指定组织的数据是否已经缓存.
+		 * 
+		 * @param pk_org
+		 * @return
+		 */
+		public boolean isOrgCached(String pk_org) {
+			return cachedOrgs.contains(pk_org);
+		}
+	}
+
+	public static class TreeStrategy extends AbastractTreeCreateStrategy {
+
+		@Override
+		public String getCodeRule() {
+			return "2/2/2"; // 现在除科目外的所有档案均为主键树,此方法无意义
+		}
+
+		@Override
+		public Object getCodeValue(Object obj) {
+			return null;
+		}
+
+		@Override
+		public Object getNodeId(Object obj) {
+			if (obj instanceof IBDData) {
+				IBDData data = (IBDData) obj;
+				return data.getPk();
+			}
+			return null;
+
+		}
+
+		@Override
+		public Object getParentNodeId(Object obj) {
+			if (obj instanceof IBDData) {
+				IBDData data = (IBDData) obj;
+				return data.getParentPk();
+			}
+			return null;
+		}
+
+		@Override
+		public boolean isCodeTree() {
+			return false;
+		}
+
+	}
+
+	private static final String COREDATA_CACHE_KEY = "CoreDataCacheKey";
+
+	private String beanid;
+
+	private CoreData coreData = null;
+
+	private Map<String, CoreData> coreDataCacheMap = null;
+
+	private IGeneralAccessor generalAccesor;
+
+	private Set<String> loadedOrg = new HashSet<String>();
+
+	private IAccessorQueryService queryService = new HierachicalDataCacheService();
+
+	private ReadWriteLock rwlock = new ReentrantReadWriteLock();
+
+	private IAccessorVisibleUtil visibleUitl = AccessorVisibleScopeUtil
+			.getInstance();
+
+	protected HierachicalDataAccessor() {
+	}
+
+	public HierachicalDataAccessor(String beanid) {
+		this.beanid = beanid;
+		generalAccesor = new GeneralAccessor(beanid);
+		initCoreData();
+	}
+
+	public void clearCacheData() {
+		setCoreData(new CoreData(new ArrayList<IBDData>(), ""));
+		generalAccesor.clearCacheData();
+	}
+
+	private IBDData clone(IBDData data) {
+		if (data == null)
+			return null;
+		return data.clone();
+	}
+
+	private List<IBDData> clone(List<IBDData> datas) {
+		if (datas == null || datas.size() == 0)
+			return null;
+		List<IBDData> result = new ArrayList<IBDData>();
+		for (IBDData data : datas) {
+			result.add(clone(data));
+		}
+		return result;
+	}
+
+	private ArrayList<IBDData> combineDatas(List<IBDData> datasInCache,
+			List<IBDData> datas) {
+		Map<String, IBDData> pk_data_map = new HashMap<String, IBDData>();
+		for (IBDData data : datasInCache) {
+			pk_data_map.put(data.getPk(), data);
+		}
+		for (IBDData data : datas) {
+			pk_data_map.put(data.getPk(), data);
+		}
+
+		ArrayList<IBDData> result = new ArrayList<IBDData>();
+		result.addAll(pk_data_map.values());
+
+		return result;
+	}
+
+	@SuppressWarnings("unused")
+	private ArrayList<String> extractPKs(List<IBDData> datas) {
+		ArrayList<String> pks = new ArrayList<String>();
+		for (IBDData data : datas) {
+			pks.add(data.getPk());
+		}
+		return pks;
+	}
+
+	private DefaultMutableTreeNode findNodeByPkLoadDataIfNecessary(
+			String pk_org, String pk_doc) {
+		if (pk_doc == null)
+			return null;
+		CoreData core = getCoreData();
+
+		DefaultMutableTreeNode node = core.getNodeByPk(pk_doc);
+
+		// pk_doc找到对应数据而且(pk_org的数据已经在缓存中 或者 之前已经尝试加载过pk_org或其等价组织的数据)
+		if (node != null
+				&& (core.isOrgCached(pk_org) || loadedOrg
+						.contains(getVisibleUitl().getEquivalentPkOrg(beanid,
+								pk_org)))) {
+			return node;
+		} else {
+
+			// 原因有三
+			// 1.查询了未缓存的组织的数据
+			// 2.版本过期,有新增数据
+			// 3.错误的pk
+			synchronized (this) {
+				node = core.getNodeByPk(pk_doc);
+
+				if (node == null) {
+					loadDatasByPkOrg(pk_org);
+					// 很重要,必须重新获取core
+					core = getCoreData();
+					node = core.getNodeByPk(pk_doc);
+					// if(node==null) 我们需要黑名单
+				}
+			}
+
+			return node;
+		}
+	}
+
+	public List<IBDData> getChildDocs(String pk_org, String pk_doc,
+			boolean isIncludeSelf) {
+
+		DefaultMutableTreeNode node = findNodeByPkLoadDataIfNecessary(pk_org,
+				pk_doc);
+
+		if (node == null)
+			return new ArrayList<IBDData>();
+
+		@SuppressWarnings("unchecked")
+		Enumeration<DefaultMutableTreeNode> e = node.preorderEnumeration();
+		// 排除自身
+		e.nextElement();
+
+		List<IBDData> datas = new ArrayList<IBDData>();
+		if (isIncludeSelf) {
+			datas.add((IBDData) node.getUserObject());
+		}
+		while (e.hasMoreElements()) {
+			DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode) e
+					.nextElement();
+			datas.add((IBDData) tempNode.getUserObject());
+
+		}
+		datas = getVisibleUitl()
+				.filterDataByVisibleScope(datas, pk_org, beanid);
+
+		return clone(datas);
+
+	}
+
+	@Override
+	public String getClassTypeID() {
+		return this.beanid;
+	}
+
+	CoreData getCoreData() {
+		// 加读锁
+		rwlock.readLock().lock();
+		try {
+			CoreData result = coreData;
+			return result;
+		} finally {
+			rwlock.readLock().unlock();
+		}
+
+	}
+
+	@SuppressWarnings("unchecked")
+	private Map<String, CoreData> getCoreDataCacheMap() {
+		if (coreDataCacheMap == null) {
+			String regionName = ACCESSOR_REGIONNAME_PREFIX + this.beanid;
+			ICache cache = BDCacheFactory.getCacheWithFileStratery(regionName);
+			coreDataCacheMap = cache.toMap();
+		}
+		return coreDataCacheMap;
+	}
+
+	@Override
+	public IBDData getDocByCode(String pk_org, String docCode) {
+		IBDData[] data = getDocByCodes(pk_org, new String[] { docCode });
+		if (data != null && data.length > 0)
+			return data[0];
+		return null;
+	}
+
+	private List<IBDData> getDocByCodeInCache(List<IBDData> cacheData, String code) {
+		List<IBDData> dataList = new ArrayList<IBDData>();
+		if (cacheData == null || cacheData.size() == 0
+				|| StringUtils.isEmpty(code))
+			return null;
+		for (IBDData datum : cacheData) {
+			if (code.equals(datum.getCode()))
+				dataList.add(clone(datum));
+//				return clone(datum);
+		}
+		return dataList;
+	}
+
+	@Override
+	public IBDData[] getDocByCodes(String pk_org, String[] docCodes) {
+		if (StringUtils.isEmpty(pk_org) || docCodes == null
+				|| docCodes.length == 0)
+			return new IBDData[0];
+		List<IBDData> result = new ArrayList<IBDData>();
+		if (!loadedOrg.contains(getVisibleUitl().getEquivalentPkOrg(beanid,
+				pk_org))) {
+			loadDatasByPkOrg(pk_org);
+		}
+		CoreData core = getCoreData();
+		// 本组织可见的已缓存数据
+//		List<IBDData> cacheData = getVisibleUitl().filterDataByVisibleScope(
+//				core.extractDatas(), pk_org, this.beanid);
+//		for (int i = 0; i < result.length; i++) {
+//			result[i] = getDocByCodeInCache(cacheData, docCodes[i]);
+//		}
+		List<IBDData> coredata = core.extractDatas();
+		
+		List<IBDData> cacheData = getVisibleUitl().filterDataByVisibleScope(core.extractDatas(), pk_org, this.beanid);
+		
+		for (int i = 0; i < docCodes.length; i++) {
+			List<IBDData> bdDatas = getDocByCodeInCache(cacheData, docCodes[i]);
+			if(bdDatas == null || bdDatas.size() == 0){
+				result.add(null);
+			}else{
+				result.addAll(bdDatas);
+			}
+			
+		}
+		// 本组织可见的已缓存数据
+//		result  = getVisibleUitl().filterDataByVisibleScope(
+//				result, pk_org, this.beanid);
+		return result.toArray(new IBDData[0]);
+	}
+
+	@Override
+	public IBDData[] getDocByNamesWithMainLang(String pk_org, String[] docNames) {
+		if (StringUtils.isEmpty(pk_org) || docNames == null
+				|| docNames.length == 0)
+			return new IBDData[0];
+		IBDData[] result = new IBDData[docNames.length];
+		if (!loadedOrg.contains(getVisibleUitl().getEquivalentPkOrg(beanid,
+				pk_org))) {
+			loadDatasByPkOrg(pk_org);
+		}
+		CoreData core = getCoreData();
+		// 本组织可见的已缓存数据
+		List<IBDData> cacheData = getVisibleUitl().filterDataByVisibleScope(
+				core.extractDatas(), pk_org, this.beanid);
+		for (int i = 0; i < result.length; i++) {
+			result[i] = getDocByNameWithMainLanguageInCache(cacheData,
+					docNames[i]);
+		}
+		return result;
+	}
+
+	@Override
+	public IBDData getDocByNameWithMainLang(String pk_org, String docName) {
+		IBDData[] data = getDocByNamesWithMainLang(pk_org,
+				new String[] { docName });
+		if (data != null && data.length > 0)
+			return data[0];
+		return null;
+	}
+
+	private IBDData getDocByNameWithMainLanguageInCache(
+			List<IBDData> cacheData, String name) {
+		if (cacheData == null || cacheData.size() == 0
+				|| StringUtils.isEmpty(name))
+			return null;
+		for (IBDData datum : cacheData) {
+			if (name.equals(datum.getName().getText()))
+				return clone(datum);
+		}
+		return null;
+	}
+
+	public IBDData getDocByPk(String docPk) {
+		// 先从树上找,没有就委托给generalAccessor
+		IBDData result = getIBDDataFromTree(docPk);
+
+		if (result == null) {
+			result = generalAccesor.getDocByPk(docPk);
+		}
+		return result;
+	}
+
+	public IBDData[] getDocbyPks(String[] docPks) {
+		if (docPks == null)
+			return new IBDData[0];
+		LinkedHashMap<String, IBDData> pk_doc_map = new LinkedHashMap<String, IBDData>();
+		List<String> notMatchPKs = new ArrayList<String>();
+		IBDData[] resultsFromTree = getIBDDatasFromTree(docPks);
+
+		for (int i = 0; i < docPks.length; i++) {
+			String pk = docPks[i];
+			IBDData data = resultsFromTree[i];
+			pk_doc_map.put(pk, data);
+			if (data == null) {
+				notMatchPKs.add(pk);
+			}
+		}
+
+		IBDData[] resultFromGA = generalAccesor.getDocbyPks(notMatchPKs
+				.toArray(new String[0]));
+
+		if (resultFromGA != null) {
+			for (IBDData data : resultFromGA) {
+				if (data != null) {
+					pk_doc_map.put(data.getPk(), data);
+				}
+			}
+		}
+		IBDData[] data = new IBDData[docPks.length];
+		for (int i = 0; i < docPks.length; i++) {
+			data[i] = clone(pk_doc_map.get(docPks[i]));
+		}
+		return data;
+	}
+	
+	
+
+	@Override
+	public List<IBDData> getFatherDocs(String pk_org, String pk_doc,
+			boolean isIncludeSelf) {
+		DefaultMutableTreeNode node = findNodeByPkLoadDataIfNecessary(pk_org,
+				pk_doc);
+		if (node == null)
+			return new ArrayList<IBDData>();
+
+		List<IBDData> datas = new ArrayList<IBDData>();
+		TreeNode[] path = node.getPath();
+		for (int i = path.length - 1; i >= 0; i--) {
+			DefaultMutableTreeNode obj = (DefaultMutableTreeNode) path[i];
+			if (obj != null && obj.getUserObject() != null
+					&& obj.getUserObject() instanceof IBDData) {
+				if (path[i] != node) {
+					datas.add((IBDData) obj.getUserObject());
+				} else if (isIncludeSelf) {
+					datas.add((IBDData) obj.getUserObject());
+				}
+			}
+		}
+		return clone(datas);
+	}
+
+	@Override
+	public List<IBDData> getFirstLevelDocs(String pk_org) {
+
+		if (!loadedOrg.contains(getVisibleUitl().getEquivalentPkOrg(beanid,
+				pk_org))) {
+			loadDatasByPkOrg(pk_org);
+		}
+		List<IBDData> dataList = new ArrayList<IBDData>();
+		CoreData core = getCoreData();
+		DefaultMutableTreeNode root = (DefaultMutableTreeNode) core.getModel()
+				.getRoot();
+		int childCount = root.getChildCount();
+		for (int i = 0; i < childCount; i++) {
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode) root
+					.getChildAt(i);
+			if (node != null && node.getUserObject() != null
+					&& node.getUserObject() instanceof IBDData) {
+				dataList.add((IBDData) node.getUserObject());
+			}
+		}
+		return clone(getVisibleUitl().filterDataByVisibleScope(dataList,
+				pk_org, beanid));
+	}
+
+	private IBDData getIBDDataFromTree(String docPk) {
+		IBDData[] datas = getIBDDatasFromTree(new String[] { docPk });
+		return datas[0];
+	}
+
+	private IBDData[] getIBDDatasFromTree(String[] docPks) {
+		CoreData cd = getCoreData();
+		IBDData[] results = new IBDData[docPks.length];
+		for (int i = 0; i < docPks.length; i++) {
+			String docPk = docPks[i];
+			DefaultMutableTreeNode node = cd.getNodeByPk(docPk);
+			IBDData result = null;
+			if (node != null) {
+				result = ((IBDData) node.getUserObject());
+			}
+			results[i] = clone(result);
+		}
+		return results;
+	}
+
+	@Override
+	public IAccessorQueryService getQueryService() {
+		return this.queryService;
+	}
+
+	@Override
+	public IAccessorVisibleUtil getVisibleUitl() {
+		return this.visibleUitl;
+	}
+
+	private void initCoreData() {
+		String dsName = BDCacheMiscUtil.getCurrentDatasourceName();
+		this.coreData = getCoreDataCacheMap().get(dsName + COREDATA_CACHE_KEY);
+		if (this.coreData == null) {
+			setCoreData(new CoreData(new ArrayList<IBDData>(), ""));
+		}
+	}
+
+	@Override
+	public boolean isHaslevel() {
+		return true;
+	}
+
+	@Override
+	public boolean isLeaf(String pk_org, String pk_doc) {
+//		DefaultMutableTreeNode node = findNodeByPkLoadDataIfNecessary(pk_org,
+//				pk_doc);
+//		if (node != null)
+//			return node.isLeaf();
+//		return false;
+		List<IBDData> children = this.getChildDocs(pk_org, pk_doc, false);
+		return CollectionUtils.isEmpty(children);
+	}
+
+	/**
+	 * 根据管控模式中指定的可见性加载,从pk_org角度所能看到的数据。
+	 * 
+	 * @param pk_org
+	 * @throws BusinessException 
+	 */
+	// TODO: 没有定义管控模式,怎么处理?
+	// TODO: 当组织能看到集团的数据, 加载不同组织时,需要避免重复加载集团数据
+	// TODO: 加载数据出来后要放到treemodel里去
+	protected synchronized void loadDatasByPkOrg(String pk_org)  {
+
+		// 把pk_org根据可见性转换成更高等级的pk_org
+
+		pk_org = getVisibleUitl().getEquivalentPkOrg(beanid, pk_org);
+
+		HierachicalDataCacheLoadingResult result = getQueryService()
+				.loadDatasByPkOrgFromBD(pk_org, beanid,
+						getCoreData() == null ? "" : getCoreData().getVersion());
+
+		List<IBDData> datas = result.getDatas();
+
+		if (datas.size() > 0) {
+
+			boolean outOfData = !StringUtils.equals(getCoreData().getVersion(),
+					result.getNewVersion());
+
+			if (outOfData) {
+				// sortDatas((ArrayList<IBDData>) datas);
+				setCoreData(new CoreData(datas, result.getNewVersion()));
+				loadedOrg.clear();
+			} else {
+				List<IBDData> datasInCache = getCoreData().extractDatas();
+				ArrayList<IBDData> combinedDatas = combineDatas(datasInCache,
+						datas);
+				// sortDatas(combinedDatas);
+				setCoreData(new CoreData(combinedDatas, result.getNewVersion()));
+			}
+		}
+		loadedOrg.add(pk_org);
+
+	}
+
+	void setBeanid(String beanid) {
+		this.beanid = beanid;
+		generalAccesor = new GeneralAccessor(beanid);
+		initCoreData();
+	}
+
+	private void setCoreData(CoreData coreData) {
+		rwlock.writeLock().lock();
+		try {
+			this.coreData = coreData;
+			String dsName = BDCacheMiscUtil.getCurrentDatasourceName();
+			getCoreDataCacheMap().put(dsName + COREDATA_CACHE_KEY, this.coreData);
+		} finally {
+			rwlock.writeLock().unlock();
+		}
+
+	}
+
+	public void setQueryService(IAccessorQueryService service) {
+		this.queryService = service;
+	}
+
+	public void setVisibleUitl(IAccessorVisibleUtil visibleUitl) {
+		this.visibleUitl = visibleUitl;
+	}
+}