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 cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle,
301 CASCADE_DELETE_ALLOWED);
302 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
303 "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
304 } catch (final DataNodeNotFoundException e) {
305 log.warn("Datanode {} not deleted message {}", cmHandle, e.getMessage());
310 private void syncAndCreateSchemaSet(final PersistenceCmHandle persistenceCmHandle) {
312 final List<ModuleReference> moduleReferencesFromCmHandle =
313 toModuleReferences(dmiModelOperations.getModuleReferences(persistenceCmHandle));
314 final List<ModuleReference> existingModuleReferences = new ArrayList<>();
315 final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
316 prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
318 final Map<String, String> newYangResourcesModuleNameToContentMap;
319 if (unknownModuleReferences.isEmpty()) {
320 newYangResourcesModuleNameToContentMap = new HashMap<>();
322 newYangResourcesModuleNameToContentMap = getNewYangResourcesFromDmi(persistenceCmHandle,
323 unknownModuleReferences);
326 .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
327 newYangResourcesModuleNameToContentMap, existingModuleReferences);
330 private void prepareModuleSubsets(final List<ModuleReference> moduleReferencesFromCmHandle,
331 final List<ModuleReference> existingModuleReferences,
332 final List<ModuleReference> unknownModuleReferences) {
334 final Collection<ModuleReference> knownModuleReferencesInCps =
335 cpsModuleService.getYangResourceModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME);
337 for (final ModuleReference moduleReferenceFromDmiForCmHandle : moduleReferencesFromCmHandle) {
338 if (knownModuleReferencesInCps.contains(moduleReferenceFromDmiForCmHandle)) {
339 existingModuleReferences.add(moduleReferenceFromDmiForCmHandle);
341 unknownModuleReferences.add(moduleReferenceFromDmiForCmHandle);
346 private void createAnchor(final PersistenceCmHandle persistenceCmHandle) {
347 cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
348 persistenceCmHandle.getId());
351 private Map<String, String> getNewYangResourcesFromDmi(final PersistenceCmHandle persistenceCmHandle,
352 final List<ModuleReference> unknownModuleReferences) {
353 final ResponseEntity<String> responseEntity =
354 dmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle, unknownModuleReferences);
356 final JsonArray moduleResources = new Gson().fromJson(responseEntity.getBody(),
358 final Map<String, String> newYangResourcesModuleNameToContentMap = new HashMap<>();
360 for (final JsonElement moduleResource : moduleResources) {
361 final YangResource yangResource = toYangResource((JsonObject) moduleResource);
362 newYangResourcesModuleNameToContentMap.put(yangResource.getModuleName(), yangResource.getYangSource());
364 return newYangResourcesModuleNameToContentMap;
367 private static YangResource toYangResource(final JsonObject yangResourceAsJson) {
368 final YangResource yangResource = new YangResource();
369 yangResource.setModuleName(yangResourceAsJson.get("moduleName").getAsString());
370 yangResource.setRevision(yangResourceAsJson.get("revision").getAsString());
371 yangResource.setYangSource(yangResourceAsJson.get("yangSource").getAsString());
375 private static List<ModuleReference> toModuleReferences(
376 final ResponseEntity<String> dmiFetchModulesResponseEntity) {
377 final List<ModuleReference> moduleReferences = new ArrayList<>();
378 final JsonObject bodyAsJsonObject = new Gson().fromJson(dmiFetchModulesResponseEntity.getBody(),
380 final JsonArray moduleReferencesAsJson = bodyAsJsonObject.getAsJsonArray("schemas");
381 for (final JsonElement moduleReferenceAsJson : moduleReferencesAsJson) {
382 final ModuleReference moduleReference = toModuleReference((JsonObject) moduleReferenceAsJson);
383 moduleReferences.add(moduleReference);
385 return moduleReferences;
388 private static ModuleReference toModuleReference(final JsonObject moduleReferenceAsJson) {
389 final ModuleReference moduleReference = new ModuleReference();
390 moduleReference.setModuleName(moduleReferenceAsJson.get("moduleName").getAsString());
391 moduleReference.setRevision(moduleReferenceAsJson.get("revision").getAsString());
392 return moduleReference;