Fix handling of special characters in prefix names 79/135379/3
authordanielhanrahan <daniel.hanrahan@est.tech>
Wed, 12 Jul 2023 15:11:07 +0000 (16:11 +0100)
committerdanielhanrahan <daniel.hanrahan@est.tech>
Thu, 13 Jul 2023 10:38:53 +0000 (11:38 +0100)
This fixes issues with special characters like square brackets
- Make PrefixResolver use CpsPathParser instead of regex
- Make DataMapUtils use CpsPathParser instead of String parsing

Issue-ID: CPS-1758
Signed-off-by: danielhanrahan <daniel.hanrahan@est.tech>
Change-Id: I6dd66eee398a46a69c0229059195f5096ab6fdec

cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java
cps-service/src/main/java/org/onap/cps/utils/PrefixResolver.java
cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy
cps-service/src/test/groovy/org/onap/cps/utils/PrefixResolverSpec.groovy

index b0e109b..b4d5a09 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
- *  Modifications (C) 2021-2022 Nordix Foundation
+ *  Modifications (C) 2021-2023 Nordix Foundation
  *  Modifications Copyright (C) 2022 Bell Canada
  *  Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
  *  ================================================================================
@@ -33,6 +33,8 @@ import java.util.Collections;
 import java.util.Map;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
 import org.onap.cps.spi.model.DataNode;
 
 @NoArgsConstructor(access = AccessLevel.PRIVATE)
@@ -106,8 +108,9 @@ public class DataMapUtils {
     }
 
     private static String getNodeIdentifier(String xpath) {
-        if (xpath.endsWith("]")) {
-            xpath = xpath.substring(0, xpath.lastIndexOf('['));
+        final CpsPathQuery cpsPathQuery = CpsPathUtil.getCpsPathQuery(xpath);
+        if (cpsPathQuery.isPathToListElement()) {
+            xpath = cpsPathQuery.getXpathPrefix();
         }
         final int fromIndex = xpath.lastIndexOf('/') + 1;
         return xpath.substring(fromIndex);
index 58b239c..d58ddf4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2022 Nordix Foundation.
+ *  Copyright (C) 2022-2023 Nordix Foundation.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
  *  you may not use this file except in compliance with the License.
@@ -25,12 +25,13 @@ import java.io.Serializable;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import lombok.RequiredArgsConstructor;
 import org.onap.cps.api.CpsAdminService;
 import org.onap.cps.api.impl.YangTextSchemaSourceSetCache;
 import org.onap.cps.cache.AnchorDataCacheEntry;
+import org.onap.cps.cpspath.parser.CpsPathPrefixType;
+import org.onap.cps.cpspath.parser.CpsPathQuery;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
 import org.onap.cps.spi.model.Anchor;
 import org.onap.cps.yang.YangTextSchemaSourceSet;
 import org.opendaylight.yangtools.yang.common.QNameModule;
@@ -53,9 +54,6 @@ public class PrefixResolver {
 
     private final IMap<String, AnchorDataCacheEntry> anchorDataCache;
 
-    private static final Pattern TOP_LEVEL_NODE_NAME_FINDER
-        = Pattern.compile("\\/([\\w-]*)(\\[@(?!.*\\[).*?])?(\\/.*)?");  //NOSONAR
-
     /**
      * Get the module prefix for the given xpath for a dataspace and anchor name.
      *
@@ -93,9 +91,9 @@ public class PrefixResolver {
 
     private String getPrefixForTopContainer(final Map<String, String> prefixPerContainerName,
                                             final String xpath) {
-        final Matcher matcher = TOP_LEVEL_NODE_NAME_FINDER.matcher(xpath);
-        if (matcher.matches()) {
-            final String topLevelContainerName = matcher.group(1);
+        final CpsPathQuery cpsPathQuery = CpsPathUtil.getCpsPathQuery(xpath);
+        if (cpsPathQuery.getCpsPathPrefixType() == CpsPathPrefixType.ABSOLUTE) {
+            final String topLevelContainerName = cpsPathQuery.getContainerNames().get(0);
             if (prefixPerContainerName.containsKey(topLevelContainerName)) {
                 return prefixPerContainerName.get(topLevelContainerName);
             }
index c636f4b..29085a9 100644 (file)
@@ -68,8 +68,8 @@ class DataMapUtilsSpec extends Specification {
             scenario                                | xPath                                     | expectedNodeIdentifier
             'container xpath'                       | '/bookstore'                              | 'sampleModuleName:bookstore'
             'xpath contains list attribute'         | '/bookstore/categories[@code=1]'          | 'sampleModuleName:categories'
-            'xpath contains list attributes with /' | '/bookstore/categories[@code=1/2]'        | 'sampleModuleName:categories'
-
+            'xpath contains list attributes with /' | '/bookstore/categories[@code="1/2"]'      | 'sampleModuleName:categories'
+            'xpath contains list attributes with [' | '/bookstore/categories[@code="[1]"]'      | 'sampleModuleName:categories'
     }
 
     def 'Data node structure with anchor name conversion to map with root node identifier.'() {
@@ -98,7 +98,7 @@ class DataMapUtilsSpec extends Specification {
 
     def dataNode = buildDataNode(
         "/parent",[parentLeaf:'parentLeafValue', parentLeafList:['parentLeafListEntry1','parentLeafListEntry2']],[
-        buildDataNode('/parent/child-list[@id=1/2]',[listElementLeaf:'listElement1leafValue'],noChildren),
+        buildDataNode('/parent/child-list[@id="1/2"]',[listElementLeaf:'listElement1leafValue'],noChildren),
         buildDataNode('/parent/child-list[@id=2]',[listElementLeaf:'listElement2leafValue'],noChildren),
         buildDataNode('/parent/child-object',[childLeaf:'childLeafValue'],
             [buildDataNode('/parent/child-object/grand-child-object',[grandChildLeaf:'grandChildLeafValue'],noChildren)]
@@ -107,7 +107,7 @@ class DataMapUtilsSpec extends Specification {
 
     def dataNodeWithAnchor = buildDataNodeWithAnchor(
         "/parent", 'anchor01',[parentLeaf:'parentLeafValue', parentLeafList:['parentLeafListEntry1','parentLeafListEntry2']],[
-        buildDataNode('/parent/child-list[@id=1/2]',[listElementLeaf:'listElement1leafValue'],noChildren),
+        buildDataNode('/parent/child-list[@id="1/2"]',[listElementLeaf:'listElement1leafValue'],noChildren),
         buildDataNode('/parent/child-list[@id=2]',[listElementLeaf:'listElement2leafValue'],noChildren),
         buildDataNode('/parent/child-object',[childLeaf:'childLeafValue'],
             [buildDataNode('/parent/child-object/grand-child-object',[grandChildLeaf:'grandChildLeafValue'],noChildren)]
index 4c1b891..ff6ab34 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2022 Nordix Foundation
+ *  Copyright (C) 2021-2023 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  ================================================================================
@@ -77,8 +77,9 @@ class PrefixResolverSpec extends Specification {
             '/test-tree/with/descendants' || 'tree'
             '/test-tree[@id=1]'           || 'tree'
             '/test-tree[@id=1]/child'     || 'tree'
+            '/test-tree[@id="[1]"]/child' || 'tree'
+            '//test-tree'                 || ''
             '/not-defined'                || ''
-            'invalid-xpath'               || ''
     }
 
     def 'get prefix with populated anchor data cache with #scenario cache entry'() {