2  *  ============LICENSE_START=======================================================
 
   3  *  Copyright (C) 2023 Nordix Foundation
 
   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.ncmp.api.impl.deprecated.subscriptions;
 
  23 import java.util.Collection;
 
  24 import java.util.HashMap;
 
  25 import java.util.List;
 
  27 import java.util.Optional;
 
  28 import java.util.stream.Collectors;
 
  29 import lombok.extern.slf4j.Slf4j;
 
  30 import org.onap.cps.api.CpsDataService;
 
  31 import org.onap.cps.api.CpsModuleService;
 
  32 import org.onap.cps.ncmp.api.impl.inventory.NcmpPersistenceImpl;
 
  33 import org.onap.cps.ncmp.api.impl.utils.DataNodeHelper;
 
  34 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelSubscriptionEvent;
 
  35 import org.onap.cps.spi.FetchDescendantsOption;
 
  36 import org.onap.cps.spi.model.DataNode;
 
  37 import org.onap.cps.spi.utils.CpsValidator;
 
  38 import org.onap.cps.utils.JsonObjectMapper;
 
  39 import org.springframework.stereotype.Component;
 
  43 public class SubscriptionPersistenceImpl extends NcmpPersistenceImpl implements SubscriptionPersistence {
 
  45     private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions";
 
  46     private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry";
 
  48     public SubscriptionPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
 
  49                                        final CpsModuleService cpsModuleService, final CpsValidator cpsValidator) {
 
  50         super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
 
  55     public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
 
  56         final String clientId = yangModelSubscriptionEvent.getClientId();
 
  57         final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName();
 
  59         final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME,
 
  60                 SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
 
  62         if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) {
 
  63             saveSubscriptionEventYangModel(createSubscriptionEventJsonData(
 
  64                     jsonObjectMapper.asJsonString(yangModelSubscriptionEvent)));
 
  66             findDeltaCmHandlesAddOrUpdateInDatabase(yangModelSubscriptionEvent, clientId, subscriptionName, dataNodes);
 
  70     private void findDeltaCmHandlesAddOrUpdateInDatabase(final YangModelSubscriptionEvent yangModelSubscriptionEvent,
 
  71                                                          final String clientId, final String subscriptionName,
 
  72                                                          final Collection<DataNode> dataNodes) {
 
  73         final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMapNew =
 
  74                 extractCmHandleFromYangModelAsMap(yangModelSubscriptionEvent);
 
  75         final Map<String, Map<String, String>> cmHandleIdToStatusAndDetailsAsMapOriginal =
 
  76                 DataNodeHelper.cmHandleIdToStatusAndDetailsAsMapFromDataNode(dataNodes);
 
  78         final Map<String, Map<String, String>> newTargetCmHandles = mapDifference(cmHandleIdToStatusAndDetailsAsMapNew,
 
  79                         cmHandleIdToStatusAndDetailsAsMapOriginal);
 
  80         traverseCmHandleList(newTargetCmHandles, clientId, subscriptionName, true);
 
  82         final Map<String, Map<String, String>> existingTargetCmHandles =
 
  83                 mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, newTargetCmHandles);
 
  84         traverseCmHandleList(existingTargetCmHandles, clientId, subscriptionName, false);
 
  87     private static Map<String, Map<String, String>> extractCmHandleFromYangModelAsMap(
 
  88             final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
 
  89         return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles()
 
  92                         (result, cmHandle) -> {
 
  93                             final String cmHandleId = cmHandle.getCmHandleId();
 
  94                             final SubscriptionStatus status = cmHandle.getStatus();
 
  95                             final String details = cmHandle.getDetails();
 
  97                             if (cmHandleId != null && status != null) {
 
  98                                 result.put(cmHandleId, new HashMap<>());
 
  99                                 result.get(cmHandleId).put("status", status.toString());
 
 100                                 result.get(cmHandleId).put("details", details == null ? "" : details);
 
 107     private void traverseCmHandleList(final Map<String, Map<String, String>> cmHandleMap,
 
 108                                       final String clientId,
 
 109                                       final String subscriptionName,
 
 110                                       final boolean isAddListElementOperation) {
 
 111         final List<YangModelSubscriptionEvent.TargetCmHandle> cmHandleList = targetCmHandlesAsList(cmHandleMap);
 
 112         for (final YangModelSubscriptionEvent.TargetCmHandle targetCmHandle : cmHandleList) {
 
 113             final String targetCmHandleAsJson =
 
 114                     createTargetCmHandleJsonData(jsonObjectMapper.asJsonString(targetCmHandle));
 
 115             addOrReplaceCmHandlePredicateListElement(targetCmHandleAsJson, clientId, subscriptionName,
 
 116                     isAddListElementOperation);
 
 120     private boolean isSubscriptionRegistryEmptyOrNonExist(final Collection<DataNode> dataNodes,
 
 121                                                           final String clientId, final String subscriptionName) {
 
 122         final Optional<DataNode> dataNodeFirst = dataNodes.stream().findFirst();
 
 123         return ((dataNodeFirst.isPresent() && dataNodeFirst.get().getChildDataNodes().isEmpty())
 
 124                 || getCmHandlesForSubscriptionEvent(clientId, subscriptionName).isEmpty());
 
 127     private void addOrReplaceCmHandlePredicateListElement(final String targetCmHandleAsJson,
 
 128                                                           final String clientId,
 
 129                                                           final String subscriptionName,
 
 130                                                           final boolean isAddListElementOperation) {
 
 131         if (isAddListElementOperation) {
 
 132             log.info("targetCmHandleAsJson to be added into DB {}", targetCmHandleAsJson);
 
 133             cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
 
 134                     createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP);
 
 136             log.info("targetCmHandleAsJson to be updated into DB {}", targetCmHandleAsJson);
 
 137             cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
 
 138                     createCmHandleXpathPredicates(clientId, subscriptionName), targetCmHandleAsJson, NO_TIMESTAMP);
 
 142     private void saveSubscriptionEventYangModel(final String subscriptionEventJsonData) {
 
 143         log.info("SubscriptionEventJsonData to be saved into DB {}", subscriptionEventJsonData);
 
 144         cpsDataService.saveListElements(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
 
 145                 SUBSCRIPTION_REGISTRY_PARENT, subscriptionEventJsonData, NO_TIMESTAMP);
 
 149     public Collection<DataNode> getDataNodesForSubscriptionEvent() {
 
 150         return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
 
 151                 SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
 
 155     public Collection<DataNode> getCmHandlesForSubscriptionEvent(final String clientId, final String subscriptionName) {
 
 156         return cpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
 
 157                 List.of(createCmHandleXpath(clientId, subscriptionName)),
 
 158                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
 
 161     private static List<YangModelSubscriptionEvent.TargetCmHandle> targetCmHandlesAsList(
 
 162             final Map<String, Map<String, String>> newCmHandles) {
 
 163         return newCmHandles.entrySet().stream().map(entry -> {
 
 164             final String cmHandleId = entry.getKey();
 
 165             final Map<String, String> statusAndDetailsMap = entry.getValue();
 
 166             final String status = statusAndDetailsMap.get("status");
 
 167             final String details = statusAndDetailsMap.get("details");
 
 168             return new YangModelSubscriptionEvent.TargetCmHandle(cmHandleId, SubscriptionStatus.fromString(status),
 
 170         }).collect(Collectors.toList());
 
 173     private static String createSubscriptionEventJsonData(final String yangModelSubscriptionAsJson) {
 
 174         return "{\"subscription\":[" + yangModelSubscriptionAsJson + "]}";
 
 177     private static String createTargetCmHandleJsonData(final String targetCmHandleAsJson) {
 
 178         return "{\"targetCmHandles\":[" + targetCmHandleAsJson + "]}";
 
 181     private static String createCmHandleXpathPredicates(final String clientId, final String subscriptionName) {
 
 182         return "/subscription-registry/subscription[@clientID='" + clientId
 
 183                 + "' and @subscriptionName='" + subscriptionName + "']/predicates";
 
 186     private static String createCmHandleXpath(final String clientId, final String subscriptionName) {
 
 187         return "/subscription-registry/subscription[@clientID='" + clientId
 
 188                 + "' and @subscriptionName='" + subscriptionName + "']";
 
 191     private static <K, L, M> Map<K, Map<L, M>> mapDifference(final Map<K, Map<L, M>> left,
 
 192                                                              final Map<K, Map<L, M>> right) {
 
 193         final Map<K, Map<L, M>> difference = new HashMap<>();
 
 194         difference.putAll(left);
 
 195         difference.putAll(right);
 
 196         difference.entrySet().removeAll(right.entrySet());