diff options
Diffstat (limited to 'cps-path-parser/src')
5 files changed, 130 insertions, 33 deletions
diff --git a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 index 86c1705617..c88a822654 100644 --- a/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 +++ b/cps-path-parser/src/main/antlr4/org/onap/cps/cpspath/parser/antlr4/CpsPath.g4 @@ -47,13 +47,15 @@ listElementRef : OB leafCondition ( booleanOperators leafCondition)* CB ; multipleLeafConditions : OB leafCondition ( booleanOperators leafCondition)* CB ; -leafCondition : AT leafName EQ ( IntegerLiteral | StringLiteral) ; +leafCondition : AT leafName comparativeOperators ( IntegerLiteral | StringLiteral) ; leafName : QName ; booleanOperators : ( KW_AND | KW_OR ) ; -invalidPostFix : (AT | CB | COLONCOLON | EQ ).+ ; +comparativeOperators : ( EQ | GT | LT | GE | LE ) ; + +invalidPostFix : (AT | CB | COLONCOLON | comparativeOperators ).+ ; /* * Lexer Rules @@ -70,6 +72,10 @@ SLASH : '/' ; COMMA : ',' ; OP : '(' ; CP : ')' ; +GT : '>' ; +LT : '<' ; +GE : '>=' ; +LE : '<=' ; // KEYWORDS diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java index f44e310a1f..5c47127375 100644 --- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java +++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathBuilder.java @@ -25,10 +25,8 @@ import static org.onap.cps.cpspath.parser.CpsPathPrefixType.DESCENDANT; import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Queue; import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener; import org.onap.cps.cpspath.parser.antlr4.CpsPathParser; import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext; @@ -59,7 +57,7 @@ public class CpsPathBuilder extends CpsPathBaseListener { final List<String> booleanOperators = new ArrayList<>(); - final Queue<String> booleanOperatorsQueue = new LinkedList<>(); + final List<String> comparativeOperators = new ArrayList<>(); @Override public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) { @@ -83,25 +81,20 @@ public class CpsPathBuilder extends CpsPathBaseListener { @Override public void exitLeafCondition(final LeafConditionContext ctx) { - Object comparisonValue = null; + Object comparisonValue; if (ctx.IntegerLiteral() != null) { comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText()); - } - if (ctx.StringLiteral() != null) { - final boolean wasWrappedInDoubleQuote = ctx.StringLiteral().getText().startsWith("\""); + } else if (ctx.StringLiteral() != null) { + final boolean wasWrappedInDoubleQuote = ctx.StringLiteral().getText().startsWith("\""); comparisonValue = stripFirstAndLastCharacter(ctx.StringLiteral().getText()); if (wasWrappedInDoubleQuote) { comparisonValue = String.valueOf(comparisonValue).replace("'", "\\'"); } - } else if (comparisonValue == null) { - throw new PathParsingException("Unsupported comparison value encountered in expression" + ctx.getText()); - } - leavesData.put(ctx.leafName().getText(), comparisonValue); - final String booleanOperator = booleanOperatorsQueue.poll(); - appendCondition(normalizedXpathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue); - if (processingAncestorAxis) { - appendCondition(normalizedAncestorPathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue); + } else { + throw new PathParsingException( + "Unsupported comparison value encountered in expression" + ctx.getText()); } + leafContext(ctx.leafName(), comparisonValue); } @Override @@ -109,8 +102,13 @@ public class CpsPathBuilder extends CpsPathBaseListener { final CpsPathBooleanOperatorType cpsPathBooleanOperatorType = CpsPathBooleanOperatorType.fromString( ctx.getText()); booleanOperators.add(cpsPathBooleanOperatorType.getValues()); - booleanOperatorsQueue.add(cpsPathBooleanOperatorType.getValues()); - cpsPathQuery.setBooleanOperatorsType(booleanOperators); + } + + @Override + public void exitComparativeOperators(final CpsPathParser.ComparativeOperatorsContext ctx) { + final CpsPathComparativeOperator cpsPathComparativeOperator = CpsPathComparativeOperator.fromString( + ctx.getText()); + comparativeOperators.add(cpsPathComparativeOperator.getLabel()); } @Override @@ -174,6 +172,8 @@ public class CpsPathBuilder extends CpsPathBaseListener { CpsPathQuery build() { cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString()); cpsPathQuery.setContainerNames(containerNames); + cpsPathQuery.setBooleanOperators(booleanOperators); + cpsPathQuery.setComparativeOperators(comparativeOperators); return cpsPathQuery; } @@ -192,14 +192,30 @@ public class CpsPathBuilder extends CpsPathBaseListener { } } + private void leafContext(final CpsPathParser.LeafNameContext ctx, final Object comparisonValue) { + leavesData.put(ctx.getText(), comparisonValue); + appendCondition(normalizedXpathBuilder, ctx.getText(), comparisonValue); + if (processingAncestorAxis) { + appendCondition(normalizedAncestorPathBuilder, ctx.getText(), comparisonValue); + } + } + private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name, - final String booleanOperator, final Object value) { + final Object value) { final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1); - currentNormalizedPathBuilder.append(lastCharacter == '[' ? "" : " " + booleanOperator + " ") - .append("@") + final boolean isStartOfExpression = lastCharacter == '['; + if (!isStartOfExpression) { + currentNormalizedPathBuilder.append(" ").append(getLastElement(booleanOperators)).append(" "); + } + currentNormalizedPathBuilder.append("@") .append(name) - .append("='") + .append(getLastElement(comparativeOperators)) + .append("'") .append(value) .append("'"); } + + private String getLastElement(final List<String> listOfStrings) { + return listOfStrings.get(listOfStrings.size() - 1); + } } diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathComparativeOperator.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathComparativeOperator.java new file mode 100644 index 0000000000..c7ffd0d7ec --- /dev/null +++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathComparativeOperator.java @@ -0,0 +1,64 @@ +/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Tech Mahindra Ltd
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.cpspath.parser;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum CpsPathComparativeOperator {
+ EQ("="),
+ GT(">"),
+ LT("<"),
+ GE(">="),
+ LE("<=");
+
+ private final String label;
+
+ CpsPathComparativeOperator(final String label) {
+ this.label = label;
+ }
+
+ public final String getLabel() {
+ return this.label;
+ }
+
+ private static final Map<String, CpsPathComparativeOperator> cpsPathComparativeOperatorPerLabel = new HashMap<>();
+
+ static {
+ for (final CpsPathComparativeOperator cpsPathComparativeOperator : CpsPathComparativeOperator.values()) {
+ cpsPathComparativeOperatorPerLabel.put(cpsPathComparativeOperator.label, cpsPathComparativeOperator);
+ }
+ }
+
+ /**
+ * Finds the value of the given enumeration.
+ *
+ * @param label value of the enum
+ * @return a comparativeOperatorType
+ */
+ public static CpsPathComparativeOperator fromString(final String label) {
+ if (!cpsPathComparativeOperatorPerLabel.containsKey(label)) {
+ throw new PathParsingException("Incomplete leaf condition (no operator)");
+ }
+ return cpsPathComparativeOperatorPerLabel.get(label);
+ }
+}
+
diff --git a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java index 418b5ec55b..3c3cbccf7e 100644 --- a/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java +++ b/cps-path-parser/src/main/java/org/onap/cps/cpspath/parser/CpsPathQuery.java @@ -43,7 +43,8 @@ public class CpsPathQuery { private String ancestorSchemaNodeIdentifier = ""; private String textFunctionConditionLeafName; private String textFunctionConditionValue; - private List<String> booleanOperatorsType; + private List<String> booleanOperators; + private List<String> comparativeOperators; private String containsFunctionConditionLeafName; private String containsFunctionConditionValue; diff --git a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy index 9552a4d342..9ab5491b5d 100644 --- a/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy +++ b/cps-path-parser/src/test/groovy/org/onap/cps/cpspath/parser/CpsPathQuerySpec.groovy @@ -71,6 +71,10 @@ class CpsPathQuerySpec extends Specification { 'yang container' | '/cps-path' || '/cps-path' 'descendant anywhere' | '//cps-path' || '//cps-path' 'descendant with leaf condition' | '//cps-path[@key=1]' || "//cps-path[@key='1']" + 'descendant with leaf condition has ">" operator' | '//cps-path[@key>9]' || "//cps-path[@key>'9']" + 'descendant with leaf condition has "<" operator' | '//cps-path[@key<10]' || "//cps-path[@key<'10']" + 'descendant with leaf condition has ">=" operator' | '//cps-path[@key>=8]' || "//cps-path[@key>='8']" + 'descendant with leaf condition has "<=" operator' | '//cps-path[@key<=12]' || "//cps-path[@key<='12']" 'descendant with leaf value and ancestor' | '//cps-path[@key=1]/ancestor:parent[@key=1]' || "//cps-path[@key='1']/ancestor:parent[@key='1']" 'parent & child' | '/parent/child' || '/parent/child' 'parent leaf of type Integer & child' | '/parent/child[@code=1]/child2' || "/parent/child[@code='1']/child2" @@ -108,16 +112,22 @@ class CpsPathQuerySpec extends Specification { result.descendantName == "child" result.leavesData.size() == expectedNumberOfLeaves and: 'the given operator(s) returns in the correct order' - result.booleanOperatorsType == expectedOperators + result.booleanOperators == expectedOperators + and: 'the given comparativeOperator(s) returns in the correct order' + result.comparativeOperators == expectedComparativeOperator where: 'the following data is used' - scenario | cpsPath || expectedNumberOfLeaves || expectedOperators - 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 || null - 'more than one attribute has AND operator' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 || ['and'] - 'more than one attribute has OR operator' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 || ['or'] - 'more than one attribute has combinations and operators' | '//child[@int-leaf=5 and @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['and', 'and'] - 'more than one attribute has combinations or operators' | '//child[@int-leaf=5 or @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['or', 'or'] - 'more than one attribute has combinations and/or combination' | '//child[@int-leaf=5 and @leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 2 || ['and', 'or'] - 'more than one attribute has combinations or/and combination' | '//child[@int-leaf=5 or @leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 2 || ['or', 'and'] + scenario | cpsPath || expectedNumberOfLeaves || expectedOperators || expectedComparativeOperator + 'one attribute' | '//child[@common-leaf-name-int=5]' || 1 || [] || ['='] + 'more than one attribute has AND operator' | '//child[@int-leaf=5 and @leaf-name="leaf value"]' || 2 || ['and'] || ['=', '='] + 'more than one attribute has OR operator' | '//child[@int-leaf=5 or @leaf-name="leaf value"]' || 2 || ['or'] || ['=', '='] + 'more than one attribute has combinations AND operators' | '//child[@int-leaf=5 and @common-leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 3 || ['and', 'and'] || ['=', '=', '='] + 'more than one attribute has combinations OR operators' | '//child[@int-leaf=5 or @common-leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 3 || ['or', 'or'] || ['=', '=', '='] + 'more than one attribute has combinations AND/OR combination' | '//child[@int-leaf=5 and @common-leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 3 || ['and', 'or'] || ['=', '=', '='] + 'more than one attribute has combinations OR/AND combination' | '//child[@int-leaf=5 or @common-leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 3 || ['or', 'and'] || ['=', '=', '='] + 'more than one attribute has AND/> operators' | '//child[@int-leaf>15 and @leaf-name="leaf value"]' || 2 || ['and'] || ['>', '='] + 'more than one attribute has OR/< operators' | '//child[@int-leaf<5 or @leaf-name="leaf value"]' || 2 || ['or'] || ['<', '='] + 'more than one attribute has combinations AND/>= operators' | '//child[@int-leaf>=18 and @common-leaf-name="leaf value" and @leaf-name="leaf value1" ]' || 3 || ['and', 'and'] || ['>=', '=', '='] + 'more than one attribute has combinations OR/<= operators' | '//child[@int-leaf<=25 or @common-leaf-name="leaf value" or @leaf-name="leaf value1" ]' || 3 || ['or', 'or'] || ['<=', '=', '='] } def 'Parse #scenario cps path with text function condition'() { |