2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021-2022 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.LinkedHashMap;
28 import java.util.List;
30 import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener;
31 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser;
32 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext;
33 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.DescendantContext;
34 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.IncorrectPrefixContext;
35 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.LeafConditionContext;
36 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.MultipleLeafConditionsContext;
37 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.PrefixContext;
38 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.TextFunctionConditionContext;
40 public class CpsPathBuilder extends CpsPathBaseListener {
42 private static final String OPEN_BRACKET = "[";
44 private static final String CLOSE_BRACKET = "]";
46 final CpsPathQuery cpsPathQuery = new CpsPathQuery();
48 final Map<String, Object> leavesData = new LinkedHashMap<>();
50 final StringBuilder normalizedXpathBuilder = new StringBuilder();
52 final StringBuilder normalizedAncestorPathBuilder = new StringBuilder();
54 boolean processingAncestorAxis = false;
56 private List<String> containerNames = new ArrayList<>();
58 final List<String> booleanOperators = new ArrayList<>();
60 final List<String> comparativeOperators = new ArrayList<>();
63 public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) {
64 throw new PathParsingException(ctx.getText());
68 public void exitPrefix(final PrefixContext ctx) {
69 cpsPathQuery.setXpathPrefix(normalizedXpathBuilder.toString());
73 public void exitParent(final CpsPathParser.ParentContext ctx) {
74 cpsPathQuery.setNormalizedParentPath(normalizedXpathBuilder.toString());
78 public void exitIncorrectPrefix(final IncorrectPrefixContext ctx) {
79 throw new PathParsingException("CPS path can only start with one or two slashes (/)");
83 public void exitLeafCondition(final LeafConditionContext ctx) {
84 Object comparisonValue;
85 if (ctx.IntegerLiteral() != null) {
86 comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText());
87 } else if (ctx.StringLiteral() != null) {
88 final boolean wasWrappedInDoubleQuote = ctx.StringLiteral().getText().startsWith("\"");
89 comparisonValue = stripFirstAndLastCharacter(ctx.StringLiteral().getText());
90 if (wasWrappedInDoubleQuote) {
91 comparisonValue = String.valueOf(comparisonValue).replace("'", "\\'");
94 throw new PathParsingException(
95 "Unsupported comparison value encountered in expression" + ctx.getText());
97 leafContext(ctx.leafName(), comparisonValue);
101 public void exitBooleanOperators(final CpsPathParser.BooleanOperatorsContext ctx) {
102 final CpsPathBooleanOperatorType cpsPathBooleanOperatorType = CpsPathBooleanOperatorType.fromString(
104 booleanOperators.add(cpsPathBooleanOperatorType.getValues());
108 public void exitComparativeOperators(final CpsPathParser.ComparativeOperatorsContext ctx) {
109 final CpsPathComparativeOperator cpsPathComparativeOperator = CpsPathComparativeOperator.fromString(
111 comparativeOperators.add(cpsPathComparativeOperator.getLabel());
115 public void exitDescendant(final DescendantContext ctx) {
116 cpsPathQuery.setCpsPathPrefixType(DESCENDANT);
117 cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(1));
118 normalizedXpathBuilder.insert(0, "/");
122 public void enterMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
123 normalizedXpathBuilder.append(OPEN_BRACKET);
128 public void exitMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
129 normalizedXpathBuilder.append(CLOSE_BRACKET);
130 cpsPathQuery.setLeavesData(leavesData);
134 public void enterAncestorAxis(final AncestorAxisContext ctx) {
135 processingAncestorAxis = true;
139 public void exitAncestorAxis(final AncestorAxisContext ctx) {
140 cpsPathQuery.setAncestorSchemaNodeIdentifier(normalizedAncestorPathBuilder.substring(1));
141 processingAncestorAxis = false;
145 public void exitTextFunctionCondition(final TextFunctionConditionContext ctx) {
146 cpsPathQuery.setTextFunctionConditionLeafName(ctx.leafName().getText());
147 cpsPathQuery.setTextFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
151 public void exitContainsFunctionCondition(final CpsPathParser.ContainsFunctionConditionContext ctx) {
152 cpsPathQuery.setContainsFunctionConditionLeafName(ctx.leafName().getText());
153 cpsPathQuery.setContainsFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
157 public void enterListElementRef(final CpsPathParser.ListElementRefContext ctx) {
158 normalizedXpathBuilder.append(OPEN_BRACKET);
159 if (processingAncestorAxis) {
160 normalizedAncestorPathBuilder.append(OPEN_BRACKET);
165 public void exitListElementRef(final CpsPathParser.ListElementRefContext ctx) {
166 normalizedXpathBuilder.append(CLOSE_BRACKET);
167 if (processingAncestorAxis) {
168 normalizedAncestorPathBuilder.append(CLOSE_BRACKET);
172 CpsPathQuery build() {
173 cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString());
174 cpsPathQuery.setContainerNames(containerNames);
175 cpsPathQuery.setBooleanOperators(booleanOperators);
176 cpsPathQuery.setComparativeOperators(comparativeOperators);
180 private static String stripFirstAndLastCharacter(final String wrappedString) {
181 return wrappedString.substring(1, wrappedString.length() - 1);
185 public void exitContainerName(final CpsPathParser.ContainerNameContext ctx) {
186 final String containerName = ctx.getText();
187 normalizedXpathBuilder.append("/")
188 .append(containerName);
189 containerNames.add(containerName);
190 if (processingAncestorAxis) {
191 normalizedAncestorPathBuilder.append("/").append(containerName);
195 private void leafContext(final CpsPathParser.LeafNameContext ctx, final Object comparisonValue) {
196 leavesData.put(ctx.getText(), comparisonValue);
197 appendCondition(normalizedXpathBuilder, ctx.getText(), comparisonValue);
198 if (processingAncestorAxis) {
199 appendCondition(normalizedAncestorPathBuilder, ctx.getText(), comparisonValue);
203 private void appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name,
204 final Object value) {
205 final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
206 final boolean isStartOfExpression = lastCharacter == '[';
207 if (!isStartOfExpression) {
208 currentNormalizedPathBuilder.append(" ").append(getLastElement(booleanOperators)).append(" ");
210 currentNormalizedPathBuilder.append("@")
212 .append(getLastElement(comparativeOperators))
218 private String getLastElement(final List<String> listOfStrings) {
219 return listOfStrings.get(listOfStrings.size() - 1);