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.HashMap;
28 import java.util.LinkedList;
29 import java.util.List;
31 import java.util.Queue;
32 import org.onap.cps.cpspath.parser.antlr4.CpsPathBaseListener;
33 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser;
34 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.AncestorAxisContext;
35 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.DescendantContext;
36 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.IncorrectPrefixContext;
37 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.LeafConditionContext;
38 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.MultipleLeafConditionsContext;
39 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.PrefixContext;
40 import org.onap.cps.cpspath.parser.antlr4.CpsPathParser.TextFunctionConditionContext;
42 public class CpsPathBuilder extends CpsPathBaseListener {
44 private static final String OPEN_BRACKET = "[";
46 private static final String CLOSE_BRACKET = "]";
48 final CpsPathQuery cpsPathQuery = new CpsPathQuery();
50 final Map<String, Object> leavesData = new HashMap<>();
52 final StringBuilder normalizedXpathBuilder = new StringBuilder();
54 final StringBuilder normalizedAncestorPathBuilder = new StringBuilder();
56 boolean processingAncestorAxis = false;
58 private List<String> containerNames = new ArrayList<>();
60 final List<String> booleanOperators = new ArrayList<>();
62 final Queue<String> booleanOperatorsQueue = new LinkedList<>();
65 public void exitInvalidPostFix(final CpsPathParser.InvalidPostFixContext ctx) {
66 throw new PathParsingException(ctx.getText());
70 public void exitPrefix(final PrefixContext ctx) {
71 cpsPathQuery.setXpathPrefix(normalizedXpathBuilder.toString());
75 public void exitParent(final CpsPathParser.ParentContext ctx) {
76 cpsPathQuery.setNormalizedParentPath(normalizedXpathBuilder.toString());
80 public void exitIncorrectPrefix(final IncorrectPrefixContext ctx) {
81 throw new PathParsingException("CPS path can only start with one or two slashes (/)");
85 public void exitLeafCondition(final LeafConditionContext ctx) {
86 Object comparisonValue = null;
87 if (ctx.IntegerLiteral() != null) {
88 comparisonValue = Integer.valueOf(ctx.IntegerLiteral().getText());
90 if (ctx.StringLiteral() != null) {
91 final boolean wasWrappedInDoubleQuote = ctx.StringLiteral().getText().startsWith("\"");
92 comparisonValue = stripFirstAndLastCharacter(ctx.StringLiteral().getText());
93 if (wasWrappedInDoubleQuote) {
94 comparisonValue = String.valueOf(comparisonValue).replace("'", "\\'");
96 } else if (comparisonValue == null) {
97 throw new PathParsingException("Unsupported comparison value encountered in expression" + ctx.getText());
99 leavesData.put(ctx.leafName().getText(), comparisonValue);
100 final String booleanOperator = booleanOperatorsQueue.poll();
101 appendCondition(normalizedXpathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue);
102 if (processingAncestorAxis) {
103 appendCondition(normalizedAncestorPathBuilder, ctx.leafName().getText(), booleanOperator, comparisonValue);
108 public void exitBooleanOperators(final CpsPathParser.BooleanOperatorsContext ctx) {
109 final CpsPathBooleanOperatorType cpsPathBooleanOperatorType = CpsPathBooleanOperatorType.fromString(
111 booleanOperators.add(cpsPathBooleanOperatorType.getValues());
112 booleanOperatorsQueue.add(cpsPathBooleanOperatorType.getValues());
113 cpsPathQuery.setBooleanOperatorsType(booleanOperators);
117 public void exitDescendant(final DescendantContext ctx) {
118 cpsPathQuery.setCpsPathPrefixType(DESCENDANT);
119 cpsPathQuery.setDescendantName(normalizedXpathBuilder.substring(1));
120 normalizedXpathBuilder.insert(0, "/");
124 public void enterMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
125 normalizedXpathBuilder.append(OPEN_BRACKET);
130 public void exitMultipleLeafConditions(final MultipleLeafConditionsContext ctx) {
131 normalizedXpathBuilder.append(CLOSE_BRACKET);
132 cpsPathQuery.setLeavesData(leavesData);
136 public void enterAncestorAxis(final AncestorAxisContext ctx) {
137 processingAncestorAxis = true;
141 public void exitAncestorAxis(final AncestorAxisContext ctx) {
142 cpsPathQuery.setAncestorSchemaNodeIdentifier(normalizedAncestorPathBuilder.substring(1));
143 processingAncestorAxis = false;
147 public void exitTextFunctionCondition(final TextFunctionConditionContext ctx) {
148 cpsPathQuery.setTextFunctionConditionLeafName(ctx.leafName().getText());
149 cpsPathQuery.setTextFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
153 public void exitContainsFunctionCondition(final CpsPathParser.ContainsFunctionConditionContext ctx) {
154 cpsPathQuery.setContainsFunctionConditionLeafName(ctx.leafName().getText());
155 cpsPathQuery.setContainsFunctionConditionValue(stripFirstAndLastCharacter(ctx.StringLiteral().getText()));
159 public void enterListElementRef(final CpsPathParser.ListElementRefContext ctx) {
160 normalizedXpathBuilder.append(OPEN_BRACKET);
161 if (processingAncestorAxis) {
162 normalizedAncestorPathBuilder.append(OPEN_BRACKET);
167 public void exitListElementRef(final CpsPathParser.ListElementRefContext ctx) {
168 normalizedXpathBuilder.append(CLOSE_BRACKET);
169 if (processingAncestorAxis) {
170 normalizedAncestorPathBuilder.append(CLOSE_BRACKET);
174 CpsPathQuery build() {
175 cpsPathQuery.setNormalizedXpath(normalizedXpathBuilder.toString());
176 cpsPathQuery.setContainerNames(containerNames);
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 appendCondition(final StringBuilder currentNormalizedPathBuilder, final String name,
196 final String booleanOperator, final Object value) {
197 final char lastCharacter = currentNormalizedPathBuilder.charAt(currentNormalizedPathBuilder.length() - 1);
198 currentNormalizedPathBuilder.append(lastCharacter == '[' ? "" : " " + booleanOperator + " ")