Part 3: Refactor CPS Delta code to utility class 24/141424/10
authorArpit Singh <AS00745003@techmahindra.com>
Thu, 3 Jul 2025 06:33:08 +0000 (12:03 +0530)
committerArpit Singh <AS00745003@techmahindra.com>
Mon, 21 Jul 2025 13:19:12 +0000 (18:49 +0530)
- Condensed Delta Report format refactored to a utils class

Issue-ID:CPS-2838
Change-Id: I0ffaf26701f9ab297ca66c5bd1c52dfeefff077e
Signed-off-by: Arpit Singh <AS00745003@techmahindra.com>
cps-service/src/main/java/org/onap/cps/impl/CpsDeltaServiceImpl.java
cps-service/src/main/java/org/onap/cps/utils/deltareport/GroupedDeltaReportGenerator.java [new file with mode: 0644]
cps-service/src/test/groovy/org/onap/cps/impl/CpsDeltaServiceImplSpec.groovy

index 8ca49a3..9dcc9cd 100644 (file)
@@ -23,13 +23,11 @@ package org.onap.cps.impl;
 import static org.onap.cps.utils.ContentType.JSON;
 
 import io.micrometer.core.annotation.Timed;
-import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsAnchorService;
@@ -40,12 +38,10 @@ import org.onap.cps.api.model.Anchor;
 import org.onap.cps.api.model.DataNode;
 import org.onap.cps.api.model.DeltaReport;
 import org.onap.cps.api.parameters.FetchDescendantsOption;
-import org.onap.cps.cpspath.parser.CpsPathUtil;
-import org.onap.cps.utils.DataMapUtils;
 import org.onap.cps.utils.DataMapper;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.onap.cps.utils.deltareport.DeltaReportGenerator;
-import org.onap.cps.utils.deltareport.DeltaReportHelper;
+import org.onap.cps.utils.deltareport.GroupedDeltaReportGenerator;
 import org.springframework.stereotype.Service;
 
 @Slf4j
@@ -58,8 +54,8 @@ public class CpsDeltaServiceImpl implements CpsDeltaService {
     private final DataNodeFactory dataNodeFactory;
     private final DataMapper dataMapper;
     private final JsonObjectMapper jsonObjectMapper;
-    private final DeltaReportHelper deltaReportHelper;
     private final DeltaReportGenerator deltaReportGenerator;
+    private final GroupedDeltaReportGenerator groupedDeltaReportGenerator;
 
     @Override
     @Timed(value = "cps.delta.service.get.delta",
@@ -105,7 +101,8 @@ public class CpsDeltaServiceImpl implements CpsDeltaService {
 
         final List<DeltaReport> deltaReport = new ArrayList<>();
         if (groupDataNodes) {
-            deltaReport.addAll(getCondensedDeltaReports(sourceDataNodes, targetDataNodes));
+            deltaReport
+                .addAll(groupedDeltaReportGenerator.createCondensedDeltaReports(sourceDataNodes, targetDataNodes));
         } else {
             deltaReport.addAll(deltaReportGenerator.createDeltaReports(sourceDataNodes, targetDataNodes));
         }
@@ -137,91 +134,4 @@ public class CpsDeltaServiceImpl implements CpsDeltaService {
                 .createDataNodesWithYangResourceXpathAndNodeData(yangResourceContentPerName, xpath, targetData, JSON);
         }
     }
-
-    private List<DeltaReport> getCondensedDeltaReports(final Collection<DataNode> sourceDataNodes,
-                                                              final Collection<DataNode> targetDataNodes) {
-
-        final List<DeltaReport> deltaReportEntries = new ArrayList<>();
-        final Map<String, DataNode> xpathToTargetDataNodes = flattenToXpathToFirstLevelDataNodeMap(targetDataNodes);
-        deltaReportEntries.addAll(getCondensedRemovedDeltaReports(sourceDataNodes, xpathToTargetDataNodes));
-        deltaReportEntries.addAll(getCondensedUpdatedDeltaReports(sourceDataNodes, xpathToTargetDataNodes));
-        deltaReportEntries.addAll(getCondensedAddedDeltaReports(sourceDataNodes, targetDataNodes));
-        return deltaReportEntries;
-    }
-
-    private static List<DeltaReport> getCondensedRemovedDeltaReports(final Collection<DataNode> sourceDataNodes,
-                                                                   final Map<String, DataNode> xpathToTargetDataNodes) {
-
-        final List<DeltaReport> deltaReportEntriesForRemove = new ArrayList<>();
-        final Collection<DataNode> removedDataNodes =
-            getDataNodesForDeltaReport(sourceDataNodes, xpathToTargetDataNodes);
-        if (!removedDataNodes.isEmpty()) {
-            final String xpath = getXpathForDeltaReport(removedDataNodes);
-            deltaReportEntriesForRemove.add(new DeltaReportBuilder().actionRemove().withXpath(xpath)
-                .withSourceData(getCondensedDataForDeltaReport(removedDataNodes)).build());
-        }
-        return deltaReportEntriesForRemove;
-    }
-
-    private List<DeltaReport> getCondensedUpdatedDeltaReports(final Collection<DataNode> sourceDataNodes,
-                                                                   final Map<String, DataNode> xpathToTargetDataNodes) {
-        final List<DeltaReport> deltaReportEntriesForUpdates = new ArrayList<>();
-        for (final DataNode sourceDataNode : sourceDataNodes) {
-            final String xpath = sourceDataNode.getXpath();
-            if (xpathToTargetDataNodes.containsKey(xpath)) {
-                final DataNode targetDataNode = xpathToTargetDataNodes.get(xpath);
-                final List<DeltaReport> updatedDataForDeltaReport =
-                        deltaReportHelper.createDeltaReportsForUpdates(xpath, sourceDataNode, targetDataNode);
-                deltaReportEntriesForUpdates.addAll(updatedDataForDeltaReport);
-                getCondensedDeltaReportsForChildDataNodes(sourceDataNode, targetDataNode, deltaReportEntriesForUpdates);
-            }
-        }
-        return deltaReportEntriesForUpdates;
-    }
-
-    private void getCondensedDeltaReportsForChildDataNodes(final DataNode sourceDataNode,
-                                                                  final DataNode targetDataNode,
-                                                                  final List<DeltaReport> deltaReportEntries) {
-        final Collection<DataNode> childrenOfSourceDataNodes = sourceDataNode.getChildDataNodes();
-        final Collection<DataNode> childrenOfTargetDataNodes = targetDataNode.getChildDataNodes();
-        if (!childrenOfSourceDataNodes.isEmpty() || !childrenOfTargetDataNodes.isEmpty()) {
-            deltaReportEntries.addAll(getCondensedDeltaReports(childrenOfSourceDataNodes, childrenOfTargetDataNodes));
-        }
-    }
-
-    private static List<DeltaReport> getCondensedAddedDeltaReports(final Collection<DataNode> sourceDataNodes,
-            final Collection<DataNode> targetDataNodes) {
-
-        final List<DeltaReport> addedDeltaReportEntries = new ArrayList<>();
-        final Collection<DataNode> addedDataNodes =
-                getDataNodesForDeltaReport(targetDataNodes, flattenToXpathToFirstLevelDataNodeMap(sourceDataNodes));
-        if (!addedDataNodes.isEmpty()) {
-            final String xpath = getXpathForDeltaReport(addedDataNodes);
-            addedDeltaReportEntries.add(new DeltaReportBuilder().actionCreate().withXpath(xpath)
-                .withTargetData(getCondensedDataForDeltaReport(addedDataNodes)).build());
-        }
-        return addedDeltaReportEntries;
-    }
-
-    private static String getXpathForDeltaReport(final Collection<DataNode> dataNodes) {
-        final String firstNodeXpath = dataNodes.iterator().next().getXpath();
-        final String parentNodeXpath = CpsPathUtil.getNormalizedParentXpath(firstNodeXpath);
-        return parentNodeXpath.isEmpty() ? firstNodeXpath : parentNodeXpath;
-    }
-
-    private static Collection<DataNode> getDataNodesForDeltaReport(final Collection<DataNode> dataNodes,
-                                                                   final Map<String, DataNode> xpathToDataNodes) {
-        return dataNodes.stream().filter(dataNode -> !xpathToDataNodes.containsKey(dataNode.getXpath())).toList();
-    }
-
-    private static Map<String, Serializable> getCondensedDataForDeltaReport(final Collection<DataNode> dataNodes) {
-        final DataNode containerNode = new DataNodeBuilder().withChildDataNodes(dataNodes).build();
-        final Map<String, Object> condensedData = DataMapUtils.toDataMap(containerNode);
-        return condensedData.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
-            entry -> (Serializable) entry.getValue()));
-    }
-
-    private static Map<String, DataNode> flattenToXpathToFirstLevelDataNodeMap(final Collection<DataNode> dataNodes) {
-        return dataNodes.stream().collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
-    }
 }
diff --git a/cps-service/src/main/java/org/onap/cps/utils/deltareport/GroupedDeltaReportGenerator.java b/cps-service/src/main/java/org/onap/cps/utils/deltareport/GroupedDeltaReportGenerator.java
new file mode 100644 (file)
index 0000000..d0ab418
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2025 TechMahindra Ltd.
+ *  ================================================================================
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.utils.deltareport;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.onap.cps.api.model.DataNode;
+import org.onap.cps.api.model.DeltaReport;
+import org.onap.cps.cpspath.parser.CpsPathUtil;
+import org.onap.cps.impl.DataNodeBuilder;
+import org.onap.cps.impl.DeltaReportBuilder;
+import org.onap.cps.utils.DataMapUtils;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class GroupedDeltaReportGenerator {
+
+    private final DeltaReportHelper deltaReportHelper;
+
+    /**
+     * Get condensed delta reports for the given source and target data nodes.
+     *
+     * @param sourceDataNodes the source data nodes
+     * @param targetDataNodes the target data nodes
+     * @return                a list of condensed delta reports
+     */
+    public List<DeltaReport> createCondensedDeltaReports(final Collection<DataNode> sourceDataNodes,
+                                                         final Collection<DataNode> targetDataNodes) {
+
+        final List<DeltaReport> deltaReportEntries = new ArrayList<>();
+        final Map<String, DataNode> xpathToTargetDataNodes = flattenToXpathToFirstLevelDataNodeMap(targetDataNodes);
+        deltaReportEntries.addAll(getCondensedRemovedDeltaReports(sourceDataNodes, xpathToTargetDataNodes));
+        deltaReportEntries.addAll(getCondensedUpdatedDeltaReports(sourceDataNodes, xpathToTargetDataNodes));
+        deltaReportEntries.addAll(getCondensedAddedDeltaReports(sourceDataNodes, targetDataNodes));
+        return deltaReportEntries;
+    }
+
+    private static List<DeltaReport> getCondensedRemovedDeltaReports(final Collection<DataNode> sourceDataNodes,
+                                                                   final Map<String, DataNode> xpathToTargetDataNodes) {
+
+        final List<DeltaReport> deltaReportEntriesForRemove = new ArrayList<>();
+        final Collection<DataNode> removedDataNodes =
+            getDataNodesForDeltaReport(sourceDataNodes, xpathToTargetDataNodes);
+        if (!removedDataNodes.isEmpty()) {
+            final String xpath = getXpathForDeltaReport(removedDataNodes);
+            deltaReportEntriesForRemove.add(new DeltaReportBuilder().actionRemove().withXpath(xpath)
+                .withSourceData(getCondensedDataForDeltaReport(removedDataNodes)).build());
+        }
+        return deltaReportEntriesForRemove;
+    }
+
+    private List<DeltaReport> getCondensedUpdatedDeltaReports(final Collection<DataNode> sourceDataNodes,
+                                                              final Map<String, DataNode> xpathToTargetDataNodes) {
+        final List<DeltaReport> deltaReportEntriesForUpdates = new ArrayList<>();
+        for (final DataNode sourceDataNode : sourceDataNodes) {
+            final String xpath = sourceDataNode.getXpath();
+            if (xpathToTargetDataNodes.containsKey(xpath)) {
+                final DataNode targetDataNode = xpathToTargetDataNodes.get(xpath);
+                final List<DeltaReport> updatedDataForDeltaReport =
+                    deltaReportHelper.createDeltaReportsForUpdates(xpath, sourceDataNode, targetDataNode);
+                deltaReportEntriesForUpdates.addAll(updatedDataForDeltaReport);
+                getCondensedDeltaReportsForChildDataNodes(sourceDataNode, targetDataNode, deltaReportEntriesForUpdates);
+            }
+        }
+        return deltaReportEntriesForUpdates;
+    }
+
+    private void getCondensedDeltaReportsForChildDataNodes(final DataNode sourceDataNode,
+                                                           final DataNode targetDataNode,
+                                                           final List<DeltaReport> deltaReportEntries) {
+        final Collection<DataNode> childrenOfSourceDataNodes = sourceDataNode.getChildDataNodes();
+        final Collection<DataNode> childrenOfTargetDataNodes = targetDataNode.getChildDataNodes();
+        if (!childrenOfSourceDataNodes.isEmpty() || !childrenOfTargetDataNodes.isEmpty()) {
+            deltaReportEntries
+                .addAll(createCondensedDeltaReports(childrenOfSourceDataNodes, childrenOfTargetDataNodes));
+        }
+    }
+
+    private static List<DeltaReport> getCondensedAddedDeltaReports(final Collection<DataNode> sourceDataNodes,
+                                                                   final Collection<DataNode> targetDataNodes) {
+
+        final List<DeltaReport> addedDeltaReportEntries = new ArrayList<>();
+        final Collection<DataNode> addedDataNodes =
+            getDataNodesForDeltaReport(targetDataNodes, flattenToXpathToFirstLevelDataNodeMap(sourceDataNodes));
+        if (!addedDataNodes.isEmpty()) {
+            final String xpath = getXpathForDeltaReport(addedDataNodes);
+            addedDeltaReportEntries.add(new DeltaReportBuilder().actionCreate().withXpath(xpath)
+                .withTargetData(getCondensedDataForDeltaReport(addedDataNodes)).build());
+        }
+        return addedDeltaReportEntries;
+    }
+
+    private static String getXpathForDeltaReport(final Collection<DataNode> dataNodes) {
+        final String firstNodeXpath = dataNodes.iterator().next().getXpath();
+        final String parentNodeXpath = CpsPathUtil.getNormalizedParentXpath(firstNodeXpath);
+        return parentNodeXpath.isEmpty() ? firstNodeXpath : parentNodeXpath;
+    }
+
+    private static Collection<DataNode> getDataNodesForDeltaReport(final Collection<DataNode> dataNodes,
+                                                                   final Map<String, DataNode> xpathToDataNodes) {
+        return dataNodes.stream().filter(dataNode -> !xpathToDataNodes.containsKey(dataNode.getXpath())).toList();
+    }
+
+    private static Map<String, Serializable> getCondensedDataForDeltaReport(final Collection<DataNode> dataNodes) {
+        final DataNode containerNode = new DataNodeBuilder().withChildDataNodes(dataNodes).build();
+        final Map<String, Object> condensedData = DataMapUtils.toDataMap(containerNode);
+        return condensedData.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
+            entry -> (Serializable) entry.getValue()));
+    }
+
+    private static Map<String, DataNode> flattenToXpathToFirstLevelDataNodeMap(final Collection<DataNode> dataNodes) {
+        return dataNodes.stream().collect(Collectors.toMap(DataNode::getXpath, dataNode -> dataNode));
+    }
+}
index dc48ec9..089c19e 100644 (file)
@@ -38,6 +38,7 @@ import org.onap.cps.utils.YangParser
 import org.onap.cps.utils.YangParserHelper
 import org.onap.cps.utils.deltareport.DeltaReportGenerator
 import org.onap.cps.utils.deltareport.DeltaReportHelper
+import org.onap.cps.utils.deltareport.GroupedDeltaReportGenerator
 import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder
 import org.onap.cps.yang.YangTextSchemaSourceSet
 import org.onap.cps.yang.YangTextSchemaSourceSetBuilder
@@ -62,7 +63,8 @@ class CpsDeltaServiceImplSpec extends Specification {
     def jsonObjectMapper = new JsonObjectMapper(new ObjectMapper())
     def deltaReportHelper = new DeltaReportHelper()
     def deltaReportGenerator = new DeltaReportGenerator(deltaReportHelper)
-    def objectUnderTest = new CpsDeltaServiceImpl(mockCpsAnchorService, mockCpsDataService, dataNodeFactory, dataMapper, jsonObjectMapper, deltaReportHelper, deltaReportGenerator)
+    def groupedDeltaReportGenerator = new GroupedDeltaReportGenerator(deltaReportHelper)
+    def objectUnderTest = new CpsDeltaServiceImpl(mockCpsAnchorService, mockCpsDataService, dataNodeFactory, dataMapper, jsonObjectMapper, deltaReportGenerator, groupedDeltaReportGenerator)
 
     static def bookstoreDataNodeWithParentXpath = [new DataNode(xpath: '/bookstore', leaves: ['bookstore-name': 'Easons'])]
     static def bookstoreDataNodeWithChildXpath = [new DataNode(xpath: '/bookstore/categories[@code=\'02\']', leaves: ['code': '02', 'name': 'Kids'])]