From b0e78acb6aefdcb5866955802099e6091b2a6952 Mon Sep 17 00:00:00 2001 From: Ruslan Kashapov Date: Fri, 14 May 2021 12:04:34 +0300 Subject: Replace list-node content (part 1): CPS Service and persistence layers Issue-ID: CPS-362 Change-Id: I669c9fc6ef67c1992fe95e17a765f0c616b00f7e Signed-off-by: Ruslan Kashapov --- .../main/java/org/onap/cps/api/CpsDataService.java | 14 +++++++++++ .../org/onap/cps/api/impl/CpsDataServiceImpl.java | 18 ++++++++++---- .../onap/cps/spi/CpsDataPersistenceService.java | 11 +++++++++ .../cps/api/impl/CpsDataServiceImplSpec.groovy | 28 ++++++++++++++++++++++ 4 files changed, 67 insertions(+), 4 deletions(-) (limited to 'cps-service/src') diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java index 8e59ebcbb..3b50c5144 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsDataService.java @@ -105,4 +105,18 @@ public interface CpsDataService { */ void replaceNodeTree(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull String parentNodeXpath, @NonNull String jsonData); + + /** + * Replaces (if exists) child data fragment representing list-node (with one or more elements) + * under existing data node for the given anchor and dataspace. + * + * @param dataspaceName dataspace name + * @param anchorName anchor name + * @param parentNodeXpath parent node xpath + * @param jsonData json data representing list element + * @throws DataValidationException when json data is invalid (incl. list-node being empty) + * @throws DataNodeNotFoundException when parent node cannot be found by parent node xpath + */ + void replaceListNodeData(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull String parentNodeXpath, + @NonNull String jsonData); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java index 523657a7f..23bf4f2ee 100755 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsDataServiceImpl.java @@ -71,9 +71,6 @@ public class CpsDataServiceImpl implements CpsDataService { final String parentNodeXpath, final String jsonData) { final Collection dataNodesCollection = buildDataNodeCollectionFromJson(dataspaceName, anchorName, parentNodeXpath, jsonData); - if (dataNodesCollection.isEmpty()) { - throw new DataValidationException("Invalid list data.", "List node is empty."); - } cpsDataPersistenceService.addListDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodesCollection); } @@ -98,6 +95,14 @@ public class CpsDataServiceImpl implements CpsDataService { cpsDataPersistenceService.replaceDataNodeTree(dataspaceName, anchorName, dataNode); } + @Override + public void replaceListNodeData(final String dataspaceName, final String anchorName, final String parentNodeXpath, + final String jsonData) { + final Collection dataNodes = + buildDataNodeCollectionFromJson(dataspaceName, anchorName, parentNodeXpath, jsonData); + cpsDataPersistenceService.replaceListDataNodes(dataspaceName, anchorName, parentNodeXpath, dataNodes); + } + private DataNode buildDataNodeFromJson(final String dataspaceName, final String anchorName, final String parentNodeXpath, final String jsonData) { @@ -123,10 +128,15 @@ public class CpsDataServiceImpl implements CpsDataService { final var schemaContext = getSchemaContext(dataspaceName, anchor.getSchemaSetName()); final NormalizedNode normalizedNode = YangUtils.parseJsonData(jsonData, schemaContext, parentNodeXpath); - return new DataNodeBuilder() + final Collection dataNodes = new DataNodeBuilder() .withParentNodeXpath(parentNodeXpath) .withNormalizedNodeTree(normalizedNode) .buildCollection(); + if (dataNodes.isEmpty()) { + throw new DataValidationException("Invalid list data.", "List node is empty."); + } + return dataNodes; + } private SchemaContext getSchemaContext(final String dataspaceName, final String schemaSetName) { diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java index 0ed3bf005..3b16b0d81 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsDataPersistenceService.java @@ -100,6 +100,17 @@ public interface CpsDataPersistenceService { */ void replaceDataNodeTree(@NonNull String dataspaceName, @NonNull String anchorName, @NonNull DataNode dataNode); + /** + * Replaces existing list data node content including descendants. + * + * @param dataspaceName dataspace name + * @param anchorName anchor name + * @param parentNodeXpath parent node xpath + * @param dataNodes collection of data nodes representing list node elements + */ + void replaceListDataNodes(@NonNull String dataspaceName, @NonNull String anchorName, + @NonNull String parentNodeXpath, @NonNull Collection dataNodes); + /** * Get a datanode by cps path. * diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy index 5f930a152..27a5a4e0c 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsDataServiceImplSpec.groovy @@ -139,6 +139,34 @@ class CpsDataServiceImplSpec extends Specification { 'level 2 node' | '/test-tree' | '{"branch": [{"name":"Name"}]}' || '/test-tree/branch[@name=\'Name\']' } + def 'Replace list-node data fragment under existing node.'() { + given: 'schema set for given anchor and dataspace references test-tree model' + setupSchemaSetMocks('test-tree.yang') + when: 'replace list data method is invoked with list-node json data' + def jsonData = '{"branch": [{"name": "A"}, {"name": "B"}]}' + objectUnderTest.replaceListNodeData(dataspaceName, anchorName, '/test-tree', jsonData) + then: 'the persistence service method is invoked with correct parameters' + 1 * mockCpsDataPersistenceService.replaceListDataNodes(dataspaceName, anchorName, '/test-tree', + { dataNodeCollection -> + { + assert dataNodeCollection.size() == 2 + assert dataNodeCollection.collect { it.getXpath() } + .containsAll(['/test-tree/branch[@name=\'A\']', '/test-tree/branch[@name=\'B\']']) + } + } + ) + } + + def 'Replace with empty list-node data fragment.'() { + given: 'schema set for given anchor and dataspace references test-tree model' + setupSchemaSetMocks('test-tree.yang') + when: 'replace list data method is invoked with empty list-node data fragment' + def jsonData = '{"branch": []}' + objectUnderTest.replaceListNodeData(dataspaceName, anchorName, '/test-tree', jsonData) + then: 'invalid data exception is thrown' + thrown(DataValidationException) + } + def setupSchemaSetMocks(String... yangResources) { def anchor = Anchor.builder().name(anchorName).schemaSetName(schemaSetName).build() mockCpsAdminService.getAnchor(dataspaceName, anchorName) >> anchor -- cgit 1.2.3-korg