From 6c9c100daba10717641a08b6c6dc3ec3b51c56a8 Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Fri, 30 Apr 2021 12:09:44 +0100 Subject: Implement cps path query to get ancestor by schema node identifier Cleaned up some legcy issues in related testware Issue-ID: CPS-305 Signed-off-by: niamhcore Change-Id: Ic4b21308478f399e3a454dbcd73943e077b0f3f2 Signed-off-by: ToineSiebelink --- .../spi/impl/CpsDataPersistenceServiceImpl.java | 27 ++++++++- .../java/org/onap/cps/spi/query/CpsPathQuery.java | 68 ++++++++++++++-------- .../cps/spi/repository/FragmentRepository.java | 3 + 3 files changed, 73 insertions(+), 25 deletions(-) (limited to 'cps-ri/src/main') diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java index 48f1de710..ab135fd3a 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java @@ -28,9 +28,11 @@ import com.google.common.collect.ImmutableSet.Builder; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; @@ -62,6 +64,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private FragmentRepository fragmentRepository; private static final Gson GSON = new GsonBuilder().create(); + private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@\\S+?]){0,1})"; @Override public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentXpath, @@ -82,7 +85,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService try { fragmentRepository.save(fragmentEntity); } catch (final DataIntegrityViolationException exception) { - throw AlreadyDefinedException.forDataNode(dataNode.getXpath(), anchorName, exception); + throw AlreadyDefinedException.forDataNode(dataNode.getXpath(), anchorName, exception); } } @@ -144,7 +147,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName); final var anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); final var cpsPathQuery = CpsPathQuery.createFrom(cpsPath); - final List fragmentEntities; + List fragmentEntities; if (CpsPathQueryType.XPATH_LEAF_VALUE.equals(cpsPathQuery.getCpsPathQueryType())) { fragmentEntities = fragmentRepository .getByAnchorAndXpathAndLeafAttributes(anchorEntity.getId(), cpsPathQuery.getXpathPrefix(), @@ -158,11 +161,31 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService fragmentEntities = fragmentRepository .getByAnchorAndXpathEndsInDescendantName(anchorEntity.getId(), cpsPathQuery.getDescendantName()); } + if (cpsPathQuery.hasAncestorAxis()) { + final Set ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery); + fragmentEntities = ancestorXpaths.isEmpty() + ? Collections.emptyList() : fragmentRepository.findAllByAnchorAndXpathIn(anchorEntity, ancestorXpaths); + } return fragmentEntities.stream() .map(fragmentEntity -> toDataNode(fragmentEntity, fetchDescendantsOption)) .collect(Collectors.toUnmodifiableList()); } + private static Set processAncestorXpath(final List fragmentEntities, + final CpsPathQuery cpsPathQuery) { + final Set ancestorXpath = new HashSet<>(); + final var pattern = + Pattern.compile("(\\S*\\/" + cpsPathQuery.getAncestorSchemaNodeIdentifier() + REG_EX_FOR_OPTIONAL_LIST_INDEX + + "\\/\\S*"); + for (final FragmentEntity fragmentEntity : fragmentEntities) { + final var matcher = pattern.matcher(fragmentEntity.getXpath()); + if (matcher.matches()) { + ancestorXpath.add(matcher.group(1)); + } + } + return ancestorXpath; + } + private static DataNode toDataNode(final FragmentEntity fragmentEntity, final FetchDescendantsOption fetchDescendantsOption) { final Map leaves = GSON.fromJson(fragmentEntity.getAttributes(), Map.class); diff --git a/cps-ri/src/main/java/org/onap/cps/spi/query/CpsPathQuery.java b/cps-ri/src/main/java/org/onap/cps/spi/query/CpsPathQuery.java index 6f53e0013..f48d16590 100644 --- a/cps-ri/src/main/java/org/onap/cps/spi/query/CpsPathQuery.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/query/CpsPathQuery.java @@ -20,6 +20,8 @@ package org.onap.cps.spi.query; +import static org.springframework.util.StringUtils.isEmpty; + import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; @@ -39,6 +41,7 @@ public class CpsPathQuery { private Object leafValue; private String descendantName; private Map leavesData; + private String ancestorSchemaNodeIdentifier; private static final String NON_CAPTURING_GROUP_1_TO_99_YANG_CONTAINERS = "((?:\\/[^\\/]+){1,99})"; @@ -48,14 +51,14 @@ public class CpsPathQuery { private static final Pattern QUERY_CPS_PATH_WITH_SINGLE_LEAF_PATTERN = Pattern.compile(NON_CAPTURING_GROUP_1_TO_99_YANG_CONTAINERS + YANG_LEAF_VALUE_EQUALS_CONDITION); - private static final Pattern DESCENDANT_ANYWHERE_PATTERN = Pattern.compile("\\/\\/([^\\/].+)"); + private static final Pattern DESCENDANT_ANYWHERE_PATTERN = Pattern.compile("\\/\\/([^\\/][^:]+)"); private static final Pattern LEAF_INTEGER_VALUE_PATTERN = Pattern.compile("[-+]?\\d+"); private static final Pattern LEAF_STRING_VALUE_IN_SINGLE_QUOTES_PATTERN = Pattern.compile("'(.*)'"); private static final Pattern LEAF_STRING_VALUE_IN_DOUBLE_QUOTES_PATTERN = Pattern.compile("\"(.*)\""); - private static final String YANG_MULTIPLE_LEAF_VALUE_EQUALS_CONDITION = "\\[(.*?)\\s{0,9}]"; + private static final String YANG_MULTIPLE_LEAF_VALUE_EQUALS_CONDITION = "\\[(.*?)\\s{0,9}]"; private static final Pattern DESCENDANT_ANYWHERE_PATTERN_WITH_MULTIPLE_LEAF_PATTERN = Pattern.compile(DESCENDANT_ANYWHERE_PATTERN + YANG_MULTIPLE_LEAF_VALUE_EQUALS_CONDITION); @@ -64,45 +67,60 @@ public class CpsPathQuery { private static final Pattern LEAF_VALUE_PATTERN = Pattern.compile("@(\\S+?)=(.*)"); + private static final Pattern ANCESTOR_AXIS_PATTERN = Pattern.compile("(\\S+)\\/ancestor::\\/?(\\S+)"); + /** * Returns a cps path query. * - * @param cpsPath cps path + * @param cpsPathSource cps path * @return a CpsPath object. */ - public static CpsPathQuery createFrom(final String cpsPath) { - var matcher = QUERY_CPS_PATH_WITH_SINGLE_LEAF_PATTERN.matcher(cpsPath); - final var cpsPathQuery = new CpsPathQuery(); + public static CpsPathQuery createFrom(final String cpsPathSource) { + var cpsPath = cpsPathSource; + final CpsPathQuery cpsPathQuery = new CpsPathQuery(); + var matcher = ANCESTOR_AXIS_PATTERN.matcher(cpsPath); if (matcher.matches()) { - return buildCpsPathQueryWithSingleLeafPattern(cpsPath, matcher, cpsPathQuery); + cpsPath = matcher.group(1); + cpsPathQuery.setAncestorSchemaNodeIdentifier(matcher.group(2)); + } + matcher = QUERY_CPS_PATH_WITH_SINGLE_LEAF_PATTERN.matcher(cpsPath); + if (matcher.matches()) { + cpsPathQuery.setParametersForSingleLeafValue(cpsPath, matcher); + return cpsPathQuery; } matcher = DESCENDANT_ANYWHERE_PATTERN_WITH_MULTIPLE_LEAF_PATTERN.matcher(cpsPath); if (matcher.matches()) { - return buildCpsQueryForDescendentWithLeafPattern(cpsPath, matcher, cpsPathQuery); + cpsPathQuery.setParametersForDescendantWithLeafValues(cpsPath, matcher); + return cpsPathQuery; } matcher = DESCENDANT_ANYWHERE_PATTERN.matcher(cpsPath); if (matcher.matches()) { - cpsPathQuery.setCpsPathQueryType(CpsPathQueryType.XPATH_HAS_DESCENDANT_ANYWHERE); - cpsPathQuery.setDescendantName(matcher.group(1)); + cpsPathQuery.setParametersForDescendantAnywhere(matcher); return cpsPathQuery; } throw new CpsPathException("Invalid cps path.", String.format("Cannot interpret or parse cps path '%s'.", cpsPath)); } - private static CpsPathQuery buildCpsPathQueryWithSingleLeafPattern(final String cpsPath, final Matcher matcher, - final CpsPathQuery cpsPathQuery) { - cpsPathQuery.setCpsPathQueryType(CpsPathQueryType.XPATH_LEAF_VALUE); - cpsPathQuery.setXpathPrefix(matcher.group(1)); - cpsPathQuery.setLeafName(matcher.group(2)); - cpsPathQuery.setLeafValue(convertLeafValueToCorrectType(matcher.group(3), cpsPath)); - return cpsPathQuery; + /** + * Has ancestor axis been populated. + * + * @return boolean value. + */ + public boolean hasAncestorAxis() { + return !(isEmpty(ancestorSchemaNodeIdentifier)); + } + + private void setParametersForSingleLeafValue(final String cpsPath, final Matcher matcher) { + setCpsPathQueryType(CpsPathQueryType.XPATH_LEAF_VALUE); + setXpathPrefix(matcher.group(1)); + setLeafName(matcher.group(2)); + setLeafValue(convertLeafValueToCorrectType(matcher.group(3), cpsPath)); } - private static CpsPathQuery buildCpsQueryForDescendentWithLeafPattern(final String cpsPath, final Matcher matcher, - final CpsPathQuery cpsPathQuery) { - cpsPathQuery.setCpsPathQueryType(CpsPathQueryType.XPATH_HAS_DESCENDANT_WITH_LEAF_VALUES); - cpsPathQuery.setDescendantName(matcher.group(1)); + private void setParametersForDescendantWithLeafValues(final String cpsPath, final Matcher matcher) { + setCpsPathQueryType(CpsPathQueryType.XPATH_HAS_DESCENDANT_WITH_LEAF_VALUES); + setDescendantName(matcher.group(1)); final Map leafData = new HashMap<>(); for (final String leafValuePair : matcher.group(2).split(INDIVIDUAL_LEAF_DETAIL_PATTERN)) { final var descendentMatcher = LEAF_VALUE_PATTERN.matcher(leafValuePair); @@ -114,8 +132,12 @@ public class CpsPathQuery { String.format("Cannot interpret or parse attributes in cps path '%s'.", cpsPath)); } } - cpsPathQuery.setLeavesData(leafData); - return cpsPathQuery; + setLeavesData(leafData); + } + + private void setParametersForDescendantAnywhere(final Matcher matcher) { + setCpsPathQueryType(CpsPathQueryType.XPATH_HAS_DESCENDANT_ANYWHERE); + setDescendantName(matcher.group(1)); } private static Object convertLeafValueToCorrectType(final String leafValueString, final String cpsPath) { diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java index b9874484c..c484ae9e8 100755 --- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java @@ -57,6 +57,9 @@ public interface FragmentRepository extends JpaRepository .orElseThrow(() -> new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName())); } + List findAllByAnchorAndXpathIn(@NonNull AnchorEntity anchorEntity, + @NonNull Collection xpath); + @Modifying @Query("DELETE FROM FragmentEntity fe WHERE fe.anchor IN (:anchors)") void deleteByAnchorIn(@NotNull @Param("anchors") Collection anchorEntities); -- cgit 1.2.3-korg