2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2023 Nordix Foundation
4 * Modifications Copyright (C) 2023 TechMahindra Ltd
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.cps.cpspath.parser;
24 import static org.onap.cps.cpspath.parser.CpsPathPrefixType.DESCENDANT;
26 import java.util.ArrayList;
27 import java.util.List;
28 import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener;
29 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser;
30 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext;
31 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.DescendantContext;
32 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.IncorrectPrefixContext;
33 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.LeafConditionContext;
34 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.MultipleLeafConditionsContext;
35 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.PrefixContext;
36 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.TextFunctionConditionContext;
38 public class CpsPathBuilder extends CpsPathBaseListener {
40 private static final String OPEN_BRACKET = "[";
42 private static final String CLOSE_BRACKET = "]";
44 private final CpsPathQuery cpsPathQuery = new CpsPathQuery();
46 private final List<CpsPathQuery.DataLeaf> leavesData = new ArrayList<>();
48 private final StringBuilder normalizedXpathBuilder = new StringBuilder();
50 private final StringBuilder normalizedAncestorPathBuilder = new StringBuilder();
52 private boolean processingAncestorAxis = false;
54 private final List<String> containerNames = new ArrayList<>();
56 private final List<String> booleanOperators = new ArrayList<>();
58 private final List<String> comparativeOperators = new ArrayList<>();
61 public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) {
62 throw new PathParsingException(ctx.getText());
66 public void exitPrefix(final PrefixContext ctx) {
67 cpsPathQuery.setXpathPrefix(normalizedXpathBuilder.toString());
71 public void exitParent(final CpsPathParser.ParentContext ctx) {
72 cpsPathQuery.setNormalizedParentPath(normalizedXpathBuilder.toString());
76 public void exitIncorrectPrefix(final IncorrectPrefixContext ctx) {
77 throw new PathParsingException("CPS path can only start with one or two slashes (/)");
81 public void exitLeafCondition(final LeafConditionContext ctx) {
82 Object comparisonValue;
83 if (ctx.IntegerLiteral() != null) {
84 comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText());
85 } else if (ctx.StringLiteral() != null) {
86 final boolean wasWrappedInDoubleQuote = ctx.StringLiteral().getText().startsWith("\"");
87 comparisonValue = stripFirstAndLastCharacter(ctx.StringLiteral().getText());
88 if (wasWrappedInDoubleQuote) {
89 comparisonValue = String.valueOf(comparisonValue).replace("'", "\\'");
92 throw new PathParsingException(
93 "Unsupported comparison value encountered in expression" + ctx.getText());
95 leafContext(ctx.leafName(), comparisonValue);
99 public void exitBooleanOperators(final CpsPathParser.BooleanOperatorsContext ctx) {
100 booleanOperators.add(ctx.getText());
104 public void exitComparativeOperators(final CpsPathParser.ComparativeOperatorsContext ctx) {
105 comparativeOperators.add(ctx.getText());
109 public void exitDescendant(final DescendantContext ctx) {
110 cpsPathQuery.setCpsPathPrefixType(DESCENDANT);
111 cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(1));
112 normalizedXpathBuilder.insert(0, "/");
116 public void enterMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
117 normalizedXpathBuilder.append(OPEN_BRACKET);
119 booleanOperators.clear();
120 comparativeOperators.clear();
124 public void exitMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
125 normalizedXpathBuilder.append(CLOSE_BRACKET);
126 cpsPathQuery.setLeavesData(leavesData);
130 public void enterAncestorAxis(final AncestorAxisContext ctx) {
131 processingAncestorAxis = true;
135 public void exitAncestorAxis(final AncestorAxisContext ctx) {
136 cpsPathQuery.setAncestorSchemaNodeIdentifier(normalizedAncestorPathBuilder.substring(1));
137 processingAncestorAxis = false;
141 public void exitTextFunctionCondition(final TextFunctionConditionContext ctx) {
142 cpsPathQuery.setTextFunctionConditionLeafName(ctx.leafName().getText());
143 cpsPathQuery.setTextFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
147 public void exitContainsFunctionCondition(final CpsPathParser.ContainsFunctionConditionContext ctx) {
148 cpsPathQuery.setContainsFunctionConditionLeafName(ctx.leafName().getText());
149 cpsPathQuery.setContainsFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
153 public void enterListElementRef(final CpsPathParser.ListElementRefContext ctx) {
154 normalizedXpathBuilder.append(OPEN_BRACKET);
155 if (processingAncestorAxis) {
156 normalizedAncestorPathBuilder.append(OPEN_BRACKET);
161 public void exitListElementRef(final CpsPathParser.ListElementRefContext ctx) {
162 normalizedXpathBuilder.append(CLOSE_BRACKET);
163 if (processingAncestorAxis) {
164 normalizedAncestorPathBuilder.append(CLOSE_BRACKET);
168 CpsPathQuery build() {
169 cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString());
170 cpsPathQuery.setContainerNames(containerNames);
171 cpsPathQuery.setBooleanOperators(booleanOperators);
172 cpsPathQuery.setComparativeOperators(comparativeOperators);
176 private static String stripFirstAndLastCharacter(final String wrappedString) {
177 return wrappedString.substring(1, wrappedString.length() - 1);
181 public void exitContainerName(final CpsPathParser.ContainerNameContext ctx) {
182 final String containerName = ctx.getText();
183 normalizedXpathBuilder.append("/")
184 .append(containerName);
185 containerNames.add(containerName);
186 if (processingAncestorAxis) {
187 normalizedAncestorPathBuilder.append("/").append(containerName);
191 private void leafContext(final CpsPathParser.LeafNameContext ctx, final Object comparisonValue) {
192 leavesData.add(new CpsPathQuery.DataLeaf(ctx.getText(), comparisonValue));
193 appendCondition(normalizedXpathBuilder, ctx.getText(), comparisonValue);
194 if (processingAncestorAxis) {
195 appendCondition(normalizedAncestorPathBuilder, ctx.getText(), comparisonValue);
199 private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name,
200 final Object value) {
201 final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
202 final boolean isStartOfExpression = lastCharacter == '[';
203 if (!isStartOfExpression) {
204 currentNormalizedPathBuilder.append(" ").append(getLastElement(booleanOperators)).append(" ");
206 currentNormalizedPathBuilder.append("@")
208 .append(getLastElement(comparativeOperators))
214 private String getLastElement(final List<String> listOfStrings) {
215 return listOfStrings.get(listOfStrings.size() - 1);