2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 highstreet technologies GmbH
4 * Modifications Copyright (C) 2021 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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * SPDX-License-Identifier: Apache-2.0
21 * ============LICENSE_END=========================================================
24 package org.onap.cps.ncmp.api.impl;
26 import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum;
27 import static org.onap.cps.spi.CascadeDeleteAllowed.CASCADE_DELETE_ALLOWED;
29 import com.fasterxml.jackson.core.JsonProcessingException;
30 import com.fasterxml.jackson.databind.ObjectMapper;
31 import com.google.gson.Gson;
32 import com.google.gson.JsonArray;
33 import com.google.gson.JsonElement;
34 import com.google.gson.JsonObject;
35 import java.time.OffsetDateTime;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.HashMap;
39 import java.util.List;
41 import lombok.extern.slf4j.Slf4j;
42 import org.onap.cps.api.CpsAdminService;
43 import org.onap.cps.api.CpsDataService;
44 import org.onap.cps.api.CpsModuleService;
45 import org.onap.cps.api.CpsQueryService;
46 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
47 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
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.models.CmHandle;
52 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
53 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
54 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
55 import org.onap.cps.ncmp.api.models.YangResource;
56 import org.onap.cps.spi.FetchDescendantsOption;
57 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
58 import org.onap.cps.spi.exceptions.DataValidationException;
59 import org.onap.cps.spi.model.DataNode;
60 import org.onap.cps.spi.model.ModuleReference;
61 import org.springframework.http.ResponseEntity;
62 import org.springframework.stereotype.Service;
63 import org.springframework.util.StringUtils;
67 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
69 private static final String NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME = "NFP-Operational";
71 private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
73 private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
75 private static final OffsetDateTime NO_TIMESTAMP = null;
77 private CpsDataService cpsDataService;
79 private ObjectMapper objectMapper;
81 private CpsQueryService cpsQueryService;
83 private DmiDataOperations dmiDataOperations;
85 private DmiModelOperations dmiModelOperations;
87 private CpsModuleService cpsModuleService;
89 private CpsAdminService cpsAdminService;
92 * Constructor Injection for Dependencies.
93 * @param dmiDataOperations DMI operation
94 * @param cpsDataService Data Service Interface
95 * @param cpsQueryService Query Service Interface
96 * @param objectMapper Object Mapper
98 public NetworkCmProxyDataServiceImpl(final DmiDataOperations dmiDataOperations,
99 final DmiModelOperations dmiModelOperations,
100 final CpsModuleService cpsModuleService,
101 final CpsDataService cpsDataService,
102 final CpsQueryService cpsQueryService,
103 final CpsAdminService cpsAdminService,
104 final ObjectMapper objectMapper) {
105 this.dmiDataOperations = dmiDataOperations;
106 this.dmiModelOperations = dmiModelOperations;
107 this.cpsModuleService = cpsModuleService;
108 this.cpsDataService = cpsDataService;
109 this.cpsQueryService = cpsQueryService;
110 this.cpsAdminService = cpsAdminService;
111 this.objectMapper = objectMapper;
115 public DataNode getDataNode(final String cmHandle, final String xpath,
116 final FetchDescendantsOption fetchDescendantsOption) {
117 return cpsDataService
118 .getDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, xpath, fetchDescendantsOption);
122 public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
123 final FetchDescendantsOption fetchDescendantsOption) {
124 return cpsQueryService
125 .queryDataNodes(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption);
129 public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) {
130 if (!StringUtils.hasText(parentNodeXpath) || "/".equals(parentNodeXpath)) {
131 cpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, jsonData, NO_TIMESTAMP);
134 .saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
139 public void addListNodeElements(final String cmHandle, final String parentNodeXpath, final String jsonData) {
140 cpsDataService.saveListElements(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
145 public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) {
147 .updateNodeLeaves(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
152 public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) {
153 cpsDataService.replaceNodeTree(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
158 public void updateDmiRegistrationAndSyncModule(final DmiPluginRegistration dmiPluginRegistration) {
159 dmiPluginRegistration.validateDmiPluginRegistration();
161 if (dmiPluginRegistration.getCreatedCmHandles() != null) {
162 parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration);
164 if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
165 parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
167 if (dmiPluginRegistration.getRemovedCmHandles() != null) {
168 parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration);
170 } catch (final JsonProcessingException e) {
171 handleJsonProcessingException(dmiPluginRegistration, e);
176 public Object getResourceDataOperationalForCmHandle(final String cmHandle,
177 final String resourceIdentifier,
178 final String acceptParamInHeader,
179 final String optionsParamInQuery) {
180 return handleResponse(dmiDataOperations.getResourceDataFromDmi(
185 DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL), "Not able to get resource data.");
189 public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandle,
190 final String resourceIdentifier,
191 final String acceptParamInHeader,
192 final String optionsParamInQuery) {
193 return handleResponse(dmiDataOperations.getResourceDataFromDmi(
198 DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING), "Not able to get resource data.");
202 public void writeResourceDataPassThroughRunningForCmHandle(final String cmHandle,
203 final String resourceIdentifier,
204 final OperationEnum operation,
205 final String requestData,
206 final String dataType) {
208 dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(
209 cmHandle, resourceIdentifier, operation, requestData, dataType),
210 "Not able to " + operation + " resource data.");
215 public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandle) {
216 return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle);
220 * Retrieve cm handle identifiers for the given list of module names.
222 * @param moduleNames module names.
223 * @return a collection of anchor identifiers
226 public Collection<String> executeCmHandleHasAllModulesSearch(final Collection<String> moduleNames) {
227 return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
231 * THis method registers a cm handle and intiates modules sync.
233 * @param dmiPluginRegistration dmi plugin registration information.
234 * @throws JsonProcessingException thrown if json is malformed or missing.
236 public void parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
237 final DmiPluginRegistration dmiPluginRegistration) throws JsonProcessingException {
238 final PersistenceCmHandlesList createdPersistenceCmHandlesList =
239 getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getCreatedCmHandles());
240 registerAndSyncNewCmHandles(createdPersistenceCmHandlesList);
243 private static Object handleResponse(final ResponseEntity<?> responseEntity,
244 final String exceptionMessage) {
245 if (responseEntity.getStatusCode().is2xxSuccessful()) {
246 return responseEntity.getBody();
248 throw new NcmpException(exceptionMessage,
249 "DMI status code: " + responseEntity.getStatusCodeValue()
250 + ", DMI response body: " + responseEntity.getBody());
254 private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration)
255 throws JsonProcessingException {
256 final PersistenceCmHandlesList updatedPersistenceCmHandlesList =
257 getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getUpdatedCmHandles());
258 final String cmHandlesAsJson = objectMapper.writeValueAsString(updatedPersistenceCmHandlesList);
259 cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
260 "/dmi-registry", cmHandlesAsJson, NO_TIMESTAMP);
263 private PersistenceCmHandlesList getUpdatedPersistenceCmHandlesList(
264 final DmiPluginRegistration dmiPluginRegistration,
265 final List<CmHandle> updatedCmHandles) {
266 return PersistenceCmHandlesList.toPersistenceCmHandlesList(
267 dmiPluginRegistration.getDmiPlugin(),
268 dmiPluginRegistration.getDmiDataPlugin(),
269 dmiPluginRegistration.getDmiModelPlugin(),
273 private static void handleJsonProcessingException(final DmiPluginRegistration dmiPluginRegistration,
274 final JsonProcessingException e) {
275 final String message = "Parsing error occurred while processing DMI Plugin Registration"
276 + dmiPluginRegistration;
278 throw new DataValidationException(message, e.getMessage(), e);
281 private void registerAndSyncNewCmHandles(final PersistenceCmHandlesList persistenceCmHandlesList)
282 throws JsonProcessingException {
283 final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
284 cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
285 cmHandleJsonData, NO_TIMESTAMP);
287 for (final PersistenceCmHandle persistenceCmHandle : persistenceCmHandlesList.getPersistenceCmHandles()) {
288 syncModulesAndCreateAnchor(persistenceCmHandle);
292 protected void syncModulesAndCreateAnchor(final PersistenceCmHandle persistenceCmHandle) {
293 syncAndCreateSchemaSet(persistenceCmHandle);
294 createAnchor(persistenceCmHandle);
297 private void parseAndRemoveCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
298 for (final String cmHandle : dmiPluginRegistration.getRemovedCmHandles()) {
300 attemptToDeleteSchemaSetWithCascade(cmHandle);
301 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
302 "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
303 } catch (final DataNodeNotFoundException e) {
304 log.warn("Datanode {} not deleted message {}", cmHandle, e.getMessage());
309 private void attemptToDeleteSchemaSetWithCascade(final String schemaSetName) {
311 cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
312 CASCADE_DELETE_ALLOWED);
313 } catch (final Exception e) {
314 log.warn("Schema set {} delete failed, reason {}", schemaSetName, e.getMessage());
318 private void syncAndCreateSchemaSet(final PersistenceCmHandle persistenceCmHandle) {
320 final List<ModuleReference> moduleReferencesFromCmHandle =
321 toModuleReferences(dmiModelOperations.getModuleReferences(persistenceCmHandle));
322 final List<ModuleReference> existingModuleReferences = new ArrayList<>();
323 final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
324 prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
326 final Map<String, String> newYangResourcesModuleNameToContentMap;
327 if (unknownModuleReferences.isEmpty()) {
328 newYangResourcesModuleNameToContentMap = new HashMap<>();
330 newYangResourcesModuleNameToContentMap = getNewYangResourcesFromDmi(persistenceCmHandle,
331 unknownModuleReferences);
334 .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
335 newYangResourcesModuleNameToContentMap, existingModuleReferences);
338 private void prepareModuleSubsets(final List<ModuleReference> moduleReferencesFromCmHandle,
339 final List<ModuleReference> existingModuleReferences,
340 final List<ModuleReference> unknownModuleReferences) {
342 final Collection<ModuleReference> knownModuleReferencesInCps =
343 cpsModuleService.getYangResourceModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME);
345 for (final ModuleReference moduleReferenceFromDmiForCmHandle : moduleReferencesFromCmHandle) {
346 if (knownModuleReferencesInCps.contains(moduleReferenceFromDmiForCmHandle)) {
347 existingModuleReferences.add(moduleReferenceFromDmiForCmHandle);
349 unknownModuleReferences.add(moduleReferenceFromDmiForCmHandle);
354 private void createAnchor(final PersistenceCmHandle persistenceCmHandle) {
355 cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
356 persistenceCmHandle.getId());
359 private Map<String, String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
360 final List<ModuleReference> unknownModuleReferences) {
361 final ResponseEntity<String> responseEntity =
362 dmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences);
364 final JsonArray moduleResources = new Gson().fromJson(responseEntity.getBody(),
366 final Map<String, String> newYangResourcesModuleNameToContentMap = new HashMap<>();
368 for (final JsonElement moduleResource : moduleResources) {
369 final YangResource yangResource = toYangResource((JsonObject) moduleResource);
370 newYangResourcesModuleNameToContentMap.put(yangResource.getModuleName(), yangResource.getYangSource());
372 return newYangResourcesModuleNameToContentMap;
375 private static YangResource toYangResource(final JsonObject yangResourceAsJson) {
376 final YangResource yangResource = new YangResource();
377 yangResource.setModuleName(yangResourceAsJson.get("moduleName").getAsString());
378 yangResource.setRevision(yangResourceAsJson.get("revision").getAsString());
379 yangResource.setYangSource(yangResourceAsJson.get("yangSource").getAsString());
383 private static List<ModuleReference> toModuleReferences(
384 final ResponseEntity<String> dmiFetchModulesResponseEntity) {
385 final List<ModuleReference> moduleReferences = new ArrayList<>();
386 final JsonObject bodyAsJsonObject = new Gson().fromJson(dmiFetchModulesResponseEntity.getBody(),
388 final JsonArray moduleReferencesAsJson = bodyAsJsonObject.getAsJsonArray("schemas");
389 for (final JsonElement moduleReferenceAsJson : moduleReferencesAsJson) {
390 final ModuleReference moduleReference = toModuleReference((JsonObject) moduleReferenceAsJson);
391 moduleReferences.add(moduleReference);
393 return moduleReferences;
396 private static ModuleReference toModuleReference(final JsonObject moduleReferenceAsJson) {
397 final ModuleReference moduleReference = new ModuleReference();
398 moduleReference.setModuleName(moduleReferenceAsJson.get("moduleName").getAsString());
399 moduleReference.setRevision(moduleReferenceAsJson.get("revision").getAsString());
400 return moduleReference;