Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.arextest.diff.handler.keycompute.ListKeyProcess Maven / Gradle / Ivy
package com.arextest.diff.handler.keycompute;
import com.arextest.diff.model.enumeration.Constant;
import com.arextest.diff.model.exception.ListKeyCycleException;
import com.arextest.diff.model.key.ListSortEntity;
import com.arextest.diff.model.key.ReferenceEntity;
import com.arextest.diff.model.log.LogEntity;
import com.arextest.diff.model.log.NodeEntity;
import com.arextest.diff.utils.JacksonHelperUtil;
import com.arextest.diff.utils.ListUti;
import com.arextest.diff.utils.StringUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ListKeyProcess {
private static final Logger LOGGER = LoggerFactory.getLogger(ListKeyProcess.class);
boolean useFirstElementKey = false;
private List currentNodePath = new ArrayList<>();
private List logs = new ArrayList<>();
private List responseReferences;
private List allListKeys;
//
private HashMap> referenceKeys = new HashMap<>();
// >
private HashMap, HashMap> listIndexKeys = new HashMap<>();
private List currentParentPath;
public ListKeyProcess(List responseReferences,
List allListKeys) {
this.responseReferences = responseReferences;
this.allListKeys = allListKeys;
}
public List getLogs() {
return logs;
}
public HashMap, HashMap> getListIndexKeys() {
return listIndexKeys;
}
/**
* Get the listKey that needs to be calculated first
*
* @param responseReferences
* @param allListKeys
* @return
* @throws ListKeyCycleException
*/
private LinkedList computeReferencedListPriority(
List responseReferences,
List allListKeys) throws ListKeyCycleException {
if (responseReferences == null || responseReferences.isEmpty()) {
return new LinkedList<>();
}
Map> listKeysMap = this.getListKeysMap(allListKeys);
// the collection of fkPaths
Set fkPaths = new HashSet<>();
// the collection of pkNodeListPaths
Set pkListPaths = new HashSet<>();
// fkPath -> the collection of pkNodeListPaths
Map> relations = new HashMap<>();
for (ReferenceEntity re : responseReferences) {
String fkPath = ListUti.convertToString2(re.getFkNodePath());
String pkListPath = ListUti.convertToString2(re.getPkNodeListPath());
fkPaths.add(fkPath);
pkListPaths.add(pkListPath);
relations.computeIfAbsent(fkPath, k -> new HashSet<>()).add(pkListPath);
}
// all traversed node collections
Set traversedSet = new HashSet<>();
LinkedList queue = new LinkedList<>();
this.doPriorityReferences(queue, pkListPaths, new LinkedList<>(), traversedSet, relations,
fkPaths,
listKeysMap);
LinkedList listSortEntityQueue = new LinkedList<>();
String path;
while ((path = queue.poll()) != null) {
for (int i = 0; i < allListKeys.size(); i++) {
ListSortEntity entity = allListKeys.get(i);
if (ListUti.convertToString2(entity.getListNodepath()).equals(path)) {
listSortEntityQueue.add(entity);
break;
}
}
}
return listSortEntityQueue;
}
/**
* find all fkPaths in pkNodeListPath
*
* @param fkPaths the collection of fkPaths
* @param pkNodeListPath pkNodeListPath
* @return
*/
private Set findFkPathInListKey(Set fkPaths, String pkNodeListPath,
Map> listKeysMap) {
List keyPaths = listKeysMap.get(pkNodeListPath);
if (keyPaths == null || keyPaths.isEmpty()) {
return Collections.emptySet();
}
Set matchPath = new HashSet<>(keyPaths.size());
for (String keyPath : keyPaths) {
if (fkPaths.contains(keyPath)) {
matchPath.add(keyPath);
}
}
return matchPath;
}
private Map> getListKeysMap(List allListKeys) {
if (allListKeys == null || allListKeys.isEmpty()) {
return Collections.emptyMap();
}
Map> listKeysMap = new HashMap<>();
for (ListSortEntity listSortEntity : allListKeys) {
String listPath = ListUti.convertToString2(listSortEntity.getListNodepath());
List keyPaths = new ArrayList<>();
for (int i = 0; i < listSortEntity.getKeys().size(); i++) {
String listKeyPath = ListUti
.convertToString2(
mergePath(listSortEntity.getListNodepath(), listSortEntity.getKeys().get(i)));
keyPaths.add(listKeyPath);
}
listKeysMap.put(listPath, keyPaths);
}
return listKeysMap;
}
private void doPriorityReferences(LinkedList queue, Set refLinkNodes,
LinkedList singleLinkAllNodeSet, Set traversedSet,
Map> relations,
Set fkPaths, Map> listKeysMap) throws ListKeyCycleException {
if (refLinkNodes == null || refLinkNodes.isEmpty()) {
return;
}
for (String refLinkNode : refLinkNodes) {
if (singleLinkAllNodeSet.contains(refLinkNode)) {
throw new ListKeyCycleException(
String.format("an infinite loop occurs, path: %s", singleLinkAllNodeSet));
}
if (traversedSet.contains(refLinkNode)) {
continue;
}
queue.addLast(refLinkNode);
traversedSet.add(refLinkNode);
Set refFkNodePaths = findFkPathInListKey(fkPaths, refLinkNode, listKeysMap);
for (String refFkNode : refFkNodePaths) {
singleLinkAllNodeSet.addLast(refLinkNode);
Set refPkListPaths = relations.get(refFkNode);
this.doPriorityReferences(queue, refPkListPaths, singleLinkAllNodeSet, traversedSet,
relations, fkPaths,
listKeysMap);
singleLinkAllNodeSet.removeLast();
}
}
}
// add node name
private String getKeyValueByPath(List relativePath, Object obj) {
String result = null;
if (relativePath == null || relativePath.isEmpty()
|| (relativePath.size() == 1 && relativePath.get(0).equals("%value%"))) {
if (obj != null && !(obj instanceof NullNode) && !"".equals(((JsonNode) obj).asText())) {
String value;
List referencePaths = new ArrayList<>();
for (List list : getReferencePath(currentParentPath)) {
referencePaths.add(ListUti.convertToString2(list));
}
value = ((JsonNode) obj).asText();
if (value.matches("\\d+\\.0+")) {
value = value.substring(0, value.lastIndexOf('.'));
}
if (!referencePaths.isEmpty() && !value.equals("0")) {
int cnt = 0;
for (String referencePath : referencePaths) {
String refKey = null;
if (referenceKeys.containsKey(referencePath)) {
refKey = referenceKeys.get(referencePath).get(value);
}
if (refKey != null) {
cnt++;
value = refKey;
}
}
if (cnt == 0) {
LogEntity log = new LogEntity(
"The referenced node could not be found or the referenced List does not have listKey, fkNodePath: "
+ ListUti.convertToString2(currentParentPath) + ", fkNodeValue: " + value);
logs.add(log);
}
if (cnt > 1) {
LogEntity log = new LogEntity("More than one referenced node, fkNodePath: "
+ ListUti.convertToString2(currentParentPath) + ", fkNodeValue: " + value);
logs.add(log);
}
}
String nodeName = currentParentPath.get(currentParentPath.size() - 1);
StringBuilder sb = new StringBuilder();
if (nodeName != null) {
sb.append("(").append(nodeName).append(":").append(value).append(")");
} else {
sb.append("(").append(value).append(")");
}
result = sb.toString();
}
return replaceArexPrefix(result);
}
if (obj instanceof ObjectNode) {
String path = relativePath.get(0);
ObjectNode jsonObj = (ObjectNode) obj;
if (path.contains("[first]")) {
useFirstElementKey = true;
path = path.substring(0, path.indexOf("[first]"));
} else if (path.contains("[combination]")) {
useFirstElementKey = false;
path = path.substring(0, path.indexOf("[combination]"));
} else {
useFirstElementKey = false;
}
currentParentPath.add(path);
Object subObj = null;
if (path.equals(Constant.DYNAMIC_PATH)) {
List names = JacksonHelperUtil.getNames(jsonObj);
int size = names.size();
if (size > 0) {
List rList = new ArrayList<>(size);
StringBuilder sb = new StringBuilder();
sb.append("{");
for (String name : names) {
subObj = jsonObj.get(name);
if (subObj != null) {
ListUti.removeLast(currentParentPath);
currentParentPath.add(name);
result = getKeyValueByPath(relativePath.subList(1, relativePath.size()), subObj);
if (result != null) {
rList.add(result);
}
}
}
for (String r : rList) {
sb.append(r);
}
sb.append("}");
result = sb.toString();
}
} else {
subObj = jsonObj.get(path);
if (subObj != null) {
result = getKeyValueByPath(relativePath.subList(1, relativePath.size()), subObj);
}
}
currentParentPath.remove(currentParentPath.size() - 1);
} else if (obj instanceof ArrayNode) {
ArrayNode jsonArray = (ArrayNode) obj;
int len = jsonArray.size();
if (len > 0) {
List list = new ArrayList<>(len);
StringBuilder sb = new StringBuilder();
sb.append("[");
if (useFirstElementKey) {
currentParentPath.add(null);
String elementKey = getKeyValueByPath(relativePath, jsonArray.get(0));
if (elementKey != null) {
list.add(elementKey);
}
currentParentPath.remove(currentParentPath.size() - 1);
useFirstElementKey = false;
} else {// combination default
for (int i = 0; i < len; i++) {
currentParentPath.add(null);
String elementKey = getKeyValueByPath(relativePath, jsonArray.get(i));
if (elementKey != null) {
list.add(elementKey);
}
currentParentPath.remove(currentParentPath.size() - 1);
}
}
if (list.size() > 1) {
Collections.sort(list);
}
for (String s : list) {
sb.append(s);
}
sb.append("]");
result = sb.toString();
}
}
return result;
}
public void computeAllListKey(Object obj) throws ListKeyCycleException {
LinkedList priorityListSortEntities =
this.computeReferencedListPriority(responseReferences, allListKeys);
// priority list keys
ListSortEntity listSortEntity;
try {
while ((listSortEntity = priorityListSortEntities.poll()) != null) {
List listNodePath = listSortEntity.getListNodepath();
List> keys = listSortEntity.getKeys();
List referenceNodeRelativePath = listSortEntity.getReferenceNodeRelativePath();
Object object = getObject(obj, listNodePath);
if (!JacksonHelperUtil.isArrayNode(object)) {
LOGGER.warn("list node path is not array node, path: {}", listNodePath);
continue;
}
ArrayNode listObj = (ArrayNode) object;
HashMap referenceKeyValue = new HashMap<>();
referenceKeys.put(
ListUti.convertToString2(mergePath(listNodePath, referenceNodeRelativePath)),
referenceKeyValue);
// traverse list elements, compute pKkey -> listkey
for (int i = 0; i < listObj.size(); i++) {
StringBuilder fullKey = new StringBuilder();
Object listElement = listObj.get(i);
Object refObj = getObject(listElement, referenceNodeRelativePath);
String refValue = refObj == null ? null : StringUtil.objectToString(refObj);
if (keys == null || keys.isEmpty()) {
throw new RuntimeException("ref list node don't have listkey!");
}
for (List path : keys) {
currentParentPath = ListUti.deepCopy(listNodePath);
currentParentPath.add(null);
String currentKey = getKeyValueByPath(path, listElement);
if (currentKey != null) {
fullKey.append(currentKey);
}
}
// if refValue repeat, log
referenceKeyValue.put(refValue, fullKey.toString());
}
}
} catch (Throwable throwable) {
LOGGER.error("computePriorityListSort error", throwable);
}
// other normal list keys,traverse the whole tree
// currentNodePath.add(new NodeEntity("root", 0));
computeNormalListKey(obj);
}
public void computeNormalListKey(Object obj) {
if (obj instanceof ObjectNode) {
ObjectNode jsonObj = (ObjectNode) obj;
List names = JacksonHelperUtil.getNames(jsonObj);
for (String fieldName : names) {
currentNodePath.add(new NodeEntity(fieldName, 0));
Object objFieldValue = jsonObj.get(fieldName);
computeNormalListKey(objFieldValue);
currentNodePath.remove(currentNodePath.size() - 1);
}
} else if (obj instanceof ArrayNode) {
ArrayNode objArray = (ArrayNode) obj;
ListSortEntity listSortEntity = findListKeys(currentNodePath);
if (listSortEntity != null) {
HashMap indexKeys = new HashMap<>();
for (int i = 0; i < objArray.size(); i++) {
StringBuilder fullKey = new StringBuilder();
currentNodePath.add(new NodeEntity(null, i));
Object listElement = objArray.get(i);
for (List path : listSortEntity.getKeys()) {
currentParentPath = ListUti.deepCopy(listSortEntity.getListNodepath());
currentParentPath.add(null);
String currentKey = getKeyValueByPath(path, listElement);
if (currentKey != null) {
fullKey.append(currentKey);
}
}
indexKeys.put(i, fullKey.toString());
computeNormalListKey(listElement);
currentNodePath.remove(currentNodePath.size() - 1);
}
if (!indexKeys.isEmpty()) {
listIndexKeys.put(new ArrayList<>(currentNodePath), indexKeys);
}
} else {
for (int i = 0; i < objArray.size(); i++) {
currentNodePath.add(new NodeEntity(null, i));
Object listElement = objArray.get(i);
computeNormalListKey(listElement);
currentNodePath.remove(currentNodePath.size() - 1);
}
}
}
}
private Object getObject(Object obj, List listNodePath) {
for (String s : listNodePath) {
if (!(JacksonHelperUtil.isObjectNode(obj))) {
return null;
}
obj = ((ObjectNode) obj).get(s);
}
return obj;
}
private List mergePath(List path1, List path2) {
List newPath = new ArrayList<>();
newPath.addAll(path1);
newPath.addAll(path2);
return newPath;
}
private List> getReferencePath(List currentPath) {
List> refPkPaths = new ArrayList<>();
List paths = new ArrayList<>();
for (String s : currentPath) {
if (s != null) {
paths.add(s);
}
}
List list;
for (ReferenceEntity responseReference : responseReferences) {
List fkNodePath = responseReference.getFkNodePath();
if ("%value%".equals(fkNodePath.get(fkNodePath.size() - 1))) {
fkNodePath = fkNodePath.subList(0, fkNodePath.size() - 1);
}
// support dynamic path
if (ListUti.stringListEqualsOnWildcard(paths, fkNodePath)) {
list = responseReference.getPkNodePath();
refPkPaths.add(list);
}
}
return refPkPaths;
}
private ListSortEntity findListKeys(List path) {
List pathWithoutIndex = new ArrayList<>();
for (NodeEntity nodeEntity : path) {
if (nodeEntity.getNodeName() != null) {
pathWithoutIndex.add(nodeEntity.getNodeName());
}
}
if (pathWithoutIndex.isEmpty()) {
pathWithoutIndex.add("");
}
for (ListSortEntity listSortEntity : allListKeys) {
// support dynamic path
if (ListUti.stringListEqualsOnWildcard(listSortEntity.getListNodepath(), pathWithoutIndex)) {
return listSortEntity;
}
}
return null;
}
private String replaceArexPrefix(String key) {
if (StringUtil.isEmpty(key)) {
return key;
}
for (String prefix : Constant.PREFIX_SET) {
key = key.replace(prefix, "");
}
return key;
}
}