Code to persist or update the yang model subscription into db
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / subscriptions / SubscriptionPersistenceImpl.java
index 9a063d6..d2b1237 100644 (file)
@@ -22,11 +22,18 @@ package org.onap.cps.ncmp.api.impl.subscriptions;
 
 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
 
+import java.io.Serializable;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsDataService;
+import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
@@ -41,35 +48,86 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
     private static final String SUBSCRIPTION_DATASPACE_NAME = "NCMP-Admin";
     private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions";
     private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry";
-
     private final JsonObjectMapper jsonObjectMapper;
     private final CpsDataService cpsDataService;
 
     @Override
     public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
-        final String subscriptionEventJsonData =
-                createSubscriptionEventJsonData(jsonObjectMapper.asJsonString(yangModelSubscriptionEvent));
+        final String clientId = yangModelSubscriptionEvent.getClientId();
+        final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName();
+
         final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(SUBSCRIPTION_DATASPACE_NAME,
                 SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+
+        if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) {
+            saveSubscriptionEventYangModel(createSubscriptionEventJsonData(
+                    jsonObjectMapper.asJsonString(yangModelSubscriptionEvent)));
+        } else {
+            findDeltaCmHandlesAddOrUpdateInDatabase(yangModelSubscriptionEvent, clientId, subscriptionName, dataNodes);
+        }
+    }
+
+    private void findDeltaCmHandlesAddOrUpdateInDatabase(final YangModelSubscriptionEvent yangModelSubscriptionEvent,
+                                                         final String clientId, final String subscriptionName,
+                                                         final Collection<DataNode> dataNodes) {
+        final Map<String, SubscriptionStatus> cmHandleIdsFromYangModel =
+                extractCmHandleFromYangModelAsMap(yangModelSubscriptionEvent);
+        final Map<String, SubscriptionStatus> cmHandleIdsFromDatabase =
+                extractCmHandleFromDbAsMap(dataNodes);
+
+        final Map<String, SubscriptionStatus> newCmHandles =
+                mapDifference(cmHandleIdsFromYangModel, cmHandleIdsFromDatabase);
+        traverseCmHandleList(newCmHandles, clientId, subscriptionName, true);
+
+        final Map<String, SubscriptionStatus> existingCmHandles =
+                mapDifference(cmHandleIdsFromYangModel, newCmHandles);
+        traverseCmHandleList(existingCmHandles, clientId, subscriptionName, false);
+    }
+
+    private boolean isSubscriptionRegistryEmptyOrNonExist(final Collection<DataNode> dataNodes,
+                                                          final String clientId, final String subscriptionName) {
         final Optional<DataNode> dataNodeFirst = dataNodes.stream().findFirst();
-        final boolean isCreateOperation =
-                dataNodeFirst.isPresent() && dataNodeFirst.get().getChildDataNodes().isEmpty();
-        saveOrUpdateSubscriptionEventYangModel(subscriptionEventJsonData, isCreateOperation);
+        return ((dataNodeFirst.isPresent() && dataNodeFirst.get().getChildDataNodes().isEmpty())
+                || getCmHandlesForSubscriptionEvent(clientId, subscriptionName).isEmpty());
+    }
+
+    private void traverseCmHandleList(final Map<String, SubscriptionStatus> cmHandleMap,
+                                      final String clientId,
+                                      final String subscriptionName,
+                                      final boolean isAddListElementOperation) {
+        final List<YangModelSubscriptionEvent.TargetCmHandle> cmHandleList =
+                targetCmHandlesAsList(cmHandleMap);
+        for (final YangModelSubscriptionEvent.TargetCmHandle targetCmHandle : cmHandleList) {
+            final String targetCmHandleAsJson =
+                    createTargetCmHandleJsonData(jsonObjectMapper.asJsonString(targetCmHandle));
+            addOrReplaceCmHandlePredicateListElement(targetCmHandleAsJson, clientId, subscriptionName,
+                    isAddListElementOperation);
+        }
     }
 
-    private void saveOrUpdateSubscriptionEventYangModel(final String subscriptionEventJsonData,
-                                                        final boolean isCreateOperation) {
-        if (isCreateOperation) {
-            log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData);
-            cpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
-                    SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP);
+    private void addOrReplaceCmHandlePredicateListElement(final String targetCmHandleAsJson,
+                                                          final String clientId,
+                                                          final String subscriptionName,
+                                                          final boolean isAddListElementOperation) {
+        if (isAddListElementOperation) {
+            log.info("targetCmHandleAsJson to be added into DB {}", targetCmHandleAsJson);
+            cpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME,
+                    SUBSCRIPTION_ANCHOR_NAME, createCmHandleXpathPredicates(clientId, subscriptionName),
+                    targetCmHandleAsJson, NO_TIMESTAMP);
         } else {
-            log.info("SubscriptionEventJsonData to be updated into DB {}", subscriptionEventJsonData);
-            cpsDataService.updateDataNodeAndDescendants(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
-                    SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP);
+            log.info("targetCmHandleAsJson to be updated into DB {}", targetCmHandleAsJson);
+            cpsDataService.updateNodeLeaves(SUBSCRIPTION_DATASPACE_NAME,
+                    SUBSCRIPTION_ANCHOR_NAME, createCmHandleXpathPredicates(clientId, subscriptionName),
+                    targetCmHandleAsJson, NO_TIMESTAMP);
         }
     }
 
+    private void saveSubscriptionEventYangModel(final String subscriptionEventJsonData) {
+        log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData);
+        cpsDataService.saveListElements(SUBSCRIPTION_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
+                SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP);
+    }
+
     @Override
     public Collection<DataNode> getDataNodesForSubscriptionEvent() {
         return cpsDataService.getDataNodes(SUBSCRIPTION_DATASPACE_NAME,
@@ -77,7 +135,58 @@ public class SubscriptionPersistenceImpl implements SubscriptionPersistence {
                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
     }
 
+    @Override
+    public Collection<DataNode> getCmHandlesForSubscriptionEvent(final String clientId, final String subscriptionName) {
+        return cpsDataService.getDataNodesForMultipleXpaths(SUBSCRIPTION_DATASPACE_NAME,
+                SUBSCRIPTION_ANCHOR_NAME, Arrays.asList(createCmHandleXpath(clientId, subscriptionName)),
+                FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
+    }
+
+    private static Map<String, SubscriptionStatus> extractCmHandleFromDbAsMap(final Collection<DataNode> dataNodes) {
+        final List<Map<String, Serializable>> dataNodeLeaves = DataNodeHelper.getDataNodeLeaves(dataNodes);
+        final List<Collection<Serializable>> cmHandleIdToStatus = DataNodeHelper.getCmHandleIdToStatus(dataNodeLeaves);
+        return DataNodeHelper.getCmHandleIdToStatusMap(cmHandleIdToStatus);
+    }
+
+    private static Map<String, SubscriptionStatus> extractCmHandleFromYangModelAsMap(
+            final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
+        return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles()
+                .stream().collect(Collectors.toMap(
+                        YangModelSubscriptionEvent.TargetCmHandle::getCmHandleId,
+                        YangModelSubscriptionEvent.TargetCmHandle::getStatus));
+    }
+
+    private static List<YangModelSubscriptionEvent.TargetCmHandle> targetCmHandlesAsList(
+            final Map<String, SubscriptionStatus> newCmHandles) {
+        return newCmHandles.entrySet().stream().map(entry ->
+                new YangModelSubscriptionEvent.TargetCmHandle(entry.getKey(),
+                        entry.getValue())).collect(Collectors.toList());
+    }
+
     private static String createSubscriptionEventJsonData(final String yangModelSubscriptionAsJson) {
         return "{\"subscription\":[" + yangModelSubscriptionAsJson + "]}";
     }
+
+    private static String createTargetCmHandleJsonData(final String targetCmHandleAsJson) {
+        return "{\"targetCmHandles\":[" + targetCmHandleAsJson + "]}";
+    }
+
+    private static String createCmHandleXpathPredicates(final String clientId, final String subscriptionName) {
+        return "/subscription-registry/subscription[@clientID='" + clientId
+                + "' and @subscriptionName='" + subscriptionName + "']/predicates";
+    }
+
+    private static String createCmHandleXpath(final String clientId, final String subscriptionName) {
+        return "/subscription-registry/subscription[@clientID='" + clientId
+                + "' and @subscriptionName='" + subscriptionName + "']";
+    }
+
+    private static <K, V> Map<K, V> mapDifference(final Map<? extends K, ? extends V> left,
+                                                  final Map<? extends K, ? extends V> right) {
+        final Map<K, V> difference = new HashMap<>();
+        difference.putAll(left);
+        difference.putAll(right);
+        difference.entrySet().removeAll(right.entrySet());
+        return difference;
+    }
 }