X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ri%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fcps%2Fspi%2Fimpl%2FCpsDataPersistenceServiceImpl.java;h=3d2b87d7de8b28cc090c76dcb30883e742a0d3b7;hb=f12bf21976894cf8618942a5511efb773cd791f4;hp=82e6388d8bf9964a84a36faf39c8196c04f53927;hpb=2e07b499eb798c19c8641078ff79364f9439a281;p=cps.git 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 82e6388d8b..3d2b87d7de 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 @@ -23,6 +23,7 @@ package org.onap.cps.spi.impl; +import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet.Builder; import io.micrometer.core.annotation.Timed; @@ -35,6 +36,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -63,7 +65,6 @@ import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.DataNodeBuilder; import org.onap.cps.spi.repository.AnchorRepository; import org.onap.cps.spi.repository.DataspaceRepository; -import org.onap.cps.spi.repository.FragmentQueryBuilder; import org.onap.cps.spi.repository.FragmentRepository; import org.onap.cps.spi.utils.SessionManager; import org.onap.cps.utils.JsonObjectMapper; @@ -81,7 +82,9 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService private final JsonObjectMapper jsonObjectMapper; private final SessionManager sessionManager; - private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@[\\s\\S]+?])?)"; + private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@.+?])?)"; + private static final String QUERY_ACROSS_ANCHORS = null; + private static final AnchorEntity ALL_ANCHORS = null; @Override public void addChildDataNode(final String dataspaceName, final String anchorName, final String parentNodeXpath, @@ -167,11 +170,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } } - @Override - public void storeDataNode(final String dataspaceName, final String anchorName, final DataNode dataNode) { - storeDataNodes(dataspaceName, anchorName, Collections.singletonList(dataNode)); - } - @Override public void storeDataNodes(final String dataspaceName, final String anchorName, final Collection dataNodes) { @@ -301,19 +299,14 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService return fragmentEntity; } - private Collection buildFragmentEntitiesFromFragmentExtracts(final AnchorEntity anchorEntity, - final String normalizedXpath) { - final List fragmentExtracts = - fragmentRepository.findByAnchorAndParentXpath(anchorEntity, normalizedXpath); - return FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts); - } - @Override @Timed(value = "cps.data.persistence.service.datanode.query", description = "Time taken to query data nodes") public List queryDataNodes(final String dataspaceName, final String anchorName, final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { - final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName); + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + final AnchorEntity anchorEntity = Strings.isNullOrEmpty(anchorName) ? ALL_ANCHORS + : anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName); final CpsPathQuery cpsPathQuery; try { cpsPathQuery = CpsPathUtil.getCpsPathQuery(cpsPath); @@ -322,57 +315,53 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } Collection fragmentEntities; - if (canUseRegexQuickFind(fetchDescendantsOption, cpsPathQuery)) { - return getDataNodesUsingRegexQuickFind(fetchDescendantsOption, anchorEntity, cpsPathQuery); + if (anchorEntity == ALL_ANCHORS) { + fragmentEntities = fragmentRepository.findByDataspaceAndCpsPath(dataspaceEntity, cpsPathQuery); + } else { + fragmentEntities = fragmentRepository.findByAnchorAndCpsPath(anchorEntity, cpsPathQuery); } - fragmentEntities = fragmentRepository.findByAnchorAndCpsPath(anchorEntity.getId(), cpsPathQuery); if (cpsPathQuery.hasAncestorAxis()) { final Collection ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery); - fragmentEntities = getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption); + if (anchorEntity == ALL_ANCHORS) { + fragmentEntities = fragmentRepository.findByDataspaceAndXpathIn(dataspaceEntity, ancestorXpaths); + } else { + fragmentEntities = fragmentRepository.findByAnchorAndXpathIn(anchorEntity, ancestorXpaths); + } } - return createDataNodesFromProxiedFragmentEntities(fetchDescendantsOption, anchorEntity, fragmentEntities); - } - - private static boolean canUseRegexQuickFind(final FetchDescendantsOption fetchDescendantsOption, - final CpsPathQuery cpsPathQuery) { - return fetchDescendantsOption.equals(FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) - && !cpsPathQuery.hasLeafConditions() - && !cpsPathQuery.hasTextFunctionCondition(); + fragmentEntities = prefetchDescendantsForFragmentEntities(fetchDescendantsOption, anchorEntity, + fragmentEntities); + return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities); } - private List getDataNodesUsingRegexQuickFind(final FetchDescendantsOption fetchDescendantsOption, - final AnchorEntity anchorEntity, - final CpsPathQuery cpsPathQuery) { - Collection fragmentEntities; - final String xpathRegex = FragmentQueryBuilder.getXpathSqlRegex(cpsPathQuery, true); - final List fragmentExtracts = - fragmentRepository.quickFindWithDescendants(anchorEntity.getId(), xpathRegex); - fragmentEntities = FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts); - if (cpsPathQuery.hasAncestorAxis()) { - final Collection ancestorXpaths = processAncestorXpath(fragmentEntities, cpsPathQuery); - fragmentEntities = getFragmentEntities(anchorEntity, ancestorXpaths, fetchDescendantsOption); - } - return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities); + @Override + public List queryDataNodesAcrossAnchors(final String dataspaceName, final String cpsPath, + final FetchDescendantsOption fetchDescendantsOption) { + return queryDataNodes(dataspaceName, QUERY_ACROSS_ANCHORS, cpsPath, fetchDescendantsOption); } - private List createDataNodesFromProxiedFragmentEntities( + private Collection prefetchDescendantsForFragmentEntities( final FetchDescendantsOption fetchDescendantsOption, final AnchorEntity anchorEntity, final Collection proxiedFragmentEntities) { - final List dataNodes = new ArrayList<>(proxiedFragmentEntities.size()); - for (final FragmentEntity proxiedFragmentEntity : proxiedFragmentEntities) { - if (FetchDescendantsOption.OMIT_DESCENDANTS.equals(fetchDescendantsOption)) { - dataNodes.add(toDataNode(proxiedFragmentEntity, fetchDescendantsOption)); - } else { - final String normalizedXpath = getNormalizedXpath(proxiedFragmentEntity.getXpath()); - final Collection unproxiedFragmentEntities = - buildFragmentEntitiesFromFragmentExtracts(anchorEntity, normalizedXpath); - for (final FragmentEntity unproxiedFragmentEntity : unproxiedFragmentEntities) { - dataNodes.add(toDataNode(unproxiedFragmentEntity, fetchDescendantsOption)); - } - } + if (FetchDescendantsOption.OMIT_DESCENDANTS.equals(fetchDescendantsOption)) { + return proxiedFragmentEntities; } - return Collections.unmodifiableList(dataNodes); + + final List fragmentEntityIds = proxiedFragmentEntities.stream() + .map(FragmentEntity::getId).collect(Collectors.toList()); + + final List fragmentExtracts = + fragmentRepository.findExtractsWithDescendantsByIds(fragmentEntityIds, fetchDescendantsOption.getDepth()); + + if (anchorEntity == ALL_ANCHORS) { + final Collection anchorIds = fragmentExtracts.stream() + .map(FragmentExtract::getAnchorId).collect(Collectors.toSet()); + final List anchorEntities = anchorRepository.findAllById(anchorIds); + final Map anchorEntityPerId = anchorEntities.stream() + .collect(Collectors.toMap(AnchorEntity::getId, Function.identity())); + return FragmentEntityArranger.toFragmentEntityTreesAcrossAnchors(anchorEntityPerId, fragmentExtracts); + } + return FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts); } private List createDataNodesFromFragmentEntities(final FetchDescendantsOption fetchDescendantsOption, @@ -415,8 +404,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService final CpsPathQuery cpsPathQuery) { final Set ancestorXpath = new HashSet<>(); final Pattern pattern = - Pattern.compile("([\\s\\S]*/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier()) - + REG_EX_FOR_OPTIONAL_LIST_INDEX + "/[\\s\\S]*"); + Pattern.compile("(.*/" + Pattern.quote(cpsPathQuery.getAncestorSchemaNodeIdentifier()) + + REG_EX_FOR_OPTIONAL_LIST_INDEX + "/.*"); for (final FragmentEntity fragmentEntity : fragmentEntities) { final Matcher matcher = pattern.matcher(fragmentEntity.getXpath()); if (matcher.matches()) { @@ -436,6 +425,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService return new DataNodeBuilder() .withXpath(fragmentEntity.getXpath()) .withLeaves(leaves) + .withDataspace(fragmentEntity.getAnchor().getDataspace().getName()) + .withAnchor(fragmentEntity.getAnchor().getName()) .withChildDataNodes(childDataNodes).build(); } @@ -459,34 +450,30 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } @Override - public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath, - final Map updateLeaves) { + public void batchUpdateDataLeaves(final String dataspaceName, final String anchorName, + final Map> updatedLeavesPerXPath) { final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName); - final FragmentEntity fragmentEntity = getFragmentEntity(anchorEntity, xpath); - final String currentLeavesAsString = fragmentEntity.getAttributes(); - final String mergedLeaves = mergeLeaves(updateLeaves, currentLeavesAsString); - fragmentEntity.setAttributes(mergedLeaves); - fragmentRepository.save(fragmentEntity); - } - @Override - public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName, - final DataNode dataNode) { - final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName); - final FragmentEntity fragmentEntity = getFragmentEntity(anchorEntity, dataNode.getXpath()); - updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode); + final Collection xpathsOfUpdatedLeaves = updatedLeavesPerXPath.keySet(); + final Collection fragmentEntities = getFragmentEntities(anchorEntity, xpathsOfUpdatedLeaves, + FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); + + for (final FragmentEntity fragmentEntity : fragmentEntities) { + final Map updatedLeaves = updatedLeavesPerXPath.get(fragmentEntity.getXpath()); + final String mergedLeaves = mergeLeaves(updatedLeaves, fragmentEntity.getAttributes()); + fragmentEntity.setAttributes(mergedLeaves); + } + try { - fragmentRepository.save(fragmentEntity); + fragmentRepository.saveAll(fragmentEntities); } catch (final StaleStateException staleStateException) { - throw new ConcurrencyException("Concurrent Transactions", - String.format("dataspace :'%s', Anchor : '%s' and xpath: '%s' is updated by another transaction.", - dataspaceName, anchorName, dataNode.getXpath())); + retryUpdateDataNodesIndividually(anchorEntity, fragmentEntities); } } @Override public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName, - final List updatedDataNodes) { + final Collection updatedDataNodes) { final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName); final Map xpathToUpdatedDataNode = updatedDataNodes.stream() @@ -711,9 +698,13 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } private String mergeLeaves(final Map updateLeaves, final String currentLeavesAsString) { - final Map currentLeavesAsMap = currentLeavesAsString.isEmpty() - ? new HashMap<>() : jsonObjectMapper.convertJsonString(currentLeavesAsString, Map.class); - currentLeavesAsMap.putAll(updateLeaves); + Map currentLeavesAsMap = new HashMap<>(); + if (currentLeavesAsString != null) { + currentLeavesAsMap = currentLeavesAsString.isEmpty() + ? new HashMap<>() : jsonObjectMapper.convertJsonString(currentLeavesAsString, Map.class); + currentLeavesAsMap.putAll(updateLeaves); + } + if (currentLeavesAsMap.isEmpty()) { return ""; }