From a317890387fdbc689f8dcd8648b5bfe3b43abd1e Mon Sep 17 00:00:00 2001 From: "rajesh.kumar" Date: Wed, 14 Dec 2022 14:27:29 +0000 Subject: Query data nodes across all anchors under one dataspace Issue-ID: CPS-1396 Change-ID: I73f97f986a817d423f93a8d922dcd9647b1412ab Signed-off-by: rajesh.kumar --- .../java/org/onap/cps/api/CpsQueryService.java | 12 ++++++++ .../org/onap/cps/api/impl/CpsQueryServiceImpl.java | 8 ++++++ .../onap/cps/spi/CpsDataPersistenceService.java | 13 +++++++++ .../org/onap/cps/spi/model/DataNodeBuilder.java | 15 +++++++++- .../main/java/org/onap/cps/utils/DataMapUtils.java | 15 ++++++++++ .../cps/api/impl/CpsQueryServiceImplSpec.groovy | 14 ++++++++++ .../org/onap/cps/utils/DataMapUtilsSpec.groovy | 32 ++++++++++++++++++++++ 7 files changed, 108 insertions(+), 1 deletion(-) (limited to 'cps-service') diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java index 68ae1ebf0..af54077fe 100644 --- a/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java +++ b/cps-service/src/main/java/org/onap/cps/api/CpsQueryService.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2020-2022 Nordix Foundation + * 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. @@ -42,4 +43,15 @@ public interface CpsQueryService { Collection queryDataNodes(String dataspaceName, String anchorName, String cpsPath, FetchDescendantsOption fetchDescendantsOption); + /** + * Get data nodes for the given dataspace across all anchors by cps path. + * + * @param dataspaceName dataspace name + * @param cpsPath CPS path + * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be + * included in the output + * @return a collection of data nodes + */ + Collection queryDataNodesAcrossAnchors(String dataspaceName, String cpsPath, + FetchDescendantsOption fetchDescendantsOption); } diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java index a63faabac..ac018c9e8 100644 --- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsQueryServiceImpl.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2021-2022 Nordix Foundation + * 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. @@ -45,4 +46,11 @@ public class CpsQueryServiceImpl implements CpsQueryService { cpsValidator.validateNameCharacters(dataspaceName, anchorName); return cpsDataPersistenceService.queryDataNodes(dataspaceName, anchorName, cpsPath, fetchDescendantsOption); } + + @Override + public Collection queryDataNodesAcrossAnchors(final String dataspaceName, + final String cpsPath, final FetchDescendantsOption fetchDescendantsOption) { + cpsValidator.validateNameCharacters(dataspaceName); + return cpsDataPersistenceService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath, fetchDescendantsOption); + } } 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 f10443fda..540401913 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 @@ -223,6 +223,19 @@ public interface CpsDataPersistenceService { List queryDataNodes(String dataspaceName, String anchorName, String cpsPath, FetchDescendantsOption fetchDescendantsOption); + /** + * Get a datanode by dataspace name and cps path across all anchors. + * + * @param dataspaceName dataspace name + * @param cpsPath cps path + * @param fetchDescendantsOption defines whether the descendants of the node(s) found by the query should be + * included in the output + * @return the data nodes found i.e. 0 or more data nodes + */ + List queryDataNodesAcrossAnchors(String dataspaceName, + String cpsPath, FetchDescendantsOption fetchDescendantsOption); + + /** * Starts a session which allows use of locks and batch interaction with the persistence service. * diff --git a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java index b23cdfc8d..6fc36ebb6 100644 --- a/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java +++ b/cps-service/src/main/java/org/onap/cps/spi/model/DataNodeBuilder.java @@ -3,7 +3,7 @@ * Copyright (C) 2021 Bell Canada. All rights reserved. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 Nordix Foundation. - * 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. @@ -54,6 +54,7 @@ public class DataNodeBuilder { private String parentNodeXpath = ""; private Map leaves = Collections.emptyMap(); private Collection childDataNodes = Collections.emptySet(); + private String anchorName; /** * To use parent node xpath for creating {@link DataNode}. @@ -88,6 +89,17 @@ public class DataNodeBuilder { return this; } + /** + * To use anchor name for creating {@link DataNode}. + * + * @param anchorName anchor name for the data node + * @return DataNodeBuilder + */ + public DataNodeBuilder withAnchor(final String anchorName) { + this.anchorName = anchorName; + return this; + } + /** * To use module name for prefix for creating {@link DataNode}. * @@ -153,6 +165,7 @@ public class DataNodeBuilder { dataNode.setModuleNamePrefix(moduleNamePrefix); dataNode.setLeaves(leaves); dataNode.setChildDataNodes(childDataNodes); + dataNode.setAnchorName(anchorName); return dataNode; } diff --git a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java index 14641e05e..b0e109baf 100644 --- a/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java +++ b/cps-service/src/main/java/org/onap/cps/utils/DataMapUtils.java @@ -3,6 +3,7 @@ * Copyright (C) 2021 Pantheon.tech * Modifications (C) 2021-2022 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada + * 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. @@ -48,6 +49,20 @@ public class DataMapUtils { return ImmutableMap.builder().put(nodeIdentifierWithPrefix, toDataMap(dataNode)).build(); } + /** + * Converts DataNode structure into a map including the root node identifier for a JSON response. + * + * @param dataNode data node object + * @return a map representing same data with the root node identifier + */ + public static Map toDataMapWithIdentifierAndAnchor(final DataNode dataNode, final String prefix) { + final String nodeIdentifierWithPrefix = getNodeIdentifierWithPrefix(dataNode.getXpath(), prefix); + final Map dataMap = ImmutableMap.builder() + .put(nodeIdentifierWithPrefix, toDataMap(dataNode)).build(); + return ImmutableMap.builder().put("anchorName", dataNode.getAnchorName()) + .put("dataNode", dataMap).build(); + } + /** * Converts DataNode structure into a map for a JSON response. * diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy index 56c43d163..553027a4b 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsQueryServiceImplSpec.groovy @@ -48,4 +48,18 @@ class CpsQueryServiceImplSpec extends Specification { FetchDescendantsOption.DIRECT_CHILDREN_ONLY, new FetchDescendantsOption(10)] } + def 'Query data nodes across all anchors by cps path with #fetchDescendantsOption.'() { + given: 'a dataspace name, an anchor name and a cps path' + def dataspaceName = 'some-dataspace' + def cpsPath = '/cps-path' + when: 'queryDataNodes is invoked' + objectUnderTest.queryDataNodesAcrossAnchors(dataspaceName, cpsPath, fetchDescendantsOption) + then: 'the persistence service is called once with the correct parameters' + 1 * mockCpsDataPersistenceService.queryDataNodesAcrossAnchors(dataspaceName, cpsPath, fetchDescendantsOption) + and: 'the CpsValidator is called on the dataspaceName, schemaSetName and anchorName' + 1 * mockCpsValidator.validateNameCharacters(dataspaceName) + where: 'all fetch descendants options are supported' + fetchDescendantsOption << [FetchDescendantsOption.OMIT_DESCENDANTS, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS] + } + } diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy index 84dddeb60..e27b43763 100644 --- a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy @@ -3,6 +3,7 @@ * Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2020-2022 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada. + * Modifications Copyright (C) 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. @@ -37,10 +38,23 @@ class DataMapUtilsSpec extends Specification { ), ]) + def dataNodeWithAnchor = buildDataNodeWithAnchor( + "/parent", 'anchor01',[parentLeaf:'parentLeafValue', parentLeafList:['parentLeafListEntry1','parentLeafListEntry2']],[ + buildDataNode('/parent/child-list[@id=1/2]',[listElementLeaf:'listElement1leafValue'],noChildren), + buildDataNode('/parent/child-list[@id=2]',[listElementLeaf:'listElement2leafValue'],noChildren), + buildDataNode('/parent/child-object',[childLeaf:'childLeafValue'], + [buildDataNode('/parent/child-object/grand-child-object',[grandChildLeaf:'grandChildLeafValue'],noChildren)] + ), + ]) + static def buildDataNode(xpath, leaves, children) { return new DataNodeBuilder().withXpath(xpath).withLeaves(leaves).withChildDataNodes(children).build() } + static def buildDataNodeWithAnchor(xpath, anchorName, leaves, children) { + return new DataNodeBuilder().withXpath(xpath).withAnchor(anchorName).withLeaves(leaves).withChildDataNodes(children).build() + } + def 'Data node structure conversion to map.'() { when: 'data node structure is converted to a map' def result = DataMapUtils.toDataMap(dataNode) @@ -90,5 +104,23 @@ class DataMapUtilsSpec extends Specification { 'xpath contains list attributes with /' | '/bookstore/categories[@code=1/2]' | 'sampleModuleName:categories' } + + def 'Data node structure with anchor name conversion to map with root node identifier.'() { + when: 'data node structure is converted to a map with root node identifier' + def result = DataMapUtils.toDataMapWithIdentifierAndAnchor(dataNodeWithAnchor, dataNodeWithAnchor.moduleNamePrefix) + then: 'root node leaves are populated under its node identifier' + def parentNode = result.get("dataNode").parent + parentNode.parentLeaf == 'parentLeafValue' + parentNode.parentLeafList == ['parentLeafListEntry1','parentLeafListEntry2'] + + and: 'leaves for child element is populated under its node identifier' + assert parentNode.'child-object'.childLeaf == 'childLeafValue' + + and: 'leaves for grandchild element is populated under its node identifier' + assert parentNode.'child-object'.'grand-child-object'.grandChildLeaf == 'grandChildLeafValue' + + and: 'data node is associated with anchor name' + assert result.get('anchorName') == 'anchor01' + } } -- cgit 1.2.3-korg