diff options
author | Bruno Sakoto <bruno.sakoto@bell.ca> | 2021-07-22 11:37:51 +0000 |
---|---|---|
committer | Gerrit Code Review <gerrit@onap.org> | 2021-07-22 11:37:51 +0000 |
commit | 9ac6d71e6b4297d26fddd2c8fb3095e15c2444da (patch) | |
tree | 0ba0b8faec9dac17b292b020ea4b74a4e4329737 /cps-ri/src/main | |
parent | 187c8c84dcfa347ba3475a36c73b36ef59874655 (diff) | |
parent | a3e8d92c291a61395e91554004af318f70090ecf (diff) |
Merge "Fixed inconsistent data issue with replaceNode"
Diffstat (limited to 'cps-ri/src/main')
-rw-r--r-- | cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java | 68 |
1 files changed, 50 insertions, 18 deletions
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 6e12d06011..fdbafd4bee 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 @@ -37,6 +37,8 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.transaction.Transactional; +import lombok.extern.slf4j.Slf4j; +import org.hibernate.StaleStateException; import org.onap.cps.cpspath.parser.CpsPathQuery; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; @@ -44,28 +46,40 @@ import org.onap.cps.spi.entities.AnchorEntity; import org.onap.cps.spi.entities.DataspaceEntity; import org.onap.cps.spi.entities.FragmentEntity; import org.onap.cps.spi.exceptions.AlreadyDefinedException; +import org.onap.cps.spi.exceptions.ConcurrencyException; import org.onap.cps.spi.exceptions.CpsPathException; 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.FragmentRepository; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; @Service +@Slf4j public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService { - @Autowired private DataspaceRepository dataspaceRepository; - @Autowired private AnchorRepository anchorRepository; - @Autowired private FragmentRepository fragmentRepository; + /** + * Constructor. + * + * @param dataspaceRepository dataspaceRepository + * @param anchorRepository anchorRepository + * @param fragmentRepository fragmentRepository + */ + public CpsDataPersistenceServiceImpl(final DataspaceRepository dataspaceRepository, + final AnchorRepository anchorRepository, final FragmentRepository fragmentRepository) { + this.dataspaceRepository = dataspaceRepository; + this.anchorRepository = anchorRepository; + this.fragmentRepository = fragmentRepository; + } + private static final Gson GSON = new GsonBuilder().create(); private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@\\S+?]){0,1})"; @@ -234,18 +248,41 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } @Override - public void replaceDataNodeTree(final String dataspaceName, final String anchorName, final DataNode dataNode) { + public void replaceDataNodeTree(final String dataspaceName, final String anchorName, + final DataNode dataNode) { final var fragmentEntity = getFragmentByXpath(dataspaceName, anchorName, dataNode.getXpath()); - removeExistingDescendants(fragmentEntity); + replaceDataNodeTree(fragmentEntity, dataNode); + try { + fragmentRepository.save(fragmentEntity); + } 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()), + staleStateException); + } + } - fragmentEntity.setAttributes(GSON.toJson(dataNode.getLeaves())); - final Set<FragmentEntity> childFragmentEntities = dataNode.getChildDataNodes().stream().map( - childDataNode -> convertToFragmentWithAllDescendants( - fragmentEntity.getDataspace(), fragmentEntity.getAnchor(), childDataNode) - ).collect(Collectors.toUnmodifiableSet()); - fragmentEntity.setChildFragments(childFragmentEntities); + private void replaceDataNodeTree(final FragmentEntity existingFragmentEntity, final DataNode submittedDataNode) { - fragmentRepository.save(fragmentEntity); + existingFragmentEntity.setAttributes(GSON.toJson(submittedDataNode.getLeaves())); + + final Map<String, FragmentEntity> existingChildrenByXpath = existingFragmentEntity.getChildFragments() + .stream().collect(Collectors.toMap(FragmentEntity::getXpath, childFragmentEntity -> childFragmentEntity)); + + final var updatedChildFragments = new HashSet<FragmentEntity>(); + + for (final DataNode submittedChildDataNode : submittedDataNode.getChildDataNodes()) { + final FragmentEntity childFragment; + if (existingChildrenByXpath.containsKey(submittedChildDataNode.getXpath())) { + childFragment = existingChildrenByXpath.get(submittedChildDataNode.getXpath()); + replaceDataNodeTree(childFragment, submittedChildDataNode); + } else { + childFragment = convertToFragmentWithAllDescendants( + existingFragmentEntity.getDataspace(), existingFragmentEntity.getAnchor(), submittedChildDataNode); + } + updatedChildFragments.add(childFragment); + } + existingFragmentEntity.setChildFragments(updatedChildFragments); } @Override @@ -272,11 +309,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService } } - private void removeExistingDescendants(final FragmentEntity fragmentEntity) { - fragmentEntity.setChildFragments(Collections.emptySet()); - fragmentRepository.save(fragmentEntity); - } - private static boolean isRootXpath(final String xpath) { return "/".equals(xpath) || "".equals(xpath); } |