summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLee Anjella Macabuhay <lee.anjella.macabuhay@est.tech>2024-01-22 09:40:02 +0000
committerGerrit Code Review <gerrit@onap.org>2024-01-22 09:40:02 +0000
commitb0e7e756cfbaa9828d503891b47c8ac75c2dc0d3 (patch)
tree6a962973ef5528cbef982a8b54122185dd4a06c7
parent2ba1fea36de49e9b9e82882ead17fa51f53ea66f (diff)
parent84c8d8d383469e05420f8e3e482d00e527c87734 (diff)
Merge "Remove Lambda & Restructure File"
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java10
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java55
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/impl/CpsDataPersistenceServiceImpl.java542
3 files changed, 298 insertions, 309 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java
index a31332f094..0ed95adff2 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -164,12 +164,12 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
}
private void setInitialStates(final YangModelCmHandle yangModelCmHandle) {
- CompositeStateUtils.setInitialDataStoreSyncState().accept(yangModelCmHandle.getCompositeState());
- CompositeStateUtils.setCompositeState(READY).accept(yangModelCmHandle.getCompositeState());
+ CompositeStateUtils.setInitialDataStoreSyncState(yangModelCmHandle.getCompositeState());
+ CompositeStateUtils.setCompositeState(READY, yangModelCmHandle.getCompositeState());
}
private void retryCmHandle(final YangModelCmHandle yangModelCmHandle) {
- CompositeStateUtils.setCompositeStateForRetry().accept(yangModelCmHandle.getCompositeState());
+ CompositeStateUtils.setCompositeStateForRetry(yangModelCmHandle.getCompositeState());
}
private void registerNewCmHandle(final YangModelCmHandle yangModelCmHandle) {
@@ -178,7 +178,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState
}
private void setCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState targetCmHandleState) {
- CompositeStateUtils.setCompositeState(targetCmHandleState).accept(yangModelCmHandle.getCompositeState());
+ CompositeStateUtils.setCompositeState(targetCmHandleState, yangModelCmHandle.getCompositeState());
}
private boolean isNew(final CompositeState existingCompositeState) {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java
index 99cca8c0b3..35ad54fdef 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
package org.onap.cps.ncmp.api.impl.inventory;
-import java.util.function.Consumer;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -34,31 +33,23 @@ public class CompositeStateUtils {
/**
* Sets the cmHandleState to the provided state and updates the timestamp.
- *
- * @return Updated CompositeState
*/
- public static Consumer<CompositeState> setCompositeState(final CmHandleState cmHandleState) {
- return compositeState -> {
- compositeState.setCmHandleState(cmHandleState);
- compositeState.setLastUpdateTimeNow();
- };
+ public static void setCompositeState(final CmHandleState cmHandleState,
+ final CompositeState compositeState) {
+ compositeState.setCmHandleState(cmHandleState);
+ compositeState.setLastUpdateTimeNow();
}
/**
* Set the Operational datastore sync state based on the global flag.
- *
- * @return Updated CompositeState
*/
- public static Consumer<CompositeState> setInitialDataStoreSyncState() {
-
- return compositeState -> {
- compositeState.setDataSyncEnabled(false);
- final CompositeState.Operational operational =
- getInitialDataStoreSyncState(compositeState.getDataSyncEnabled());
- final CompositeState.DataStores dataStores =
- CompositeState.DataStores.builder().operationalDataStore(operational).build();
- compositeState.setDataStores(dataStores);
- };
+ public static void setInitialDataStoreSyncState(final CompositeState compositeState) {
+ compositeState.setDataSyncEnabled(false);
+ final CompositeState.Operational operational =
+ getInitialDataStoreSyncState(compositeState.getDataSyncEnabled());
+ final CompositeState.DataStores dataStores =
+ CompositeState.DataStores.builder().operationalDataStore(operational).build();
+ compositeState.setDataStores(dataStores);
}
/**
@@ -91,19 +82,15 @@ public class CompositeStateUtils {
/**
* Sets the cmHandleState to ADVISED and retain the lock details. Used in retry scenarios.
- *
- * @return Updated CompositeState
*/
- public static Consumer<CompositeState> setCompositeStateForRetry() {
- return compositeState -> {
- compositeState.setCmHandleState(CmHandleState.ADVISED);
- compositeState.setLastUpdateTimeNow();
- final String oldLockReasonDetails = compositeState.getLockReason().getDetails();
- final CompositeState.LockReason lockReason =
- CompositeState.LockReason.builder()
- .lockReasonCategory(compositeState.getLockReason().getLockReasonCategory())
- .details(oldLockReasonDetails).build();
- compositeState.setLockReason(lockReason);
- };
+ public static void setCompositeStateForRetry(final CompositeState compositeState) {
+ compositeState.setCmHandleState(CmHandleState.ADVISED);
+ compositeState.setLastUpdateTimeNow();
+ final String oldLockReasonDetails = compositeState.getLockReason().getDetails();
+ final CompositeState.LockReason lockReason =
+ CompositeState.LockReason.builder()
+ .lockReasonCategory(compositeState.getLockReason().getLockReasonCategory())
+ .details(oldLockReasonDetails).build();
+ compositeState.setLockReason(lockReason);
}
}
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 1cfe21d3a2..fd47793a7a 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
@@ -84,67 +84,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
private static final String REG_EX_FOR_OPTIONAL_LIST_INDEX = "(\\[@.+?])?)";
@Override
- public void addChildDataNodes(final String dataspaceName, final String anchorName,
- final String parentNodeXpath, final Collection<DataNode> dataNodes) {
- final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
- addChildrenDataNodes(anchorEntity, parentNodeXpath, dataNodes);
- }
-
- @Override
- public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath,
- final Collection<DataNode> newListElements) {
- final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
- addChildrenDataNodes(anchorEntity, parentNodeXpath, newListElements);
- }
-
- private void addNewChildDataNode(final AnchorEntity anchorEntity, final String parentNodeXpath,
- final DataNode newChild) {
- final FragmentEntity parentFragmentEntity = getFragmentEntity(anchorEntity, parentNodeXpath);
- final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants(anchorEntity, newChild);
- newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId());
- try {
- fragmentRepository.save(newChildAsFragmentEntity);
- } catch (final DataIntegrityViolationException dataIntegrityViolationException) {
- throw AlreadyDefinedException.forDataNodes(Collections.singletonList(newChild.getXpath()),
- anchorEntity.getName());
- }
- }
-
- private void addChildrenDataNodes(final AnchorEntity anchorEntity, final String parentNodeXpath,
- final Collection<DataNode> newChildren) {
- final FragmentEntity parentFragmentEntity = getFragmentEntity(anchorEntity, parentNodeXpath);
- final List<FragmentEntity> fragmentEntities = new ArrayList<>(newChildren.size());
- try {
- for (final DataNode newChildAsDataNode : newChildren) {
- final FragmentEntity newChildAsFragmentEntity =
- convertToFragmentWithAllDescendants(anchorEntity, newChildAsDataNode);
- newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId());
- fragmentEntities.add(newChildAsFragmentEntity);
- }
- fragmentRepository.saveAll(fragmentEntities);
- } catch (final DataIntegrityViolationException dataIntegrityViolationException) {
- log.warn("Exception occurred : {} , While saving : {} children, retrying using individual save operations",
- dataIntegrityViolationException, fragmentEntities.size());
- retrySavingEachChildIndividually(anchorEntity, parentNodeXpath, newChildren);
- }
- }
-
- private void retrySavingEachChildIndividually(final AnchorEntity anchorEntity, final String parentNodeXpath,
- final Collection<DataNode> newChildren) {
- final Collection<String> failedXpaths = new HashSet<>();
- for (final DataNode newChild : newChildren) {
- try {
- addNewChildDataNode(anchorEntity, parentNodeXpath, newChild);
- } catch (final AlreadyDefinedException alreadyDefinedException) {
- failedXpaths.add(newChild.getXpath());
- }
- }
- if (!failedXpaths.isEmpty()) {
- throw AlreadyDefinedException.forDataNodes(failedXpaths, anchorEntity.getName());
- }
- }
-
- @Override
public void storeDataNodes(final String dataspaceName, final String anchorName,
final Collection<DataNode> dataNodes) {
final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
@@ -157,7 +96,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
fragmentRepository.saveAll(fragmentEntities);
} catch (final DataIntegrityViolationException exception) {
log.warn("Exception occurred : {} , While saving : {} data nodes, Retrying saving data nodes individually",
- exception, dataNodes.size());
+ exception, dataNodes.size());
storeDataNodesIndividually(anchorEntity, dataNodes);
}
}
@@ -197,79 +136,153 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return parentFragment;
}
- private FragmentEntity toFragmentEntity(final AnchorEntity anchorEntity, final DataNode dataNode) {
- return FragmentEntity.builder()
- .anchor(anchorEntity)
- .xpath(dataNode.getXpath())
- .attributes(jsonObjectMapper.asJsonString(dataNode.getLeaves()))
- .build();
+ @Override
+ public void addListElements(final String dataspaceName, final String anchorName, final String parentNodeXpath,
+ final Collection<DataNode> newListElements) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+ addChildrenDataNodes(anchorEntity, parentNodeXpath, newListElements);
}
@Override
- @Timed(value = "cps.data.persistence.service.datanode.get",
- description = "Time taken to get a data node")
- public Collection<DataNode> getDataNodes(final String dataspaceName, final String anchorName,
- final String xpath,
- final FetchDescendantsOption fetchDescendantsOption) {
- final String targetXpath = getNormalizedXpath(xpath);
- final Collection<DataNode> dataNodes = getDataNodesForMultipleXpaths(dataspaceName, anchorName,
- Collections.singletonList(targetXpath), fetchDescendantsOption);
- if (dataNodes.isEmpty()) {
- throw new DataNodeNotFoundException(dataspaceName, anchorName, xpath);
+ public void addChildDataNodes(final String dataspaceName, final String anchorName,
+ final String parentNodeXpath, final Collection<DataNode> dataNodes) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+ addChildrenDataNodes(anchorEntity, parentNodeXpath, dataNodes);
+ }
+
+ private void addChildrenDataNodes(final AnchorEntity anchorEntity, final String parentNodeXpath,
+ final Collection<DataNode> newChildren) {
+ final FragmentEntity parentFragmentEntity = getFragmentEntity(anchorEntity, parentNodeXpath);
+ final List<FragmentEntity> fragmentEntities = new ArrayList<>(newChildren.size());
+ try {
+ for (final DataNode newChildAsDataNode : newChildren) {
+ final FragmentEntity newChildAsFragmentEntity =
+ convertToFragmentWithAllDescendants(anchorEntity, newChildAsDataNode);
+ newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId());
+ fragmentEntities.add(newChildAsFragmentEntity);
+ }
+ fragmentRepository.saveAll(fragmentEntities);
+ } catch (final DataIntegrityViolationException dataIntegrityViolationException) {
+ log.warn("Exception occurred : {} , While saving : {} children, retrying using individual save operations",
+ dataIntegrityViolationException, fragmentEntities.size());
+ retrySavingEachChildIndividually(anchorEntity, parentNodeXpath, newChildren);
}
- return dataNodes;
}
- @Override
- @Timed(value = "cps.data.persistence.service.datanode.batch.get",
- description = "Time taken to get data nodes")
- public Collection<DataNode> getDataNodesForMultipleXpaths(final String dataspaceName, final String anchorName,
- final Collection<String> xpaths,
- final FetchDescendantsOption fetchDescendantsOption) {
- final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
- Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpaths);
- fragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(fetchDescendantsOption,
- fragmentEntities);
- return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
+ private void addNewChildDataNode(final AnchorEntity anchorEntity, final String parentNodeXpath,
+ final DataNode newChild) {
+ final FragmentEntity parentFragmentEntity = getFragmentEntity(anchorEntity, parentNodeXpath);
+ final FragmentEntity newChildAsFragmentEntity = convertToFragmentWithAllDescendants(anchorEntity, newChild);
+ newChildAsFragmentEntity.setParentId(parentFragmentEntity.getId());
+ try {
+ fragmentRepository.save(newChildAsFragmentEntity);
+ } catch (final DataIntegrityViolationException dataIntegrityViolationException) {
+ throw AlreadyDefinedException.forDataNodes(Collections.singletonList(newChild.getXpath()),
+ anchorEntity.getName());
+ }
}
- private Collection<FragmentEntity> getFragmentEntities(final AnchorEntity anchorEntity,
- final Collection<String> xpaths) {
- final Collection<String> normalizedXpaths = getNormalizedXpaths(xpaths);
+ private void retrySavingEachChildIndividually(final AnchorEntity anchorEntity, final String parentNodeXpath,
+ final Collection<DataNode> newChildren) {
+ final Collection<String> failedXpaths = new HashSet<>();
+ for (final DataNode newChild : newChildren) {
+ try {
+ addNewChildDataNode(anchorEntity, parentNodeXpath, newChild);
+ } catch (final AlreadyDefinedException alreadyDefinedException) {
+ failedXpaths.add(newChild.getXpath());
+ }
+ }
+ if (!failedXpaths.isEmpty()) {
+ throw AlreadyDefinedException.forDataNodes(failedXpaths, anchorEntity.getName());
+ }
+ }
- final boolean haveRootXpath = normalizedXpaths.removeIf(CpsDataPersistenceServiceImpl::isRootXpath);
+ @Override
+ public void batchUpdateDataLeaves(final String dataspaceName, final String anchorName,
+ final Map<String, Map<String, Serializable>> updatedLeavesPerXPath) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
- final List<FragmentEntity> fragmentEntities = fragmentRepository.findByAnchorAndXpathIn(anchorEntity,
- normalizedXpaths);
+ final Collection<String> xpathsOfUpdatedLeaves = updatedLeavesPerXPath.keySet();
+ final Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpathsOfUpdatedLeaves);
for (final FragmentEntity fragmentEntity : fragmentEntities) {
- normalizedXpaths.remove(fragmentEntity.getXpath());
+ final Map<String, Serializable> updatedLeaves = updatedLeavesPerXPath.get(fragmentEntity.getXpath());
+ final String mergedLeaves = mergeLeaves(updatedLeaves, fragmentEntity.getAttributes());
+ fragmentEntity.setAttributes(mergedLeaves);
}
- for (final String xpath : normalizedXpaths) {
- if (!CpsPathUtil.isPathToListElement(xpath)) {
- fragmentEntities.addAll(fragmentRepository.findListByAnchorAndXpath(anchorEntity, xpath));
- }
+ try {
+ fragmentRepository.saveAll(fragmentEntities);
+ } catch (final StaleStateException staleStateException) {
+ retryUpdateDataNodesIndividually(anchorEntity, fragmentEntities);
}
+ }
- if (haveRootXpath) {
- fragmentEntities.addAll(fragmentRepository.findRootsByAnchorId(anchorEntity.getId()));
+ @Override
+ public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
+ final Collection<DataNode> updatedDataNodes) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+
+ final Map<String, DataNode> xpathToUpdatedDataNode = updatedDataNodes.stream()
+ .collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
+
+ final Collection<String> xpaths = xpathToUpdatedDataNode.keySet();
+ Collection<FragmentEntity> existingFragmentEntities = getFragmentEntities(anchorEntity, xpaths);
+ existingFragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(
+ FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS, existingFragmentEntities);
+
+ for (final FragmentEntity existingFragmentEntity : existingFragmentEntities) {
+ final DataNode updatedDataNode = xpathToUpdatedDataNode.get(existingFragmentEntity.getXpath());
+ updateFragmentEntityAndDescendantsWithDataNode(existingFragmentEntity, updatedDataNode);
}
- return fragmentEntities;
+ try {
+ fragmentRepository.saveAll(existingFragmentEntities);
+ } catch (final StaleStateException staleStateException) {
+ retryUpdateDataNodesIndividually(anchorEntity, existingFragmentEntities);
+ }
}
- private FragmentEntity getFragmentEntity(final AnchorEntity anchorEntity, final String xpath) {
- final FragmentEntity fragmentEntity;
- if (isRootXpath(xpath)) {
- fragmentEntity = fragmentRepository.findOneByAnchorId(anchorEntity.getId()).orElse(null);
- } else {
- fragmentEntity = fragmentRepository.getByAnchorAndXpath(anchorEntity, getNormalizedXpath(xpath));
+ private void retryUpdateDataNodesIndividually(final AnchorEntity anchorEntity,
+ final Collection<FragmentEntity> fragmentEntities) {
+ final Collection<String> failedXpaths = new HashSet<>();
+ for (final FragmentEntity dataNodeFragment : fragmentEntities) {
+ try {
+ fragmentRepository.save(dataNodeFragment);
+ } catch (final StaleStateException staleStateException) {
+ failedXpaths.add(dataNodeFragment.getXpath());
+ }
}
- if (fragmentEntity == null) {
- throw new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath);
+ if (!failedXpaths.isEmpty()) {
+ final String failedXpathsConcatenated = String.join(",", failedXpaths);
+ throw new ConcurrencyException("Concurrent Transactions", String.format(
+ "DataNodes : %s in Dataspace :'%s' with Anchor : '%s' are updated by another transaction.",
+ failedXpathsConcatenated, anchorEntity.getDataspace().getName(), anchorEntity.getName()));
}
- return fragmentEntity;
+ }
+
+ private void updateFragmentEntityAndDescendantsWithDataNode(final FragmentEntity existingFragmentEntity,
+ final DataNode newDataNode) {
+ copyAttributesFromNewDataNode(existingFragmentEntity, newDataNode);
+
+ final Map<String, FragmentEntity> existingChildrenByXpath = existingFragmentEntity.getChildFragments().stream()
+ .collect(Collectors.toMap(FragmentEntity::getXpath, childFragmentEntity -> childFragmentEntity));
+
+ final Collection<FragmentEntity> updatedChildFragments = new HashSet<>();
+ for (final DataNode newDataNodeChild : newDataNode.getChildDataNodes()) {
+ final FragmentEntity childFragment;
+ if (isNewDataNode(newDataNodeChild, existingChildrenByXpath)) {
+ childFragment = convertToFragmentWithAllDescendants(existingFragmentEntity.getAnchor(),
+ newDataNodeChild);
+ } else {
+ childFragment = existingChildrenByXpath.get(newDataNodeChild.getXpath());
+ updateFragmentEntityAndDescendantsWithDataNode(childFragment, newDataNodeChild);
+ }
+ updatedChildFragments.add(childFragment);
+ }
+
+ existingFragmentEntity.getChildFragments().clear();
+ existingFragmentEntity.getChildFragments().addAll(updatedChildFragments);
}
@Override
@@ -338,11 +351,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
}
- private List<Long> getAnchorIdsForPagination(final DataspaceEntity dataspaceEntity, final CpsPathQuery cpsPathQuery,
- final PaginationOption paginationOption) {
- return fragmentRepository.findAnchorIdsForPagination(dataspaceEntity, cpsPathQuery, paginationOption);
- }
-
private List<DataNode> createDataNodesFromFragmentEntities(final FetchDescendantsOption fetchDescendantsOption,
final Collection<FragmentEntity> fragmentEntities) {
final List<DataNode> dataNodes = new ArrayList<>(fragmentEntities.size());
@@ -352,29 +360,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return Collections.unmodifiableList(dataNodes);
}
- private static String getNormalizedXpath(final String xpathSource) {
- if (isRootXpath(xpathSource)) {
- return xpathSource;
- }
- try {
- return CpsPathUtil.getNormalizedXpath(xpathSource);
- } catch (final PathParsingException pathParsingException) {
- throw new CpsPathException(pathParsingException.getMessage());
- }
- }
-
- private static Collection<String> getNormalizedXpaths(final Collection<String> xpaths) {
- final Collection<String> normalizedXpaths = new HashSet<>(xpaths.size());
- for (final String xpath : xpaths) {
- try {
- normalizedXpaths.add(getNormalizedXpath(xpath));
- } catch (final CpsPathException cpsPathException) {
- log.warn("Error parsing xpath \"{}\": {}", xpath, cpsPathException.getMessage());
- }
- }
- return normalizedXpaths;
- }
-
@Override
public String startSession() {
return sessionManager.startSession();
@@ -404,21 +389,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return anchorIdList.size();
}
- private static Set<String> processAncestorXpath(final Collection<FragmentEntity> fragmentEntities,
- final CpsPathQuery cpsPathQuery) {
- final Set<String> ancestorXpath = new HashSet<>();
- final Pattern pattern =
- 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()) {
- ancestorXpath.add(matcher.group(1));
- }
- }
- return ancestorXpath;
- }
-
private DataNode toDataNode(final FragmentEntity fragmentEntity,
final FetchDescendantsOption fetchDescendantsOption) {
final List<DataNode> childDataNodes = getChildDataNodes(fragmentEntity, fetchDescendantsOption);
@@ -434,103 +404,15 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
.withChildDataNodes(childDataNodes).build();
}
- private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
- final FetchDescendantsOption fetchDescendantsOption) {
- if (fetchDescendantsOption.hasNext()) {
- return fragmentEntity.getChildFragments().stream()
- .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption.next()))
- .collect(Collectors.toList());
- }
- return Collections.emptyList();
- }
-
- @Override
- public void batchUpdateDataLeaves(final String dataspaceName, final String anchorName,
- final Map<String, Map<String, Serializable>> updatedLeavesPerXPath) {
- final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
-
- final Collection<String> xpathsOfUpdatedLeaves = updatedLeavesPerXPath.keySet();
- final Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpathsOfUpdatedLeaves);
-
- for (final FragmentEntity fragmentEntity : fragmentEntities) {
- final Map<String, Serializable> updatedLeaves = updatedLeavesPerXPath.get(fragmentEntity.getXpath());
- final String mergedLeaves = mergeLeaves(updatedLeaves, fragmentEntity.getAttributes());
- fragmentEntity.setAttributes(mergedLeaves);
- }
-
- try {
- fragmentRepository.saveAll(fragmentEntities);
- } catch (final StaleStateException staleStateException) {
- retryUpdateDataNodesIndividually(anchorEntity, fragmentEntities);
- }
- }
-
- @Override
- public void updateDataNodesAndDescendants(final String dataspaceName, final String anchorName,
- final Collection<DataNode> updatedDataNodes) {
- final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
-
- final Map<String, DataNode> xpathToUpdatedDataNode = updatedDataNodes.stream()
- .collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
-
- final Collection<String> xpaths = xpathToUpdatedDataNode.keySet();
- Collection<FragmentEntity> existingFragmentEntities = getFragmentEntities(anchorEntity, xpaths);
- existingFragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(
- FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS, existingFragmentEntities);
-
- for (final FragmentEntity existingFragmentEntity : existingFragmentEntities) {
- final DataNode updatedDataNode = xpathToUpdatedDataNode.get(existingFragmentEntity.getXpath());
- updateFragmentEntityAndDescendantsWithDataNode(existingFragmentEntity, updatedDataNode);
- }
-
- try {
- fragmentRepository.saveAll(existingFragmentEntities);
- } catch (final StaleStateException staleStateException) {
- retryUpdateDataNodesIndividually(anchorEntity, existingFragmentEntities);
- }
- }
-
- private void retryUpdateDataNodesIndividually(final AnchorEntity anchorEntity,
- final Collection<FragmentEntity> fragmentEntities) {
- final Collection<String> failedXpaths = new HashSet<>();
- for (final FragmentEntity dataNodeFragment : fragmentEntities) {
- try {
- fragmentRepository.save(dataNodeFragment);
- } catch (final StaleStateException staleStateException) {
- failedXpaths.add(dataNodeFragment.getXpath());
- }
- }
- if (!failedXpaths.isEmpty()) {
- final String failedXpathsConcatenated = String.join(",", failedXpaths);
- throw new ConcurrencyException("Concurrent Transactions", String.format(
- "DataNodes : %s in Dataspace :'%s' with Anchor : '%s' are updated by another transaction.",
- failedXpathsConcatenated, anchorEntity.getDataspace().getName(), anchorEntity.getName()));
- }
+ private FragmentEntity toFragmentEntity(final AnchorEntity anchorEntity, final DataNode dataNode) {
+ return FragmentEntity.builder()
+ .anchor(anchorEntity)
+ .xpath(dataNode.getXpath())
+ .attributes(jsonObjectMapper.asJsonString(dataNode.getLeaves()))
+ .build();
}
- private void updateFragmentEntityAndDescendantsWithDataNode(final FragmentEntity existingFragmentEntity,
- final DataNode newDataNode) {
- copyAttributesFromNewDataNode(existingFragmentEntity, newDataNode);
-
- final Map<String, FragmentEntity> existingChildrenByXpath = existingFragmentEntity.getChildFragments().stream()
- .collect(Collectors.toMap(FragmentEntity::getXpath, childFragmentEntity -> childFragmentEntity));
-
- final Collection<FragmentEntity> updatedChildFragments = new HashSet<>();
- for (final DataNode newDataNodeChild : newDataNode.getChildDataNodes()) {
- final FragmentEntity childFragment;
- if (isNewDataNode(newDataNodeChild, existingChildrenByXpath)) {
- childFragment = convertToFragmentWithAllDescendants(existingFragmentEntity.getAnchor(),
- newDataNodeChild);
- } else {
- childFragment = existingChildrenByXpath.get(newDataNodeChild.getXpath());
- updateFragmentEntityAndDescendantsWithDataNode(childFragment, newDataNodeChild);
- }
- updatedChildFragments.add(childFragment);
- }
- existingFragmentEntity.getChildFragments().clear();
- existingFragmentEntity.getChildFragments().addAll(updatedChildFragments);
- }
@Override
@Transactional
@@ -636,6 +518,116 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
}
+ @Override
+ @Timed(value = "cps.data.persistence.service.datanode.get",
+ description = "Time taken to get a data node")
+ public Collection<DataNode> getDataNodes(final String dataspaceName, final String anchorName,
+ final String xpath,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ final String targetXpath = 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
+ @Timed(value = "cps.data.persistence.service.datanode.batch.get",
+ description = "Time taken to get data nodes")
+ public Collection<DataNode> getDataNodesForMultipleXpaths(final String dataspaceName, final String anchorName,
+ final Collection<String> xpaths,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ final AnchorEntity anchorEntity = getAnchorEntity(dataspaceName, anchorName);
+ Collection<FragmentEntity> fragmentEntities = getFragmentEntities(anchorEntity, xpaths);
+ fragmentEntities = fragmentRepository.prefetchDescendantsOfFragmentEntities(fetchDescendantsOption,
+ fragmentEntities);
+ return createDataNodesFromFragmentEntities(fetchDescendantsOption, fragmentEntities);
+ }
+
+ private List<DataNode> getChildDataNodes(final FragmentEntity fragmentEntity,
+ final FetchDescendantsOption fetchDescendantsOption) {
+ if (fetchDescendantsOption.hasNext()) {
+ return fragmentEntity.getChildFragments().stream()
+ .map(childFragmentEntity -> toDataNode(childFragmentEntity, fetchDescendantsOption.next()))
+ .collect(Collectors.toList());
+ }
+ return Collections.emptyList();
+ }
+
+ private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
+ final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
+ return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
+ }
+
+ private List<Long> getAnchorIdsForPagination(final DataspaceEntity dataspaceEntity, final CpsPathQuery cpsPathQuery,
+ final PaginationOption paginationOption) {
+ return fragmentRepository.findAnchorIdsForPagination(dataspaceEntity, cpsPathQuery, paginationOption);
+ }
+
+ private static String getNormalizedXpath(final String xpathSource) {
+ if (isRootXpath(xpathSource)) {
+ return xpathSource;
+ }
+ try {
+ return CpsPathUtil.getNormalizedXpath(xpathSource);
+ } catch (final PathParsingException pathParsingException) {
+ throw new CpsPathException(pathParsingException.getMessage());
+ }
+ }
+
+ private static Collection<String> getNormalizedXpaths(final Collection<String> xpaths) {
+ final Collection<String> normalizedXpaths = new HashSet<>(xpaths.size());
+ for (final String xpath : xpaths) {
+ try {
+ normalizedXpaths.add(getNormalizedXpath(xpath));
+ } catch (final CpsPathException cpsPathException) {
+ log.warn("Error parsing xpath \"{}\": {}", xpath, cpsPathException.getMessage());
+ }
+ }
+ return normalizedXpaths;
+ }
+
+ private FragmentEntity getFragmentEntity(final AnchorEntity anchorEntity, final String xpath) {
+ final FragmentEntity fragmentEntity;
+ if (isRootXpath(xpath)) {
+ fragmentEntity = fragmentRepository.findOneByAnchorId(anchorEntity.getId()).orElse(null);
+ } else {
+ fragmentEntity = fragmentRepository.getByAnchorAndXpath(anchorEntity, getNormalizedXpath(xpath));
+ }
+ if (fragmentEntity == null) {
+ throw new DataNodeNotFoundException(anchorEntity.getDataspace().getName(), anchorEntity.getName(), xpath);
+ }
+ return fragmentEntity;
+ }
+
+ private Collection<FragmentEntity> getFragmentEntities(final AnchorEntity anchorEntity,
+ final Collection<String> xpaths) {
+ final Collection<String> normalizedXpaths = getNormalizedXpaths(xpaths);
+
+ final boolean haveRootXpath = normalizedXpaths.removeIf(CpsDataPersistenceServiceImpl::isRootXpath);
+
+ final List<FragmentEntity> fragmentEntities = fragmentRepository.findByAnchorAndXpathIn(anchorEntity,
+ normalizedXpaths);
+
+ for (final FragmentEntity fragmentEntity : fragmentEntities) {
+ normalizedXpaths.remove(fragmentEntity.getXpath());
+ }
+
+ for (final String xpath : normalizedXpaths) {
+ if (!CpsPathUtil.isPathToListElement(xpath)) {
+ fragmentEntities.addAll(fragmentRepository.findListByAnchorAndXpath(anchorEntity, xpath));
+ }
+ }
+
+ if (haveRootXpath) {
+ fragmentEntities.addAll(fragmentRepository.findRootsByAnchorId(anchorEntity.getId()));
+ }
+
+ return fragmentEntities;
+ }
+
private static String getListElementXpathPrefix(final Collection<DataNode> newListElements) {
if (newListElements.isEmpty()) {
throw new CpsAdminException("Invalid list replacement",
@@ -660,20 +652,6 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return existingListElementEntity;
}
- private static boolean isNewDataNode(final DataNode replacementDataNode,
- final Map<String, FragmentEntity> existingListElementsByXpath) {
- return !existingListElementsByXpath.containsKey(replacementDataNode.getXpath());
- }
-
- private void copyAttributesFromNewDataNode(final FragmentEntity existingFragmentEntity,
- final DataNode newDataNode) {
- final String oldOrderedLeavesAsJson = getOrderedLeavesAsJson(existingFragmentEntity.getAttributes());
- final String newOrderedLeavesAsJson = getOrderedLeavesAsJson(newDataNode.getLeaves());
- if (!oldOrderedLeavesAsJson.equals(newOrderedLeavesAsJson)) {
- existingFragmentEntity.setAttributes(jsonObjectMapper.asJsonString(newDataNode.getLeaves()));
- }
- }
-
private String getOrderedLeavesAsJson(final Map<String, Serializable> currentLeaves) {
final Map<String, Serializable> sortedLeaves = new TreeMap<>(String::compareTo);
sortedLeaves.putAll(currentLeaves);
@@ -685,7 +663,7 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
return "{}";
}
final Map<String, Serializable> sortedLeaves = jsonObjectMapper.convertJsonString(currentLeavesAsString,
- TreeMap.class);
+ TreeMap.class);
return jsonObjectMapper.asJsonString(sortedLeaves);
}
@@ -696,10 +674,39 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
.collect(Collectors.toMap(FragmentEntity::getXpath, fragmentEntity -> fragmentEntity));
}
+ private static Set<String> processAncestorXpath(final Collection<FragmentEntity> fragmentEntities,
+ final CpsPathQuery cpsPathQuery) {
+ final Set<String> ancestorXpath = new HashSet<>();
+ final Pattern pattern =
+ 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()) {
+ ancestorXpath.add(matcher.group(1));
+ }
+ }
+ return ancestorXpath;
+ }
+
private static boolean isRootXpath(final String xpath) {
return "/".equals(xpath) || "".equals(xpath);
}
+ private static boolean isNewDataNode(final DataNode replacementDataNode,
+ final Map<String, FragmentEntity> existingListElementsByXpath) {
+ return !existingListElementsByXpath.containsKey(replacementDataNode.getXpath());
+ }
+
+ private void copyAttributesFromNewDataNode(final FragmentEntity existingFragmentEntity,
+ final DataNode newDataNode) {
+ final String oldOrderedLeavesAsJson = getOrderedLeavesAsJson(existingFragmentEntity.getAttributes());
+ final String newOrderedLeavesAsJson = getOrderedLeavesAsJson(newDataNode.getLeaves());
+ if (!oldOrderedLeavesAsJson.equals(newOrderedLeavesAsJson)) {
+ existingFragmentEntity.setAttributes(jsonObjectMapper.asJsonString(newDataNode.getLeaves()));
+ }
+ }
+
private String mergeLeaves(final Map<String, Serializable> updateLeaves, final String currentLeavesAsString) {
Map<String, Serializable> currentLeavesAsMap = new HashMap<>();
if (currentLeavesAsString != null) {
@@ -712,9 +719,4 @@ public class CpsDataPersistenceServiceImpl implements CpsDataPersistenceService
}
return jsonObjectMapper.asJsonString(currentLeavesAsMap);
}
-
- private AnchorEntity getAnchorEntity(final String dataspaceName, final String anchorName) {
- final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName);
- return anchorRepository.getByDataspaceAndName(dataspaceEntity, anchorName);
- }
}