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 java.time.OffsetDateTime;
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.HashMap;
35 import java.util.List;
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.api.CpsQueryService;
42 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
43 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
44 import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations;
45 import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations;
46 import org.onap.cps.ncmp.api.impl.operations.DmiOperations;
47 import org.onap.cps.ncmp.api.models.CmHandle;
48 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
49 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
50 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
51 import org.onap.cps.spi.FetchDescendantsOption;
52 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
53 import org.onap.cps.spi.exceptions.DataValidationException;
54 import org.onap.cps.spi.model.DataNode;
55 import org.onap.cps.spi.model.ModuleReference;
56 import org.springframework.http.ResponseEntity;
57 import org.springframework.stereotype.Service;
58 import org.springframework.util.StringUtils;
62 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
64 private static final String NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME = "NFP-Operational";
66 private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
68 private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
70 private static final OffsetDateTime NO_TIMESTAMP = null;
72 private CpsDataService cpsDataService;
74 private ObjectMapper objectMapper;
76 private CpsQueryService cpsQueryService;
78 private DmiDataOperations dmiDataOperations;
80 private DmiModelOperations dmiModelOperations;
82 private CpsModuleService cpsModuleService;
84 private CpsAdminService cpsAdminService;
87 * Constructor Injection for Dependencies.
88 * @param dmiDataOperations DMI operation
89 * @param cpsDataService Data Service Interface
90 * @param cpsQueryService Query Service Interface
91 * @param objectMapper Object Mapper
93 public NetworkCmProxyDataServiceImpl(final DmiDataOperations dmiDataOperations,
94 final DmiModelOperations dmiModelOperations,
95 final CpsModuleService cpsModuleService,
96 final CpsDataService cpsDataService,
97 final CpsQueryService cpsQueryService,
98 final CpsAdminService cpsAdminService,
99 final ObjectMapper objectMapper) {
100 this.dmiDataOperations = dmiDataOperations;
101 this.dmiModelOperations = dmiModelOperations;
102 this.cpsModuleService = cpsModuleService;
103 this.cpsDataService = cpsDataService;
104 this.cpsQueryService = cpsQueryService;
105 this.cpsAdminService = cpsAdminService;
106 this.objectMapper = objectMapper;
110 public DataNode getDataNode(final String cmHandle, final String xpath,
111 final FetchDescendantsOption fetchDescendantsOption) {
112 return cpsDataService
113 .getDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, xpath, fetchDescendantsOption);
117 public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
118 final FetchDescendantsOption fetchDescendantsOption) {
119 return cpsQueryService
120 .queryDataNodes(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption);
124 public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) {
125 if (!StringUtils.hasText(parentNodeXpath) || "/".equals(parentNodeXpath)) {
126 cpsDataService.saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, jsonData, NO_TIMESTAMP);
129 .saveData(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
134 public void addListNodeElements(final String cmHandle, final String parentNodeXpath, final String jsonData) {
135 cpsDataService.saveListElements(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
140 public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) {
142 .updateNodeLeaves(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
147 public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) {
148 cpsDataService.replaceNodeTree(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData,
153 public void updateDmiRegistrationAndSyncModule(final DmiPluginRegistration dmiPluginRegistration) {
154 dmiPluginRegistration.validateDmiPluginRegistration();
156 if (dmiPluginRegistration.getCreatedCmHandles() != null) {
157 parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration);
159 if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
160 parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
162 if (dmiPluginRegistration.getRemovedCmHandles() != null) {
163 parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration);
165 } catch (final JsonProcessingException e) {
166 handleJsonProcessingException(dmiPluginRegistration, e);
171 public Object getResourceDataOperationalForCmHandle(final String cmHandle,
172 final String resourceIdentifier,
173 final String acceptParamInHeader,
174 final String optionsParamInQuery) {
175 return handleResponse(dmiDataOperations.getResourceDataFromDmi(
180 DmiOperations.DataStoreEnum.PASSTHROUGH_OPERATIONAL), "Not able to get resource data.");
184 public Object getResourceDataPassThroughRunningForCmHandle(final String cmHandle,
185 final String resourceIdentifier,
186 final String acceptParamInHeader,
187 final String optionsParamInQuery) {
188 return handleResponse(dmiDataOperations.getResourceDataFromDmi(
193 DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING), "Not able to get resource data.");
197 public void writeResourceDataPassThroughRunningForCmHandle(final String cmHandle,
198 final String resourceIdentifier,
199 final OperationEnum operation,
200 final String requestData,
201 final String dataType) {
203 dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(
204 cmHandle, resourceIdentifier, operation, requestData, dataType),
205 "Not able to " + operation + " resource data.");
210 public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandle) {
211 return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandle);
215 * Retrieve cm handle identifiers for the given list of module names.
217 * @param moduleNames module names.
218 * @return a collection of anchor identifiers
221 public Collection<String> executeCmHandleHasAllModulesSearch(final Collection<String> moduleNames) {
222 return cpsAdminService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNames);
226 * THis method registers a cm handle and intiates modules sync.
228 * @param dmiPluginRegistration dmi plugin registration information.
229 * @throws JsonProcessingException thrown if json is malformed or missing.
231 public void parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(
232 final DmiPluginRegistration dmiPluginRegistration) throws JsonProcessingException {
233 final PersistenceCmHandlesList createdPersistenceCmHandlesList =
234 getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getCreatedCmHandles());
235 registerAndSyncNewCmHandles(createdPersistenceCmHandlesList);
238 private static Object handleResponse(final ResponseEntity<?> responseEntity,
239 final String exceptionMessage) {
240 if (responseEntity.getStatusCode().is2xxSuccessful()) {
241 return responseEntity.getBody();
243 throw new NcmpException(exceptionMessage,
244 "DMI status code: " + responseEntity.getStatusCodeValue()
245 + ", DMI response body: " + responseEntity.getBody());
249 private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration)
250 throws JsonProcessingException {
251 final PersistenceCmHandlesList updatedPersistenceCmHandlesList =
252 getUpdatedPersistenceCmHandlesList(dmiPluginRegistration, dmiPluginRegistration.getUpdatedCmHandles());
253 final String cmHandlesAsJson = objectMapper.writeValueAsString(updatedPersistenceCmHandlesList);
254 cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
255 "/dmi-registry", cmHandlesAsJson, NO_TIMESTAMP);
258 private PersistenceCmHandlesList getUpdatedPersistenceCmHandlesList(
259 final DmiPluginRegistration dmiPluginRegistration,
260 final List<CmHandle> updatedCmHandles) {
261 return PersistenceCmHandlesList.toPersistenceCmHandlesList(
262 dmiPluginRegistration.getDmiPlugin(),
263 dmiPluginRegistration.getDmiDataPlugin(),
264 dmiPluginRegistration.getDmiModelPlugin(),
268 private static void handleJsonProcessingException(final DmiPluginRegistration dmiPluginRegistration,
269 final JsonProcessingException e) {
270 final String message = "Parsing error occurred while processing DMI Plugin Registration"
271 + dmiPluginRegistration;
273 throw new DataValidationException(message, e.getMessage(), e);
276 private void registerAndSyncNewCmHandles(final PersistenceCmHandlesList persistenceCmHandlesList)
277 throws JsonProcessingException {
278 final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
279 cpsDataService.saveListElements(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
280 cmHandleJsonData, NO_TIMESTAMP);
282 for (final PersistenceCmHandle persistenceCmHandle : persistenceCmHandlesList.getPersistenceCmHandles()) {
283 syncModulesAndCreateAnchor(persistenceCmHandle);
287 protected void syncModulesAndCreateAnchor(final PersistenceCmHandle persistenceCmHandle) {
288 syncAndCreateSchemaSet(persistenceCmHandle);
289 createAnchor(persistenceCmHandle);
292 private void parseAndRemoveCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
293 for (final String cmHandle : dmiPluginRegistration.getRemovedCmHandles()) {
295 attemptToDeleteSchemaSetWithCascade(cmHandle);
296 cpsDataService.deleteListOrListElement(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
297 "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
298 } catch (final DataNodeNotFoundException e) {
299 log.warn("Datanode {} not deleted message {}", cmHandle, e.getMessage());
304 private void attemptToDeleteSchemaSetWithCascade(final String schemaSetName) {
306 cpsModuleService.deleteSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName,
307 CASCADE_DELETE_ALLOWED);
308 } catch (final Exception e) {
309 log.warn("Schema set {} delete failed, reason {}", schemaSetName, e.getMessage());
313 private void syncAndCreateSchemaSet(final PersistenceCmHandle persistenceCmHandle) {
314 final List<ModuleReference> moduleReferencesFromCmHandle =
315 dmiModelOperations.getModuleReferences(persistenceCmHandle);
316 final List<ModuleReference> existingModuleReferences = new ArrayList<>();
317 final List<ModuleReference> unknownModuleReferences = new ArrayList<>();
318 prepareModuleSubsets(moduleReferencesFromCmHandle, existingModuleReferences, unknownModuleReferences);
320 final Map<String, String> newYangResourcesModuleNameToContentMap;
321 if (unknownModuleReferences.isEmpty()) {
322 newYangResourcesModuleNameToContentMap = new HashMap<>();
324 newYangResourcesModuleNameToContentMap = dmiModelOperations.getNewYangResourcesFromDmi(persistenceCmHandle,
325 unknownModuleReferences);
328 .createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
329 newYangResourcesModuleNameToContentMap, existingModuleReferences);
332 private void prepareModuleSubsets(final List<ModuleReference> moduleReferencesFromCmHandle,
333 final List<ModuleReference> existingModuleReferences,
334 final List<ModuleReference> unknownModuleReferences) {
336 final Collection<ModuleReference> knownModuleReferencesInCps =
337 cpsModuleService.getYangResourceModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME);
339 for (final ModuleReference moduleReferenceFromDmiForCmHandle : moduleReferencesFromCmHandle) {
340 if (knownModuleReferencesInCps.contains(moduleReferenceFromDmiForCmHandle)) {
341 existingModuleReferences.add(moduleReferenceFromDmiForCmHandle);
343 unknownModuleReferences.add(moduleReferenceFromDmiForCmHandle);
348 private void createAnchor(final PersistenceCmHandle persistenceCmHandle) {
349 cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, persistenceCmHandle.getId(),
350 persistenceCmHandle.getId());