summaryrefslogtreecommitdiffstats
path: root/cps-ri/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'cps-ri/src/main')
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java2
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java16
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java127
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java11
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java73
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/repository/FragmentRepository.java6
6 files changed, 146 insertions, 89 deletions
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
index 2ffbb4ae0e..82afc5a818 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/entities/FragmentEntity.java
@@ -44,6 +44,7 @@ import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
+import lombok.ToString;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@@ -89,6 +90,7 @@ public class FragmentEntity implements Serializable {
@JoinColumn(name = "anchor_id")
private AnchorEntity anchor;
+ @ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Set<FragmentEntity> childFragments;
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
index 2cebfc72c0..162b268d87 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsAdminPersistenceServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2022 Nordix Foundation.
+ * Copyright (C) 2020-2023 Nordix Foundation.
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -131,6 +131,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
}
@Override
+ public Collection<Anchor> getAnchors(final String dataspaceName, final Collection<String> schemaSetNames) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ return anchorRepository.findAllByDataspaceAndSchemaSetNameIn(dataspaceEntity, schemaSetNames)
+ .stream().map(CpsAdminPersistenceServiceImpl::toAnchor).collect(Collectors.toSet());
+ }
+
+ @Override
public Collection<Anchor> queryAnchors(final String dataspaceName, final Collection<String> inputModuleNames) {
try {
validateDataspaceAndModuleNames(dataspaceName, inputModuleNames);
@@ -157,6 +164,13 @@ public class CpsAdminPersistenceServiceImpl implements CpsAdminPersistenceServic
anchorRepository.delete(anchorEntity);
}
+ @Transactional
+ @Override
+ public void deleteAnchors(final String dataspaceName, final Collection<String> anchorNames) {
+ final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ anchorRepository.deleteAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
+ }
+
private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
final var dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
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 5b310efd5d..f634008dc6 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
@@ -3,7 +3,7 @@
* Copyright (C) 2021-2023 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2020-2022 Bell Canada.
- * Modifications Copyright (C) 2022 TechMahindra Ltd.
+ * Modifications Copyright (C) 2022-2023 TechMahindra Ltd.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -57,6 +57,7 @@ import org.onap.cps.spi.exceptions.ConcurrencyException;
import org.onap.cps.spi.exceptions.CpsAdminException;
import org.onap.cps.spi.exceptions.CpsPathException;
import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
+import org.onap.cps.spi.exceptions.DataNodeNotFoundExceptionBatch;
import org.onap.cps.spi.model.DataNode;
import org.onap.cps.spi.model.DataNodeBuilder;
import org.onap.cps.spi.repository.AnchorRepository;
@@ -120,7 +121,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
private void addNewChildDataNode(final String dataspaceName, final String anchorName,
final String parentNodeXpath, final DataNode newChild) {
final FragmentEntity parentFragmentEntity =
- getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, parentNodeXpath);
+ getFragmentEntity(dataspaceName, anchorName, parentNodeXpath);
final FragmentEntity newChildAsFragmentEntity =
convertToFragmentWithAllDescendants(parentFragmentEntity.getDataspace(),
parentFragmentEntity.getAnchor(), newChild);
@@ -136,7 +137,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
private void addChildrenDataNodes(final String dataspaceName, final String anchorName, final String parentNodeXpath,
final Collection<DataNode> newChildren) {
final FragmentEntity parentFragmentEntity =
- getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, parentNodeXpath);
+ getFragmentEntity(dataspaceName, anchorName, parentNodeXpath);
final List<FragmentEntity> fragmentEntities = new ArrayList<>(newChildren.size());
try {
newChildren.forEach(newChildAsDataNode -> {
@@ -249,17 +250,28 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
@Override
- public DataNode getDataNode(final String dataspaceName, final String anchorName, final String xpath,
- final FetchDescendantsOption fetchDescendantsOption) {
- final FragmentEntity fragmentEntity = getFragmentByXpath(dataspaceName, anchorName, xpath,
- fetchDescendantsOption);
- return toDataNode(fragmentEntity, fetchDescendantsOption);
+ public Collection<DataNode> getDataNodes(final String dataspaceName, final String anchorName,
+ final String xpath,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ final String targetXpath = isRootXpath(xpath) ? xpath : CpsPathUtil.getNormalizedXpath(xpath);
+ final Collection<DataNode> dataNodes = getDataNodesForMultipleXpaths(dataspaceName, anchorName,
+ Collections.singletonList(targetXpath), fetchDescendantsOption);
+ if (dataNodes.isEmpty()) {
+ throw new DataNodeNotFoundException(dataspaceName, anchorName, xpath);
+ }
+ return dataNodes;
}
@Override
- public Collection<DataNode> getDataNodes(final String dataspaceName, final String anchorName,
- final Collection<String> xpaths,
- final FetchDescendantsOption fetchDescendantsOption) {
+ public Collection<DataNode> getDataNodesForMultipleXpaths(final String dataspaceName, final String anchorName,
+ final Collection<String> xpaths,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ final Collection<FragmentEntity> fragmentEntities = getFragmentEntities(dataspaceName, anchorName, xpaths);
+ return toDataNodes(fragmentEntities, fetchDescendantsOption);
+ }
+
+ private Collection<FragmentEntity> getFragmentEntities(final String dataspaceName, final String anchorName,
+ final Collection<String> xpaths) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
@@ -271,7 +283,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
try {
normalizedXpaths.add(CpsPathUtil.getNormalizedXpath(xpath));
} catch (final PathParsingException e) {
- log.warn("Error parsing xpath \"{}\" in getDataNodes: {}", xpath, e.getMessage());
+ log.warn("Error parsing xpath \"{}\": {}", xpath, e.getMessage());
}
}
final Collection<FragmentEntity> fragmentEntities =
@@ -283,17 +295,10 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
fragmentEntities.addAll(FragmentEntityArranger.toFragmentEntityTrees(anchorEntity, fragmentExtracts));
}
- return toDataNodes(fragmentEntities, fetchDescendantsOption);
+ return fragmentEntities;
}
- private FragmentEntity getFragmentWithoutDescendantsByXpath(final String dataspaceName,
- final String anchorName,
- final String xpath) {
- return getFragmentByXpath(dataspaceName, anchorName, xpath, FetchDescendantsOption.OMIT_DESCENDANTS);
- }
-
- private FragmentEntity getFragmentByXpath(final String dataspaceName, final String anchorName,
- final String xpath, final FetchDescendantsOption fetchDescendantsOption) {
+ private FragmentEntity getFragmentEntity(final String dataspaceName, final String anchorName, final String xpath) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
final FragmentEntity fragmentEntity;
@@ -304,13 +309,8 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
.stream().findFirst().orElse(null);
} else {
final String normalizedXpath = getNormalizedXpath(xpath);
- if (FetchDescendantsOption.OMIT_DESCENDANTS.equals(fetchDescendantsOption)) {
- fragmentEntity =
- fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, normalizedXpath);
- } else {
- fragmentEntity = buildFragmentEntitiesFromFragmentExtracts(anchorEntity, normalizedXpath)
- .stream().findFirst().orElse(null);
- }
+ fragmentEntity =
+ fragmentRepository.getByDataspaceAndAnchorAndXpath(dataspaceEntity, anchorEntity, normalizedXpath);
}
if (fragmentEntity == null) {
throw new DataNodeNotFoundException(dataspaceEntity.getName(), anchorEntity.getName(), xpath);
@@ -486,7 +486,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
@Override
public void updateDataLeaves(final String dataspaceName, final String anchorName, final String xpath,
final Map<String, Serializable> updateLeaves) {
- final FragmentEntity fragmentEntity = getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, xpath);
+ final FragmentEntity fragmentEntity = getFragmentEntity(dataspaceName, anchorName, xpath);
final String currentLeavesAsString = fragmentEntity.getAttributes();
final String mergedLeaves = mergeLeaves(updateLeaves, currentLeavesAsString);
fragmentEntity.setAttributes(mergedLeaves);
@@ -496,8 +496,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
@Override
public void updateDataNodeAndDescendants(final String dataspaceName, final String anchorName,
final DataNode dataNode) {
- final FragmentEntity fragmentEntity =
- getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, dataNode.getXpath());
+ final FragmentEntity fragmentEntity = getFragmentEntity(dataspaceName, anchorName, dataNode.getXpath());
updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode);
try {
fragmentRepository.save(fragmentEntity);
@@ -509,21 +508,24 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
@Override
- public void updateDataNodesAndDescendants(final String dataspaceName,
- final String anchorName,
- final List<DataNode> dataNodes) {
-
- final Map<DataNode, FragmentEntity> dataNodeFragmentEntityMap = dataNodes.stream()
- .collect(Collectors.toMap(
- dataNode -> dataNode,
- dataNode ->
- getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, dataNode.getXpath())));
- dataNodeFragmentEntityMap.forEach(
- (dataNode, fragmentEntity) -> updateFragmentEntityAndDescendantsWithDataNode(fragmentEntity, dataNode));
+ public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
+ final List<DataNode> updatedDataNodes) {
+ final Map<String, DataNode> xpathToUpdatedDataNode = updatedDataNodes.stream()
+ .collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
+
+ final Collection<String> xpaths = xpathToUpdatedDataNode.keySet();
+ final Collection<FragmentEntity> existingFragmentEntities =
+ getFragmentEntities(dataspaceName, anchorName, xpaths);
+
+ for (final FragmentEntity existingFragmentEntity : existingFragmentEntities) {
+ final DataNode updatedDataNode = xpathToUpdatedDataNode.get(existingFragmentEntity.getXpath());
+ updateFragmentEntityAndDescendantsWithDataNode(existingFragmentEntity, updatedDataNode);
+ }
+
try {
- fragmentRepository.saveAll(dataNodeFragmentEntityMap.values());
+ fragmentRepository.saveAll(existingFragmentEntities);
} catch (final StaleStateException staleStateException) {
- retryUpdateDataNodesIndividually(dataspaceName, anchorName, dataNodeFragmentEntityMap.values());
+ retryUpdateDataNodesIndividually(dataspaceName, anchorName, existingFragmentEntities);
}
}
@@ -577,8 +579,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
@Transactional
public void replaceListContent(final String dataspaceName, final String anchorName, final String parentNodeXpath,
final Collection<DataNode> newListElements) {
- final FragmentEntity parentEntity =
- getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, parentNodeXpath);
+ final FragmentEntity parentEntity = getFragmentEntity(dataspaceName, anchorName, parentNodeXpath);
final String listElementXpathPrefix = getListElementXpathPrefix(newListElements);
final Map<String, FragmentEntity> existingListElementFragmentEntitiesByXPath =
extractListElementFragmentEntitiesByXPath(parentEntity.getChildFragments(), listElementXpathPrefix);
@@ -607,22 +608,44 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
@Override
@Transactional
+ public void deleteDataNodes(final String dataspaceName, final Collection<String> anchorNames) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ final Collection<AnchorEntity> anchorEntities =
+ anchorRepository.findAllByDataspaceAndNameIn(dataspaceEntity, anchorNames);
+ fragmentRepository.deleteByAnchorIn(anchorEntities);
+ }
+
+ @Override
+ @Transactional
public void deleteDataNodes(final String dataspaceName, final String anchorName,
final Collection<String> xpathsToDelete) {
final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
final AnchorEntity anchorEntity = anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
- final Collection<String> normalizedXpaths = new ArrayList<>(xpathsToDelete.size());
+ final Collection<String> deleteChecklist = new HashSet<>(xpathsToDelete.size());
for (final String xpath : xpathsToDelete) {
try {
- normalizedXpaths.add(CpsPathUtil.getNormalizedXpath(xpath));
+ deleteChecklist.add(CpsPathUtil.getNormalizedXpath(xpath));
} catch (final PathParsingException e) {
- log.debug("Error parsing xpath \"{}\" in deleteDataNodes: {}", xpath, e.getMessage());
+ log.debug("Error parsing xpath \"{}\": {}", xpath, e.getMessage());
}
}
- fragmentRepository.deleteByAnchorIdAndXpaths(anchorEntity.getId(), normalizedXpaths);
- fragmentRepository.deleteListsByAnchorIdAndXpaths(anchorEntity.getId(), normalizedXpaths);
+ final Collection<String> xpathsToExistingContainers =
+ fragmentRepository.findAllXpathByAnchorAndXpathIn(anchorEntity, deleteChecklist);
+ deleteChecklist.removeAll(xpathsToExistingContainers);
+
+ final Collection<String> xpathsToExistingLists = deleteChecklist.stream()
+ .filter(xpath -> fragmentRepository.existsByAnchorAndXpathStartsWith(anchorEntity, xpath + "["))
+ .collect(Collectors.toList());
+ deleteChecklist.removeAll(xpathsToExistingLists);
+
+ if (!deleteChecklist.isEmpty()) {
+ throw new DataNodeNotFoundExceptionBatch(dataspaceName, anchorName, deleteChecklist);
+ }
+
+ fragmentRepository.deleteByAnchorIdAndXpaths(anchorEntity.getId(), xpathsToExistingContainers);
+ fragmentRepository.deleteListsByAnchorIdAndXpaths(anchorEntity.getId(), xpathsToExistingLists);
}
@Override
@@ -652,7 +675,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
} else {
parentNodeXpath = CpsPathUtil.getNormalizedParentXpath(targetXpath);
}
- parentFragmentEntity = getFragmentWithoutDescendantsByXpath(dataspaceName, anchorName, parentNodeXpath);
+ parentFragmentEntity = getFragmentEntity(dataspaceName, anchorName, parentNodeXpath);
if (CpsPathUtil.isPathToListElement(targetXpath)) {
targetDeleted = deleteDataNode(parentFragmentEntity, targetXpath);
} else {
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
index 3dbd578c73..46b0fec1c2 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/AnchorRepository.java
@@ -47,6 +47,12 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
Collection<AnchorEntity> findAllBySchemaSet(@NotNull SchemaSetEntity schemaSetEntity);
+ Collection<AnchorEntity> findAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> anchorNames);
+
+ Collection<AnchorEntity> findAllByDataspaceAndSchemaSetNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> schemaSetNames);
+
Integer countByDataspace(@NotNull DataspaceEntity dataspaceEntity);
@Query(value = "SELECT anchor.* FROM yang_resource\n"
@@ -58,4 +64,7 @@ public interface AnchorRepository extends JpaRepository<AnchorEntity, Integer> {
+ "HAVING COUNT(DISTINCT module_name) = :sizeOfModuleNames", nativeQuery = true)
Collection<AnchorEntity> getAnchorsByDataspaceIdAndModuleNames(@Param("dataspaceId") int dataspaceId,
@Param("moduleNames") Collection<String> moduleNames, @Param("sizeOfModuleNames") int sizeOfModuleNames);
-} \ No newline at end of file
+
+ void deleteAllByDataspaceAndNameIn(@NotNull DataspaceEntity dataspaceEntity,
+ @NotNull Collection<String> anchorNames);
+}
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
index 0e4d359da5..5c5458a039 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/FragmentNativeRepositoryImpl.java
@@ -21,8 +21,11 @@
package org.onap.cps.spi.repository;
import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
+import javax.persistence.Query;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@@ -40,55 +43,55 @@ public class FragmentNativeRepositoryImpl implements FragmentNativeRepository {
@PersistenceContext
private final EntityManager entityManager;
- private final TempTableCreator tempTableCreator;
-
@Override
public void deleteFragmentEntity(final long fragmentEntityId) {
entityManager.createNativeQuery(
- DROP_FRAGMENT_CONSTRAINT
- + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
- + "DELETE FROM fragment WHERE id = ?;"
- + DROP_FRAGMENT_CONSTRAINT
- + ADD_ORIGINAL_FRAGMENT_CONSTRAINT)
+ addFragmentConstraintWithDeleteCascade("DELETE FROM fragment WHERE id = ?"))
.setParameter(1, fragmentEntityId)
.executeUpdate();
}
@Override
- // Accept security hotspot as temporary table name in SQL query is created internally, not from user input.
- @SuppressWarnings("squid:S2077")
public void deleteByAnchorIdAndXpaths(final int anchorId, final Collection<String> xpaths) {
- if (!xpaths.isEmpty()) {
- final String tempTableName = tempTableCreator.createTemporaryTable("xpathsToDelete", xpaths, "xpath");
- entityManager.createNativeQuery(
- DROP_FRAGMENT_CONSTRAINT
- + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
- + "DELETE FROM fragment f USING " + tempTableName + " t"
- + " WHERE f.anchor_id = :anchorId AND f.xpath = t.xpath;"
- + DROP_FRAGMENT_CONSTRAINT
- + ADD_ORIGINAL_FRAGMENT_CONSTRAINT)
- .setParameter("anchorId", anchorId)
- .executeUpdate();
- }
+ final String queryString = addFragmentConstraintWithDeleteCascade(
+ "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath IN (:parameterPlaceholders))");
+ executeUpdateWithAnchorIdAndCollection(queryString, anchorId, xpaths);
}
@Override
- // Accept security hotspot as temporary table name in SQL query is created internally, not from user input.
+ public void deleteListsByAnchorIdAndXpaths(final int anchorId, final Collection<String> listXpaths) {
+ final Collection<String> listXpathPatterns =
+ listXpaths.stream().map(listXpath -> listXpath + "[%").collect(Collectors.toSet());
+ final String queryString = addFragmentConstraintWithDeleteCascade(
+ "DELETE FROM fragment f WHERE f.anchor_id = ? AND (f.xpath LIKE ANY (array[:parameterPlaceholders]))");
+ executeUpdateWithAnchorIdAndCollection(queryString, anchorId, listXpathPatterns);
+ }
+
+ // Accept security hotspot as placeholders in SQL query are created internally, not from user input.
@SuppressWarnings("squid:S2077")
- public void deleteListsByAnchorIdAndXpaths(final int anchorId, final Collection<String> xpaths) {
- if (!xpaths.isEmpty()) {
- final String tempTableName = tempTableCreator.createTemporaryTable("xpathsToDelete", xpaths, "xpath");
- entityManager.createNativeQuery(
- DROP_FRAGMENT_CONSTRAINT
- + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
- + "DELETE FROM fragment f USING " + tempTableName + " t"
- + " WHERE f.anchor_id = :anchorId AND f.xpath LIKE CONCAT(t.xpath, :xpathListPattern);"
- + DROP_FRAGMENT_CONSTRAINT
- + ADD_ORIGINAL_FRAGMENT_CONSTRAINT)
- .setParameter("anchorId", anchorId)
- .setParameter("xpathListPattern", "[%%")
- .executeUpdate();
+ private void executeUpdateWithAnchorIdAndCollection(final String sqlTemplate, final int anchorId,
+ final Collection<String> collection) {
+ if (!collection.isEmpty()) {
+ final String parameterPlaceholders = String.join(",", Collections.nCopies(collection.size(), "?"));
+ final String queryStringWithParameterPlaceholders =
+ sqlTemplate.replaceFirst(":parameterPlaceholders\\b", parameterPlaceholders);
+
+ final Query query = entityManager.createNativeQuery(queryStringWithParameterPlaceholders);
+ query.setParameter(1, anchorId);
+ int parameterIndex = 2;
+ for (final String parameterValue : collection) {
+ query.setParameter(parameterIndex++, parameterValue);
+ }
+ query.executeUpdate();
}
}
+ private static String addFragmentConstraintWithDeleteCascade(final String queryString) {
+ return DROP_FRAGMENT_CONSTRAINT
+ + ADD_FRAGMENT_CONSTRAINT_WITH_CASCADE
+ + queryString + ";"
+ + DROP_FRAGMENT_CONSTRAINT
+ + ADD_ORIGINAL_FRAGMENT_CONSTRAINT;
+ }
+
}
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 8bdb7d985b..51ebcb4127 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
@@ -100,4 +100,10 @@ public interface FragmentRepository extends JpaRepository<FragmentEntity, Long>,
nativeQuery = true)
List<FragmentExtract> quickFindWithDescendants(@Param("anchorId") int anchorId,
@Param("xpathRegex") String xpathRegex);
+
+ @Query("SELECT f.xpath FROM FragmentEntity f WHERE f.anchor = :anchor AND f.xpath IN :xpaths")
+ List<String> findAllXpathByAnchorAndXpathIn(@Param("anchor") AnchorEntity anchorEntity,
+ @Param("xpaths") Collection<String> xpaths);
+
+ boolean existsByAnchorAndXpathStartsWith(AnchorEntity anchorEntity, String xpath);
}