All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arextest.diff.handler.pathparse.JsonPathExpressionHandler Maven / Gradle / Ivy

There is a newer version: 0.2.15
Show newest version
package com.arextest.diff.handler.pathparse;

import com.arextest.diff.factory.TaskThreadFactory;
import com.arextest.diff.model.RulesConfig;
import com.arextest.diff.model.enumeration.Constant;
import com.arextest.diff.model.pathparse.ExpressionNodeEntity;
import com.arextest.diff.model.pathparse.ExpressionNodeType;
import com.arextest.diff.model.pathparse.expression.EqualsExpression;
import com.arextest.diff.model.pathparse.expression.PathExpression;
import com.arextest.diff.utils.ListUti;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Logger;

public class JsonPathExpressionHandler {

  private static final Logger LOGGER = Logger.getLogger(JsonPathExpressionHandler.class.getName());

  public void doExpressionParse(RulesConfig rulesConfig,
      Object baseObj, Object testObj) throws ExecutionException, InterruptedException {

    Map>, LinkedList>>
        conditionExclusions = null;

    try {
      List> expressionExclusions = rulesConfig.getExpressionExclusions();

      CompletableFuture, LinkedList>>>
          future1 = CompletableFuture.supplyAsync(
          () -> doMultiExpressionParse(expressionExclusions, baseObj),
          TaskThreadFactory.jsonObjectThreadPool
      );

      CompletableFuture, LinkedList>>>
          future2 = CompletableFuture.supplyAsync(
          () -> doMultiExpressionParse(expressionExclusions, testObj),
          TaskThreadFactory.jsonObjectThreadPool
      );

      CompletableFuture voidCompletableFuture = CompletableFuture.allOf(future1, future2);
      voidCompletableFuture.get(Constant.JSON_PATH_PARSE_MINUTES_TIME, TimeUnit.MINUTES);

      Map, LinkedList>> baseExpression = future1.get();
      Map, LinkedList>> testExpression = future2.get();
      conditionExclusions = mergeExpression(baseExpression, testExpression);

    } catch (RuntimeException | TimeoutException e) {
      LOGGER.warning("doExpressionParse error: " + e.getMessage());
    }
    rulesConfig.setConditionExclusions(conditionExclusions);
  }

  public Map, LinkedList>> doMultiExpressionParse(
      List> expressionExclusions, Object object) {
    Map, LinkedList>> result =
        new HashMap<>();

    try {
      if (ListUti.isEmpty(expressionExclusions)) {
        return result;
      }

      for (List expressionNodeEntityList : expressionExclusions) {
        LinkedList> linkedLists = doSinglePathExpressionParse(
            expressionNodeEntityList, 0, expressionNodeEntityList.size(), object, false);
        if (linkedLists != null) {
          result.put(expressionNodeEntityList, linkedLists);
        }
      }
    } catch (RuntimeException exception) {
      LOGGER.warning("doMultiExpressionParse error: " + exception.getMessage());
    }
    return result;
  }


  /**
   * response/students/[i] response/students/[i]/info response/su/[i]/info
   * response/students/[info/name="xiaomi"] response/students/[info/name="xiaomi"]/age
   * response/students/[info/name="xiaomi"]/info/name response/students/info/[name="xiaomi"]
   * response/[region="beijing"] response/students[%value%="NO.111"]
   *
   * @return
   */
  private LinkedList> doSinglePathExpressionParse(
      List expressionNodeEntityList,
      int startIndex, int endIndex, Object object, boolean isArr) {

    LinkedList> result = null;

    if (startIndex >= endIndex) {
      return new LinkedList<>();
    }

    if (object == null) {
      return result;
    }

    ExpressionNodeEntity expressionNodeEntity = expressionNodeEntityList.get(startIndex);
    int nodeType = expressionNodeEntity.getNodeType();

    if (nodeType == ExpressionNodeType.NAME_NODE) {

      String nodeName = expressionNodeEntity.getNodeName();
      if (object instanceof ObjectNode) {
        Object nextObj = ((ObjectNode) object).get(nodeName);
        LinkedList> localPath = doSinglePathExpressionParse(
            expressionNodeEntityList, startIndex + 1, endIndex,
            nextObj, false);
        result = appendExpressionNameNode(localPath, nodeName);

      } else if (object instanceof ArrayNode) {

        // condition: fuzzy paths
        ArrayNode arrayNode = (ArrayNode) object;
        for (int i = 0; i < arrayNode.size(); i++) {
          Object nextObj = arrayNode.get(i);
          LinkedList> localPath = doSinglePathExpressionParse(
              expressionNodeEntityList, startIndex, endIndex,
              nextObj, true);
          if (localPath != null) {
            if (result == null) {
              result = new LinkedList<>();
            }
            result.addAll(appendExpressionIndexNode(localPath, i));
          }
        }

      } else {
        // todo: %value%
      }

    } else if (nodeType == ExpressionNodeType.EXPRESSION_NODE) {

      PathExpression expression = expressionNodeEntity.getExpression();
      if (expression instanceof EqualsExpression) {

        if (object instanceof ObjectNode) {
          EqualsExpression equalsExpression = (EqualsExpression) expression;
          boolean verified = verifyExpression((ObjectNode) object, equalsExpression);
          if (verified) {
            if (isArr) {
              result = doSinglePathExpressionParse(
                  expressionNodeEntityList, startIndex + 1, endIndex,
                  object, false);
            } else {
              // determine whether it is the last node. If it is not the last node, it is invalid.
              if (startIndex == endIndex - 1) {
                List leftValue = equalsExpression.getLeftValue();
                LinkedList expressionNodeEntities = new LinkedList<>();
                for (String pathName : leftValue) {
                  expressionNodeEntities.add(
                      new ExpressionNodeEntity(pathName, ExpressionNodeType.NAME_NODE));
                }
                result = new LinkedList<>();
                result.add(expressionNodeEntities);
              }
            }

          }
        } else if (object instanceof ArrayNode) {
          ArrayNode arrayNode = (ArrayNode) object;
          for (int i = 0; i < arrayNode.size(); i++) {
            Object nextObj = arrayNode.get(i);
            LinkedList> localPath = doSinglePathExpressionParse(
                expressionNodeEntityList, startIndex, endIndex,
                nextObj, true);

            if (localPath != null) {
              if (result == null) {
                result = new LinkedList<>();
              }
              result.addAll(appendExpressionIndexNode(localPath, i));
            }
          }
        } else {
          // todo: %value%
        }
      }

    } else if (nodeType == ExpressionNodeType.INDEX_NODE) {

      if (object instanceof ArrayNode) {
        int arrIndex = expressionNodeEntity.getIndex();
        ArrayNode arrayNode = (ArrayNode) object;
        Object nextObj = arrayNode.get(arrIndex);
        LinkedList> localPath = doSinglePathExpressionParse(
            expressionNodeEntityList, startIndex + 1, endIndex, nextObj, true);
        result = appendExpressionIndexNode(localPath, arrIndex);

      } else {
        // If invalid, localPath is discarded.
      }

    } else {
      // unknown node type, no processing
    }

    return result;
  }

  private boolean verifyExpression(ObjectNode objectNode, EqualsExpression expressionNodeEntity) {
    List leftValue = expressionNodeEntity.getLeftValue();
    String valueFormPath = getValueFormPath(objectNode, leftValue);
    String equalsValue = expressionNodeEntity.getRightValue();
    return Objects.equals(valueFormPath, equalsValue);
  }

  private LinkedList> appendExpressionNameNode(
      LinkedList> localPath,
      String nodeName) {

    LinkedList> result = new LinkedList<>();

    if (localPath == null) {
      return null;
    }

    if (localPath.isEmpty()) {
      LinkedList expressionList = new LinkedList<>();
      expressionList.add(new ExpressionNodeEntity(nodeName, ExpressionNodeType.NAME_NODE));
      result.add(expressionList);
      return result;
    }

    for (LinkedList expressionNodeEntityList : localPath) {
      if (expressionNodeEntityList != null) {
        expressionNodeEntityList.addFirst(
            new ExpressionNodeEntity(nodeName, ExpressionNodeType.NAME_NODE));
        result.add(expressionNodeEntityList);
      }
    }
    return result;
  }

  private LinkedList> appendExpressionIndexNode(
      LinkedList> localPath, int index) {
    LinkedList> result = new LinkedList<>();

    if (localPath == null) {
      return null;
    }

    if (localPath.isEmpty()) {
      LinkedList expressionList = new LinkedList<>();
      expressionList.add(new ExpressionNodeEntity(index, ExpressionNodeType.INDEX_NODE));
      result.add(expressionList);
      return result;
    }

    for (LinkedList expressionNodeEntityList : localPath) {
      if (expressionNodeEntityList != null) {
        expressionNodeEntityList.addFirst(
            new ExpressionNodeEntity(index, ExpressionNodeType.INDEX_NODE));
        result.add(expressionNodeEntityList);
      }
    }
    return result;
  }

  private String getValueFormPath(Object objectNode, List pathList) {
    if (ListUti.isEmpty(pathList)) {
      return null;
    }

    try {
      for (String path : pathList) {
        objectNode = ((ObjectNode) objectNode).get(path);
      }
      return objectNode instanceof TextNode ? ((TextNode) objectNode).asText()
          : objectNode.toString();
    } catch (RuntimeException e) {
    }
    return null;
  }


  private Map>, LinkedList>> mergeExpression(
      Map, LinkedList>> baseExpression,
      Map, LinkedList>> testExpression) {

    Map>, LinkedList>> result = new HashMap<>();

    Set> baseExpressionKeySet = baseExpression.keySet();
    Set> testExpresssionKeyset = testExpression.keySet();

    // get the intersection of the two sets
    Set> temp = new HashSet<>(baseExpressionKeySet);
    temp.retainAll(testExpresssionKeyset);

    for (Entry, LinkedList>> entry : baseExpression.entrySet()) {
      List key = entry.getKey();
      LinkedList> baseValue = entry.getValue();
      if (temp.contains(key)) {
        LinkedList> testValue = testExpression.get(key);
        result.put(baseValue, testValue);
      } else {
        result.put(baseValue, null);
      }
    }

    for (Entry, LinkedList>> entry : testExpression.entrySet()) {
      List key = entry.getKey();
      LinkedList> testValue = entry.getValue();
      if (!temp.contains(key)) {
        result.put(null, testValue);
      }
    }
    return result;
  }

}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy