Merge "patch operation for ncmp running"
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / NetworkCmProxyDataServiceImpl.java
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 highstreet technologies GmbH
4  *  Modifications Copyright (C) 2021-2022 Nordix Foundation
5  *  Modifications Copyright (C) 2021 Pantheon.tech
6  *  Modifications Copyright (C) 2021 Bell Canada
7  *  ================================================================================
8  *  Licensed under the Apache License, Version 2.0 (the "License");
9  *  you may not use this file except in compliance with the License.
10  *  You may obtain a copy of the License at
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *  Unless required by applicable law or agreed to in writing, software
15  *  distributed under the License is distributed on an "AS IS" BASIS,
16  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *  See the License for the specific language governing permissions and
18  *  limitations under the License.
19  *
20  *  SPDX-License-Identifier: Apache-2.0
21  *  ============LICENSE_END=========================================================
22  */
23
24 package org.onap.cps.ncmp.api.impl;
25
26 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
27 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
28
29 import com.fasterxml.jackson.core.JsonProcessingException;
30 import com.fasterxml.jackson.databind.ObjectMapper;
31 import java.time.OffsetDateTime;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import lombok.extern.slf4j.Slf4j;
38 import org.onap.cps.api.CpsAdminService;
39 import org.onap.cps.api.CpsDataService;
40 import org.onap.cps.api.CpsModuleService;
41 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
42 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
43 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
44 import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
45 import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
46 import org.onap.cps.ncmp.api.models.CmHandle;
47 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
48 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
49 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
50 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
51 import org.onap.cps.spi.exceptions.DataValidationException;
52 import org.onap.cps.spi.model.ModuleReference;
53 import org.springframework.http.ResponseEntity;
54 import org.springframework.stereotype.Service;
55
56 @Slf4j
57 @Service
58 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
59
60     private static final String NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME = "NFP-Operational";
61
62     private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
63
64     private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
65
66     private static final OffsetDateTime NO_TIMESTAMP = null;
67
68     private CpsDataService cpsDataService;
69
70     private ObjectMapper objectMapper;
71
72     private DmiDataOperations dmiDataOperations;
73
74     private DmiModelOperations dmiModelOperations;
75
76     private CpsModuleService cpsModuleService;
77
78     private CpsAdminService cpsAdminService;
79
80     /**
81      * Constructor Injection for Dependencies.
82      * @param dmiDataOperations DMI operation
83      * @param cpsDataService Data Service Interface
84      * @param objectMapper Object Mapper
85      */
86     public NetworkCmProxyDataServiceImpl(final DmiDataOperations dmiDataOperations,
87                                          final DmiModelOperations dmiModelOperations,
88                                          final CpsModuleService cpsModuleService,
89                                          final CpsDataService cpsDataService,
90                                          final CpsAdminService cpsAdminService,
91                                          final ObjectMapper objectMapper) {
92         this.dmiDataOperations = dmiDataOperations;
93         this.dmiModelOperations = dmiModelOperations;
94         this.cpsModuleService = cpsModuleService;
95         this.cpsDataService = cpsDataService;
96         this.cpsAdminService = cpsAdminService;
97         this.objectMapper = objectMapper;
98     }
99
100     @Override
101     public void updateDmiRegistrationAndSyncModule(final DmiPluginRegistration dmiPluginRegistration) {
102         dmiPluginRegistration.validateDmiPluginRegistration();
103         try {
104             if (dmiPluginRegistration.getCreatedCmHandles() != null) {
105                 parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration);
106             }
107             if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
108                 parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
109             }
110             if (dmiPluginRegistration.getRemovedCmHandles() != null) {
111                 parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration);
112             }
113         } catch (final JsonProcessingException e) {
114             handleJsonProcessingException(dmiPluginRegistration, e);
115         }
116     }
117
118     @Override
119     public Object getResourceDataOperationalForCmHandle(final String cmHandle,
120                                                         final String resourceIdentifier,
121                                                         final String acceptParamInHeader,
122                                                         final String optionsParamInQuery) {
123         return handleResponse(dmiDataOperations.getResourceDataFromDmi(
124             cmHandle,
125             resourceIdentifier,
126             optionsParamInQuery,
127             acceptParamInHeader,
128             DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL), "Not able to get resource data.");
129     }
130
131     @Override
132     public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandle,
133                                                                final String resourceIdentifier,
134                                                                final String acceptParamInHeader,
135                                                                final String optionsParamInQuery) {
136         return handleResponse(dmiDataOperations.getResourceDataFromDmi(
137             cmHandle,
138             resourceIdentifier,
139             optionsParamInQuery,
140             acceptParamInHeader,
141             DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING), "Not able to get resource data.");
142     }
143
144     @Override
145     public Object writeResourceDataPassThroughRunningForCmHandle(final String cmHandle,
146                                                                final String resourceIdentifier,
147                                                                final OperationEnum operation,
148                                                                final String requestData,
149                                                                final String dataType) {
150         return handleResponse(
151             dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(
152                 cmHandle, resourceIdentifier, operation, requestData, dataType),
153             "Not able to " + operation + " resource data.");
154     }
155
156
157     @Override
158     public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandle) {
159         return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle);
160     }
161
162     /**
163      * Retrieve cm handle identifiers for the given list of module names.
164      *
165      * @param moduleNames module names.
166      * @return a collection of anchor identifiers
167      */
168     @Override
169     public Collection<String> executeCmHandleHasAllModulesSearch(final Collection<String> moduleNames) {
170         return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
171     }
172
173     /**
174      * THis method registers a cm handle and intiates modules sync.
175      *
176      * @param dmiPluginRegistration dmi plugin registration information.
177      * @throws JsonProcessingException thrown if json is malformed or missing.
178      */
179     public void parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
180         final DmiPluginRegistration dmiPluginRegistration) throws JsonProcessingException {
181         final PersistenceCmHandlesList createdPersistenceCmHandlesList =
182             getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getCreatedCmHandles());
183         registerAndSyncNewCmHandles(createdPersistenceCmHandlesList);
184     }
185
186     private static Object handleResponse(final ResponseEntity<?> responseEntity,
187                                          final String exceptionMessage) {
188         if (responseEntity.getStatusCode().is2xxSuccessful()) {
189             return responseEntity.getBody();
190         } else {
191             throw new NcmpException(exceptionMessage,
192                     "DMI status code: " + responseEntity.getStatusCodeValue()
193                             + ", DMI response body: " + responseEntity.getBody());
194         }
195     }
196
197     private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration)
198         throws JsonProcessingException {
199         final PersistenceCmHandlesList updatedPersistenceCmHandlesList =
200             getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getUpdatedCmHandles());
201         final String cmHandlesAsJson = objectMapper.writeValueAsString(updatedPersistenceCmHandlesList);
202         cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
203                 "/dmi-registry", cmHandlesAsJson, NO_TIMESTAMP);
204     }
205
206     private PersistenceCmHandlesList getUpdatedPersistenceCmHandlesList(
207         final DmiPluginRegistration dmiPluginRegistration,
208         final List<CmHandle> updatedCmHandles) {
209         return PersistenceCmHandlesList.toPersistenceCmHandlesList(
210             dmiPluginRegistration.getDmiPlugin(),
211             dmiPluginRegistration.getDmiDataPlugin(),
212             dmiPluginRegistration.getDmiModelPlugin(),
213             updatedCmHandles);
214     }
215
216     private static void handleJsonProcessingException(final DmiPluginRegistration dmiPluginRegistration,
217                                                       final JsonProcessingException e) {
218         final String message = "Parsing error occurred while processing DMI Plugin Registration"
219             + dmiPluginRegistration;
220         log.error(message);
221         throw new DataValidationException(message, e.getMessage(), e);
222     }
223
224     private void registerAndSyncNewCmHandles(final PersistenceCmHandlesList persistenceCmHandlesList)
225         throws JsonProcessingException  {
226         final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
227         cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
228             cmHandleJsonData, NO_TIMESTAMP);
229
230         for (final PersistenceCmHandle persistenceCmHandle : persistenceCmHandlesList.getPersistenceCmHandles()) {
231             syncModulesAndCreateAnchor(persistenceCmHandle);
232         }
233     }
234
235     protected void syncModulesAndCreateAnchor(final PersistenceCmHandle persistenceCmHandle) {
236         syncAndCreateSchemaSet(persistenceCmHandle);
237         createAnchor(persistenceCmHandle);
238     }
239
240     private void parseAndRemoveCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
241         for (final String cmHandle : dmiPluginRegistration.getRemovedCmHandles()) {
242             try {
243                 attemptToDeleteSchemaSetWithCascade(cmHandle);
244                 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
245                     "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
246             } catch (final DataNodeNotFoundException e) {
247                 log.warn("Datanode {} not deleted message {}", cmHandle, e.getMessage());
248             }
249         }
250     }
251
252     private void attemptToDeleteSchemaSetWithCascade(final String schemaSetName) {
253         try {
254             cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
255                 CASCADE_DELETE_ALLOWED);
256         } catch (final Exception e) {
257             log.warn("Schema set {} delete failed, reason {}", schemaSetName, e.getMessage());
258         }
259     }
260
261     private void syncAndCreateSchemaSet(final PersistenceCmHandle persistenceCmHandle) {
262         final List<ModuleReference> moduleReferencesFromCmHandle =
263             dmiModelOperations.getModuleReferences(persistenceCmHandle);
264         final List<ModuleReference> existingModuleReferences = new ArrayList<>();
265         final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
266         prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
267
268         final Map<String, String> newYangResourcesModuleNameToContentMap;
269         if (unknownModuleReferences.isEmpty()) {
270             newYangResourcesModuleNameToContentMap = new HashMap<>();
271         } else {
272             newYangResourcesModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle,
273                 unknownModuleReferences);
274         }
275         cpsModuleService
276             .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
277                 newYangResourcesModuleNameToContentMap, existingModuleReferences);
278     }
279
280     private void prepareModuleSubsets(final List<ModuleReference> moduleReferencesFromCmHandle,
281                                       final List<ModuleReference> existingModuleReferences,
282                                       final List<ModuleReference> unknownModuleReferences) {
283
284         final Collection<ModuleReference> knownModuleReferencesInCps =
285             cpsModuleService.getYangResourceModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME);
286
287         for (final ModuleReference moduleReferenceFromDmiForCmHandle : moduleReferencesFromCmHandle) {
288             if (knownModuleReferencesInCps.contains(moduleReferenceFromDmiForCmHandle)) {
289                 existingModuleReferences.add(moduleReferenceFromDmiForCmHandle);
290             } else {
291                 unknownModuleReferences.add(moduleReferenceFromDmiForCmHandle);
292             }
293         }
294     }
295
296     private void createAnchor(final PersistenceCmHandle persistenceCmHandle) {
297         cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
298             persistenceCmHandle.getId());
299     }
300
301
302
303 }