2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2023 TechMahindra Ltd.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.cps.api.impl;
24 import java.io.Serializable;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Collections;
28 import java.util.LinkedHashMap;
29 import java.util.List;
31 import java.util.Objects;
32 import lombok.extern.slf4j.Slf4j;
33 import org.onap.cps.api.CpsDeltaService;
34 import org.onap.cps.spi.model.DataNode;
35 import org.onap.cps.spi.model.DeltaReport;
36 import org.onap.cps.spi.model.DeltaReportBuilder;
37 import org.springframework.stereotype.Service;
41 public class CpsDeltaServiceImpl implements CpsDeltaService {
44 public List<DeltaReport> getDeltaReports(final Collection<DataNode> sourceDataNodes,
45 final Collection<DataNode> targetDataNodes) {
47 final List<DeltaReport> deltaReport = new ArrayList<>();
49 final Map<String, DataNode> xpathToSourceDataNodes = convertToXPathToDataNodesMap(sourceDataNodes);
50 final Map<String, DataNode> xpathToTargetDataNodes = convertToXPathToDataNodesMap(targetDataNodes);
52 deltaReport.addAll(getRemovedAndUpdatedDeltaReports(xpathToSourceDataNodes, xpathToTargetDataNodes));
54 deltaReport.addAll(getAddedDeltaReports(xpathToSourceDataNodes, xpathToTargetDataNodes));
56 return Collections.unmodifiableList(deltaReport);
59 private static Map<String, DataNode> convertToXPathToDataNodesMap(
60 final Collection<DataNode> dataNodes) {
61 final Map<String, DataNode> xpathToDataNode = new LinkedHashMap<>();
62 for (final DataNode dataNode : dataNodes) {
63 xpathToDataNode.put(dataNode.getXpath(), dataNode);
64 final Collection<DataNode> childDataNodes = dataNode.getChildDataNodes();
65 if (!childDataNodes.isEmpty()) {
66 xpathToDataNode.putAll(convertToXPathToDataNodesMap(childDataNodes));
69 return xpathToDataNode;
72 private static List<DeltaReport> getRemovedAndUpdatedDeltaReports(
73 final Map<String, DataNode> xpathToSourceDataNodes,
74 final Map<String, DataNode> xpathToTargetDataNodes) {
75 final List<DeltaReport> removedAndUpdatedDeltaReportEntries = new ArrayList<>();
76 for (final Map.Entry<String, DataNode> entry: xpathToSourceDataNodes.entrySet()) {
77 final String xpath = entry.getKey();
78 final DataNode sourceDataNode = entry.getValue();
79 final DataNode targetDataNode = xpathToTargetDataNodes.get(xpath);
80 final List<DeltaReport> deltaReports;
81 if (targetDataNode == null) {
82 deltaReports = getRemovedDeltaReports(xpath, sourceDataNode);
84 deltaReports = getUpdatedDeltaReports(xpath, sourceDataNode, targetDataNode);
86 removedAndUpdatedDeltaReportEntries.addAll(deltaReports);
88 return removedAndUpdatedDeltaReportEntries;
91 private static List<DeltaReport> getRemovedDeltaReports(final String xpath, final DataNode sourceDataNode) {
92 final List<DeltaReport> removedDeltaReportEntries = new ArrayList<>();
93 final Map<String, Serializable> sourceDataNodeLeaves = sourceDataNode.getLeaves();
94 final DeltaReport removedDeltaReportEntry = new DeltaReportBuilder().actionRemove().withXpath(xpath)
95 .withSourceData(sourceDataNodeLeaves).build();
96 removedDeltaReportEntries.add(removedDeltaReportEntry);
97 return removedDeltaReportEntries;
100 private static List<DeltaReport> getUpdatedDeltaReports(final String xpath, final DataNode sourceDataNode,
101 final DataNode targetDataNode) {
102 final List<DeltaReport> updatedDeltaReportEntries = new ArrayList<>();
103 final Map<Map<String, Serializable>, Map<String, Serializable>> updatedLeavesAsSourceDataToTargetData =
104 getUpdatedLeavesBetweenSourceAndTargetDataNode(sourceDataNode.getLeaves(), targetDataNode.getLeaves());
105 addUpdatedLeavesToDeltaReport(xpath, updatedLeavesAsSourceDataToTargetData, updatedDeltaReportEntries);
106 return updatedDeltaReportEntries;
109 private static Map<Map<String, Serializable>,
110 Map<String, Serializable>> getUpdatedLeavesBetweenSourceAndTargetDataNode(
111 final Map<String, Serializable> leavesOfSourceDataNode,
112 final Map<String, Serializable> leavesOfTargetDataNode) {
113 final Map<Map<String, Serializable>, Map<String, Serializable>> updatedLeavesAsSourceDataToTargetData =
114 new LinkedHashMap<>();
115 final Map<String, Serializable> sourceDataInDeltaReport = new LinkedHashMap<>();
116 final Map<String, Serializable> targetDataInDeltaReport = new LinkedHashMap<>();
117 processLeavesPresentInSourceAndTargetDataNode(leavesOfSourceDataNode, leavesOfTargetDataNode,
118 sourceDataInDeltaReport, targetDataInDeltaReport);
119 processLeavesUniqueInTargetDataNode(leavesOfSourceDataNode, leavesOfTargetDataNode,
120 sourceDataInDeltaReport, targetDataInDeltaReport);
121 final boolean isUpdatedDataInDeltaReport =
122 !sourceDataInDeltaReport.isEmpty() || !targetDataInDeltaReport.isEmpty();
123 if (isUpdatedDataInDeltaReport) {
124 updatedLeavesAsSourceDataToTargetData.put(sourceDataInDeltaReport, targetDataInDeltaReport);
126 return updatedLeavesAsSourceDataToTargetData;
129 private static void processLeavesPresentInSourceAndTargetDataNode(
130 final Map<String, Serializable> leavesOfSourceDataNode,
131 final Map<String, Serializable> leavesOfTargetDataNode,
132 final Map<String, Serializable> sourceDataInDeltaReport,
133 final Map<String, Serializable> targetDataInDeltaReport) {
134 for (final Map.Entry<String, Serializable> entry: leavesOfSourceDataNode.entrySet()) {
135 final String key = entry.getKey();
136 final Serializable sourceLeaf = entry.getValue();
137 final Serializable targetLeaf = leavesOfTargetDataNode.get(key);
138 compareLeaves(key, sourceLeaf, targetLeaf, sourceDataInDeltaReport, targetDataInDeltaReport);
142 private static void processLeavesUniqueInTargetDataNode(
143 final Map<String, Serializable> leavesOfSourceDataNode,
144 final Map<String, Serializable> leavesOfTargetDataNode,
145 final Map<String, Serializable> sourceDataInDeltaReport,
146 final Map<String, Serializable> targetDataInDeltaReport) {
147 final Map<String, Serializable> uniqueLeavesOfTargetDataNode =
148 new LinkedHashMap<>(leavesOfTargetDataNode);
149 uniqueLeavesOfTargetDataNode.keySet().removeAll(leavesOfSourceDataNode.keySet());
150 for (final Map.Entry<String, Serializable> entry: uniqueLeavesOfTargetDataNode.entrySet()) {
151 final String key = entry.getKey();
152 final Serializable targetLeaf = entry.getValue();
153 final Serializable sourceLeaf = leavesOfSourceDataNode.get(key);
154 compareLeaves(key, sourceLeaf, targetLeaf, sourceDataInDeltaReport, targetDataInDeltaReport);
158 private static void compareLeaves(final String key,
159 final Serializable sourceLeaf,
160 final Serializable targetLeaf,
161 final Map<String, Serializable> sourceDataInDeltaReport,
162 final Map<String, Serializable> targetDataInDeltaReport) {
163 if (sourceLeaf != null && targetLeaf != null) {
164 if (!Objects.equals(sourceLeaf, targetLeaf)) {
165 sourceDataInDeltaReport.put(key, sourceLeaf);
166 targetDataInDeltaReport.put(key, targetLeaf);
168 } else if (sourceLeaf == null) {
169 targetDataInDeltaReport.put(key, targetLeaf);
172 sourceDataInDeltaReport.put(key, sourceLeaf);
176 private static void addUpdatedLeavesToDeltaReport(final String xpath,
177 final Map<Map<String, Serializable>, Map<String,
178 Serializable>> updatedLeavesAsSourceDataToTargetData,
179 final List<DeltaReport> updatedDeltaReportEntries) {
180 for (final Map.Entry<Map<String, Serializable>, Map<String, Serializable>> entry:
181 updatedLeavesAsSourceDataToTargetData.entrySet()) {
182 final DeltaReport updatedDataForDeltaReport = new DeltaReportBuilder().actionUpdate()
183 .withXpath(xpath).withSourceData(entry.getKey()).withTargetData(entry.getValue()).build();
184 updatedDeltaReportEntries.add(updatedDataForDeltaReport);
189 private static List<DeltaReport> getAddedDeltaReports(final Map<String, DataNode> xpathToSourceDataNodes,
190 final Map<String, DataNode> xpathToTargetDataNodes) {
192 final List<DeltaReport> addedDeltaReportEntries = new ArrayList<>();
193 final Map<String, DataNode> xpathToAddedNodes = new LinkedHashMap<>(xpathToTargetDataNodes);
194 xpathToAddedNodes.keySet().removeAll(xpathToSourceDataNodes.keySet());
195 for (final Map.Entry<String, DataNode> entry: xpathToAddedNodes.entrySet()) {
196 final String xpath = entry.getKey();
197 final DataNode dataNode = entry.getValue();
198 final DeltaReport addedDataForDeltaReport = new DeltaReportBuilder().actionAdd().withXpath(xpath)
199 .withTargetData(dataNode.getLeaves()).build();
200 addedDeltaReportEntries.add(addedDataForDeltaReport);
202 return addedDeltaReportEntries;