Add CSIT test for CPS Swagger UI
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / deprecated / subscriptions / SubscriptionPersistenceImpl.java
1 /*
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.api.impl.deprecated.subscriptions;
22
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
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;
40
41 @Slf4j
42 @Component
43 public class SubscriptionPersistenceImpl extends NcmpPersistenceImpl implements SubscriptionPersistence {
44
45     private static final String SUBSCRIPTION_ANCHOR_NAME = "AVC-Subscriptions";
46     private static final String SUBSCRIPTION_REGISTRY_PARENT = "/subscription-registry";
47
48     public SubscriptionPersistenceImpl(final JsonObjectMapper jsonObjectMapper, final CpsDataService cpsDataService,
49                                        final CpsModuleService cpsModuleService, final CpsValidator cpsValidator) {
50         super(jsonObjectMapper, cpsDataService, cpsModuleService, cpsValidator);
51     }
52
53
54     @Override
55     public void saveSubscriptionEvent(final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
56         final String clientId = yangModelSubscriptionEvent.getClientId();
57         final String subscriptionName = yangModelSubscriptionEvent.getSubscriptionName();
58
59         final Collection<DataNode> dataNodes = cpsDataService.getDataNodes(NCMP_DATASPACE_NAME,
60                 SUBSCRIPTION_ANCHOR_NAME, SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
61
62         if (isSubscriptionRegistryEmptyOrNonExist(dataNodes, clientId, subscriptionName)) {
63             saveSubscriptionEventYangModel(createSubscriptionEventJsonData(
64                     jsonObjectMapper.asJsonString(yangModelSubscriptionEvent)));
65         } else {
66             findDeltaCmHandlesAddOrUpdateInDatabase(yangModelSubscriptionEvent, clientId, subscriptionName, dataNodes);
67         }
68     }
69
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);
77
78         final Map<String, Map<String, String>> newTargetCmHandles = mapDifference(cmHandleIdToStatusAndDetailsAsMapNew,
79                         cmHandleIdToStatusAndDetailsAsMapOriginal);
80         traverseCmHandleList(newTargetCmHandles, clientId, subscriptionName, true);
81
82         final Map<String, Map<String, String>> existingTargetCmHandles =
83                 mapDifference(cmHandleIdToStatusAndDetailsAsMapNew, newTargetCmHandles);
84         traverseCmHandleList(existingTargetCmHandles, clientId, subscriptionName, false);
85     }
86
87     private static Map<String, Map<String, String>> extractCmHandleFromYangModelAsMap(
88             final YangModelSubscriptionEvent yangModelSubscriptionEvent) {
89         return yangModelSubscriptionEvent.getPredicates().getTargetCmHandles()
90                 .stream().collect(
91                         HashMap::new,
92                         (result, cmHandle) -> {
93                             final String cmHandleId = cmHandle.getCmHandleId();
94                             final SubscriptionStatus status = cmHandle.getStatus();
95                             final String details = cmHandle.getDetails();
96
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);
101                             }
102                         },
103                         HashMap::putAll
104                 );
105     }
106
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);
117         }
118     }
119
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());
125     }
126
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);
135         } else {
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);
139         }
140     }
141
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);
146     }
147
148     @Override
149     public Collection<DataNode> getDataNodesForSubscriptionEvent() {
150         return cpsDataService.getDataNodes(NCMP_DATASPACE_NAME, SUBSCRIPTION_ANCHOR_NAME,
151                 SUBSCRIPTION_REGISTRY_PARENT, FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
152     }
153
154     @Override
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);
159     }
160
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),
169                     details);
170         }).collect(Collectors.toList());
171     }
172
173     private static String createSubscriptionEventJsonData(final String yangModelSubscriptionAsJson) {
174         return "{\"subscription\":[" + yangModelSubscriptionAsJson + "]}";
175     }
176
177     private static String createTargetCmHandleJsonData(final String targetCmHandleAsJson) {
178         return "{\"targetCmHandles\":[" + targetCmHandleAsJson + "]}";
179     }
180
181     private static String createCmHandleXpathPredicates(final String clientId, final String subscriptionName) {
182         return "/subscription-registry/subscription[@clientID='" + clientId
183                 + "' and @subscriptionName='" + subscriptionName + "']/predicates";
184     }
185
186     private static String createCmHandleXpath(final String clientId, final String subscriptionName) {
187         return "/subscription-registry/subscription[@clientID='" + clientId
188                 + "' and @subscriptionName='" + subscriptionName + "']";
189     }
190
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());
197         return difference;
198     }
199 }