Async: NCMP Rest impl. including Request ID generation
[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-2022 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.constants.DmiRegistryConstants.NCMP_DATASPACE_NAME;
27 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_ANCHOR;
28 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_PARENT;
29 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME;
30 import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NO_TIMESTAMP;
31 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
32 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
33
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.HashMap;
37 import java.util.LinkedHashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.stream.Collectors;
41 import lombok.RequiredArgsConstructor;
42 import lombok.extern.slf4j.Slf4j;
43 import org.onap.cps.api.CpsAdminService;
44 import org.onap.cps.api.CpsDataService;
45 import org.onap.cps.api.CpsModuleService;
46 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
47 import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException;
48 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
49 import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
50 import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
51 import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever;
52 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
53 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse;
54 import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError;
55 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
56 import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse;
57 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
58 import org.onap.cps.spi.exceptions.AlreadyDefinedException;
59 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
60 import org.onap.cps.spi.exceptions.DataValidationException;
61 import org.onap.cps.spi.exceptions.SchemaSetNotFoundException;
62 import org.onap.cps.spi.model.ModuleReference;
63 import org.onap.cps.utils.CpsValidator;
64 import org.onap.cps.utils.JsonObjectMapper;
65 import org.springframework.http.ResponseEntity;
66 import org.springframework.stereotype.Service;
67
68 @Slf4j
69 @Service
70 @RequiredArgsConstructor
71 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
72
73     private final CpsDataService cpsDataService;
74
75     private final JsonObjectMapper jsonObjectMapper;
76
77     private final DmiDataOperations dmiDataOperations;
78
79     private final DmiModelOperations dmiModelOperations;
80
81     private final CpsModuleService cpsModuleService;
82
83     private final CpsAdminService cpsAdminService;
84
85     private final NetworkCmProxyDataServicePropertyHandler networkCmProxyDataServicePropertyHandler;
86
87     private final YangModelCmHandleRetriever yangModelCmHandleRetriever;
88
89     @Override
90     public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
91         final DmiPluginRegistration dmiPluginRegistration) {
92         dmiPluginRegistration.validateDmiPluginRegistration();
93         final var dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse();
94         dmiPluginRegistrationResponse.setRemovedCmHandles(
95             parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles()));
96         if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) {
97             dmiPluginRegistrationResponse.setCreatedCmHandles(
98                 parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration));
99         }
100         if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) {
101             dmiPluginRegistrationResponse.setUpdatedCmHandles(
102                 networkCmProxyDataServicePropertyHandler
103                     .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles()));
104         }
105         return dmiPluginRegistrationResponse;
106     }
107
108     @Override
109     public Object getResourceDataOperationalForCmHandle(final String cmHandleId,
110                                                         final String resourceIdentifier,
111                                                         final String optionsParamInQuery,
112                                                         final String topicParamInQuery,
113                                                         final String requestId) {
114         CpsValidator.validateNameCharacters(cmHandleId);
115         return getResourceDataResponse(cmHandleId, resourceIdentifier,
116                 DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL, optionsParamInQuery, topicParamInQuery, requestId);
117     }
118
119     @Override
120     public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandleId,
121                                                                final String resourceIdentifier,
122                                                                final String optionsParamInQuery,
123                                                                final String topicParamInQuery,
124                                                                final String requestId) {
125         CpsValidator.validateNameCharacters(cmHandleId);
126         return getResourceDataResponse(cmHandleId, resourceIdentifier,
127                 DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING, optionsParamInQuery, topicParamInQuery, requestId);
128     }
129
130     @Override
131     public Object writeResourceDataPassThroughRunningForCmHandle(final String cmHandleId,
132                                                                final String resourceIdentifier,
133                                                                final OperationEnum operation,
134                                                                final String requestData,
135                                                                final String dataType) {
136         CpsValidator.validateNameCharacters(cmHandleId);
137         return handleResponse(
138                 dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier, operation,
139                         requestData, dataType), operation);
140     }
141
142
143     @Override
144     public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
145         CpsValidator.validateNameCharacters(cmHandleId);
146         return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
147     }
148
149     /**
150      * Retrieve cm handle identifiers for the given list of module names.
151      *
152      * @param moduleNames module names.
153      * @return a collection of anchor identifiers
154      */
155     @Override
156     public Collection<String> executeCmHandleHasAllModulesSearch(final Collection<String> moduleNames) {
157         return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
158     }
159
160     /**
161      * Retrieve cm handle details for a given cm handle.
162      *
163      * @param cmHandleId cm handle identifier
164      * @return cm handle details
165      */
166     @Override
167     public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) {
168         CpsValidator.validateNameCharacters(cmHandleId);
169         final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle();
170         final YangModelCmHandle yangModelCmHandle =
171             yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId);
172         final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties();
173         final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties();
174         ncmpServiceCmHandle.setCmHandleID(yangModelCmHandle.getId());
175         setDmiProperties(dmiProperties, ncmpServiceCmHandle);
176         setPublicProperties(publicProperties, ncmpServiceCmHandle);
177         return ncmpServiceCmHandle;
178     }
179
180     private void setDmiProperties(final List<YangModelCmHandle.Property> dmiProperties,
181                                   final NcmpServiceCmHandle ncmpServiceCmHandle) {
182         final Map<String, String> dmiPropertiesMap = new LinkedHashMap<>(dmiProperties.size());
183         asPropertiesMap(dmiProperties, dmiPropertiesMap);
184         ncmpServiceCmHandle.setDmiProperties(dmiPropertiesMap);
185     }
186
187     private void setPublicProperties(final List<YangModelCmHandle.Property> publicProperties,
188                                      final NcmpServiceCmHandle ncmpServiceCmHandle) {
189         final Map<String, String> publicPropertiesMap = new LinkedHashMap<>();
190         asPropertiesMap(publicProperties, publicPropertiesMap);
191         ncmpServiceCmHandle.setPublicProperties(publicPropertiesMap);
192     }
193
194     private void asPropertiesMap(final List<YangModelCmHandle.Property> properties,
195                                  final Map<String, String> propertiesMap) {
196         for (final YangModelCmHandle.Property property: properties) {
197             propertiesMap.put(property.getName(), property.getValue());
198         }
199     }
200
201     /**
202      * THis method registers a cm handle and initiates modules sync.
203      *
204      * @param dmiPluginRegistration dmi plugin registration information.
205      * @return cm-handle registration response for create cm-handle requests.
206      */
207     public List<CmHandleRegistrationResponse> parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
208         final DmiPluginRegistration dmiPluginRegistration) {
209         return dmiPluginRegistration.getCreatedCmHandles().stream()
210             .map(cmHandle ->
211                 YangModelCmHandle.toYangModelCmHandle(
212                     dmiPluginRegistration.getDmiPlugin(),
213                     dmiPluginRegistration.getDmiDataPlugin(),
214                     dmiPluginRegistration.getDmiModelPlugin(), cmHandle)
215             )
216             .map(this::registerAndSyncNewCmHandle)
217             .collect(Collectors.toList());
218     }
219
220     private static Object handleResponse(final ResponseEntity<?> responseEntity, final OperationEnum operation) {
221         if (responseEntity.getStatusCode().is2xxSuccessful()) {
222             return responseEntity.getBody();
223         } else {
224             final String exceptionMessage = "Unable to " + operation.toString() + " resource data.";
225             throw new HttpClientRequestException(exceptionMessage, (String) responseEntity.getBody(),
226                     responseEntity.getStatusCodeValue());
227         }
228     }
229
230     private CmHandleRegistrationResponse registerAndSyncNewCmHandle(final YangModelCmHandle yangModelCmHandle) {
231         try {
232             CpsValidator.validateNameCharacters(yangModelCmHandle.getId());
233             final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}",
234                 jsonObjectMapper.asJsonString(yangModelCmHandle));
235             cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
236                 cmHandleJsonData, NO_TIMESTAMP);
237             syncModulesAndCreateAnchor(yangModelCmHandle);
238             return CmHandleRegistrationResponse.createSuccessResponse(yangModelCmHandle.getId());
239         } catch (final AlreadyDefinedException alreadyDefinedException) {
240             return CmHandleRegistrationResponse.createFailureResponse(
241                 yangModelCmHandle.getId(), RegistrationError.CM_HANDLE_ALREADY_EXIST);
242         } catch (final DataValidationException dataValidationException) {
243             return CmHandleRegistrationResponse.createFailureResponse(yangModelCmHandle.getId(),
244                 RegistrationError.CM_HANDLE_INVALID_ID);
245         } catch (final Exception exception) {
246             return CmHandleRegistrationResponse.createFailureResponse(yangModelCmHandle.getId(), exception);
247         }
248     }
249
250     protected void syncModulesAndCreateAnchor(final YangModelCmHandle yangModelCmHandle) {
251         syncAndCreateSchemaSet(yangModelCmHandle);
252         createAnchor(yangModelCmHandle);
253     }
254
255     protected List<CmHandleRegistrationResponse> parseAndRemoveCmHandlesInDmiRegistration(
256         final List<String> tobeRemovedCmHandles) {
257         final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses =
258             new ArrayList<>(tobeRemovedCmHandles.size());
259         for (final String cmHandle : tobeRemovedCmHandles) {
260             try {
261                 CpsValidator.validateNameCharacters(cmHandle);
262                 deleteSchemaSetWithCascade(cmHandle);
263                 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
264                     "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
265                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandle));
266             } catch (final DataNodeNotFoundException dataNodeNotFoundException) {
267                 log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}",
268                     cmHandle, dataNodeNotFoundException.getMessage());
269                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
270                     .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_DOES_NOT_EXIST));
271             } catch (final DataValidationException dataValidationException) {
272                 log.error("Unable to de-register cm-handle id: {}, caused by: {}",
273                     cmHandle, dataValidationException.getMessage());
274                 cmHandleRegistrationResponses.add(CmHandleRegistrationResponse
275                     .createFailureResponse(cmHandle, RegistrationError.CM_HANDLE_INVALID_ID));
276             } catch (final Exception exception) {
277                 log.error("Unable to de-register cm-handle id : {} , caused by : {}",
278                     cmHandle, exception.getMessage());
279                 cmHandleRegistrationResponses.add(
280                     CmHandleRegistrationResponse.createFailureResponse(cmHandle, exception));
281             }
282         }
283         return cmHandleRegistrationResponses;
284     }
285
286     private void deleteSchemaSetWithCascade(final String schemaSetName) {
287         try {
288             cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
289                 CASCADE_DELETE_ALLOWED);
290         } catch (final SchemaSetNotFoundException schemaSetNotFoundException) {
291             log.warn("Schema set {} does not exist or already deleted", schemaSetName);
292         }
293     }
294
295     private void syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle) {
296         final Collection<ModuleReference> moduleReferencesFromCmHandle =
297             dmiModelOperations.getModuleReferences(yangModelCmHandle);
298
299         final Collection<ModuleReference> identifiedNewModuleReferencesFromCmHandle = cpsModuleService
300             .identifyNewModuleReferences(moduleReferencesFromCmHandle);
301
302         final Collection<ModuleReference> existingModuleReferencesFromCmHandle =
303             moduleReferencesFromCmHandle.stream().filter(moduleReferenceFromCmHandle ->
304                 !identifiedNewModuleReferencesFromCmHandle.contains(moduleReferenceFromCmHandle)
305             ).collect(Collectors.toList());
306
307         final Map<String, String> newModuleNameToContentMap;
308         if (identifiedNewModuleReferencesFromCmHandle.isEmpty()) {
309             newModuleNameToContentMap = new HashMap<>();
310         } else {
311             newModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle,
312                 identifiedNewModuleReferencesFromCmHandle);
313         }
314         cpsModuleService
315             .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, yangModelCmHandle.getId(),
316                 newModuleNameToContentMap, existingModuleReferencesFromCmHandle);
317     }
318
319     private void createAnchor(final YangModelCmHandle yangModelCmHandle) {
320         cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, yangModelCmHandle.getId(),
321             yangModelCmHandle.getId());
322     }
323
324     private Object getResourceDataResponse(final String cmHandleId,
325                                            final String resourceIdentifier,
326                                            final DmiOperations.DataStoreEnum dataStore,
327                                            final String optionsParamInQuery,
328                                            final String topicParamInQuery,
329                                            final String requestId) {
330         final ResponseEntity<?> responseEntity = dmiDataOperations.getResourceDataFromDmi(
331                 cmHandleId, resourceIdentifier, optionsParamInQuery, dataStore, requestId, topicParamInQuery);
332         return handleResponse(responseEntity, OperationEnum.READ);
333     }
334 }