Merge "Process data-updated event asynchronously"
[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 Nordix Foundation
5  *  Modifications Copyright (C) 2021 Pantheon.tech
6  *  ================================================================================
7  *  Licensed under the Apache License, Version 2.0 (the "License");
8  *  you may not use this file except in compliance with the License.
9  *  You may obtain a copy of the License at
10  *
11  *        http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  *
19  *  SPDX-License-Identifier: Apache-2.0
20  *  ============LICENSE_END=========================================================
21  */
22
23 package org.onap.cps.ncmp.api.impl;
24
25 import com.fasterxml.jackson.core.JsonProcessingException;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.LinkedHashMap;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import javax.validation.constraints.NotNull;
34 import lombok.extern.slf4j.Slf4j;
35 import org.onap.cps.api.CpsDataService;
36 import org.onap.cps.api.CpsQueryService;
37 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
38 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
39 import org.onap.cps.ncmp.api.impl.operation.DmiOperations;
40 import org.onap.cps.ncmp.api.models.CmHandle;
41 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
42 import org.onap.cps.ncmp.api.models.GenericRequestBody;
43 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
44 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
45 import org.onap.cps.spi.FetchDescendantsOption;
46 import org.onap.cps.spi.exceptions.DataValidationException;
47 import org.onap.cps.spi.model.DataNode;
48 import org.springframework.http.HttpStatus;
49 import org.springframework.http.ResponseEntity;
50 import org.springframework.stereotype.Service;
51 import org.springframework.util.StringUtils;
52
53
54 @Slf4j
55 @Service
56 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
57
58     private static final String NF_PROXY_DATASPACE_NAME = "NFP-Operational";
59
60     private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
61
62     private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
63
64     private CpsDataService cpsDataService;
65
66     private ObjectMapper objectMapper;
67
68     private CpsQueryService cpsQueryService;
69
70     private DmiOperations dmiOperations;
71
72     /**
73      * Constructor Injection for Dependencies.
74      *
75      * @param dmiOperations   dmi operation
76      * @param cpsDataService  Data Service Interface
77      * @param cpsQueryService Query Service Interface
78      * @param objectMapper    Object Mapper
79      */
80     public NetworkCmProxyDataServiceImpl(final DmiOperations dmiOperations, final CpsDataService cpsDataService,
81         final CpsQueryService cpsQueryService, final ObjectMapper objectMapper) {
82         this.dmiOperations = dmiOperations;
83         this.cpsDataService = cpsDataService;
84         this.cpsQueryService = cpsQueryService;
85         this.objectMapper = objectMapper;
86     }
87
88     private String getDataspaceName() {
89         return NF_PROXY_DATASPACE_NAME;
90     }
91
92     @Override
93     public DataNode getDataNode(final String cmHandle, final String xpath,
94         final FetchDescendantsOption fetchDescendantsOption) {
95         return cpsDataService.getDataNode(getDataspaceName(), cmHandle, xpath, fetchDescendantsOption);
96     }
97
98     @Override
99     public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
100         final FetchDescendantsOption fetchDescendantsOption) {
101         return cpsQueryService.queryDataNodes(getDataspaceName(), cmHandle, cpsPath, fetchDescendantsOption);
102     }
103
104     @Override
105     public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) {
106         if (!StringUtils.hasText(parentNodeXpath) || "/".equals(parentNodeXpath)) {
107             cpsDataService.saveData(getDataspaceName(), cmHandle, jsonData);
108         } else {
109             cpsDataService.saveData(getDataspaceName(), cmHandle, parentNodeXpath, jsonData);
110         }
111     }
112
113     @Override
114     public void addListNodeElements(final String cmHandle, final String parentNodeXpath, final String jsonData) {
115         cpsDataService.saveListNodeData(getDataspaceName(), cmHandle, parentNodeXpath, jsonData);
116     }
117
118     @Override
119     public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) {
120         cpsDataService.updateNodeLeaves(getDataspaceName(), cmHandle, parentNodeXpath, jsonData);
121     }
122
123     @Override
124     public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) {
125         cpsDataService.replaceNodeTree(getDataspaceName(), cmHandle, parentNodeXpath, jsonData);
126     }
127
128     @Override
129     public void updateDmiPluginRegistration(final DmiPluginRegistration dmiPluginRegistration) {
130         if (dmiPluginRegistration.getCreatedCmHandles() != null) {
131             parseAndCreateCmHandlesInDmiRegistration(dmiPluginRegistration);
132         }
133         if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
134             parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
135         }
136     }
137
138     private void parseAndCreateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
139         try {
140             final List<PersistenceCmHandle> createdPersistenceCmHandles =
141                 new LinkedList<>();
142             for (final CmHandle cmHandle : dmiPluginRegistration.getCreatedCmHandles()) {
143                 createdPersistenceCmHandles.add(toPersistenceCmHandle(dmiPluginRegistration, cmHandle));
144             }
145             final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
146             persistenceCmHandlesList.setCmHandles(createdPersistenceCmHandles);
147             final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
148             cpsDataService.saveListNodeData(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
149                 cmHandleJsonData);
150         } catch (final JsonProcessingException e) {
151             log.error("Parsing error occurred while converting Object to JSON for Dmi Registry.");
152             throw new DataValidationException(
153                 "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
154                 .getMessage(), e);
155         }
156     }
157
158     private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
159         try {
160             final List<PersistenceCmHandle> updatedPersistenceCmHandles =
161                 new LinkedList<>();
162             for (final CmHandle cmHandle : dmiPluginRegistration.getUpdatedCmHandles()) {
163                 updatedPersistenceCmHandles.add(toPersistenceCmHandle(dmiPluginRegistration, cmHandle));
164             }
165             final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
166             persistenceCmHandlesList.setCmHandles(updatedPersistenceCmHandles);
167             final String cmHandlesJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
168             cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
169                 "/dmi-registry", cmHandlesJsonData);
170         } catch (final JsonProcessingException e) {
171             log.error("Parsing error occurred while converting Object to JSON Dmi Registry.");
172             throw new DataValidationException(
173                 "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
174                 .getMessage(), e);
175         }
176     }
177
178     @Override
179     public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle,
180         final @NotNull String resourceIdentifier,
181         final String acceptParam,
182         final String fieldsQueryParam,
183         final Integer depthQueryParam) {
184
185         final var dataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
186         final var dmiServiceName = String.valueOf(dataNode.getLeaves().get("dmi-service-name"));
187         final Collection<DataNode> additionalPropsList = dataNode.getChildDataNodes();
188         final var jsonBody = prepareOperationBody(GenericRequestBody.OperationEnum.READ, additionalPropsList);
189         final ResponseEntity<Object> response = dmiOperations.getResouceDataOperationalFromDmi(dmiServiceName,
190             cmHandle,
191             resourceIdentifier,
192             fieldsQueryParam,
193             depthQueryParam,
194             acceptParam,
195             jsonBody);
196         return handleResponse(response);
197     }
198
199     @Override
200     public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
201         final @NotNull String resourceIdentifier,
202         final String accept,
203         final String fields,
204         final Integer depth) {
205         final var cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
206         final var dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get("dmi-service-name"));
207         final Collection<DataNode> additionalPropsList = cmHandleDataNode.getChildDataNodes();
208         final var dmiRequesBody = prepareOperationBody(GenericRequestBody.OperationEnum.READ, additionalPropsList);
209         final ResponseEntity<Object> response = dmiOperations.getResouceDataPassThroughRunningFromDmi(dmiServiceName,
210             cmHandle,
211             resourceIdentifier,
212             fields,
213             depth,
214             accept,
215             dmiRequesBody);
216         return handleResponse(response);
217     }
218
219     private DataNode fetchDataNodeFromDmiRegistryForCmHandle(final String cmHandle) {
220         final String xpathForDmiRegistryToFetchCmHandle = "/dmi-registry/cm-handles[@id='" + cmHandle + "']";
221         final var dataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME,
222             NCMP_DMI_REGISTRY_ANCHOR,
223             xpathForDmiRegistryToFetchCmHandle,
224             FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
225         return dataNode;
226     }
227
228     private String prepareOperationBody(final GenericRequestBody.OperationEnum operation,
229         final Collection<DataNode> additionalPropertyList) {
230         final var requestBody = new GenericRequestBody();
231         final Map<String, String> additionalPropertyMap = getAdditionalPropertiesMap(additionalPropertyList);
232         requestBody.setOperation(GenericRequestBody.OperationEnum.READ);
233         requestBody.setCmHandleProperties(additionalPropertyMap);
234         try {
235             final var requestJson = objectMapper.writeValueAsString(requestBody);
236             return requestJson;
237         } catch (final JsonProcessingException je) {
238             log.error("Parsing error occurred while converting Object to JSON.");
239             throw new NcmpException("Parsing error occurred while converting given object to JSON.",
240                 je.getMessage());
241         }
242     }
243
244     private Map<String, String> getAdditionalPropertiesMap(final Collection<DataNode> additionalPropertyList) {
245         if (additionalPropertyList == null || additionalPropertyList.size() == 0) {
246             return null;
247         }
248         final Map<String, String> additionalPropertyMap = new LinkedHashMap<>();
249         for (final var node : additionalPropertyList) {
250             additionalPropertyMap.put(String.valueOf(node.getLeaves().get("name")),
251                 String.valueOf(node.getLeaves().get("value")));
252         }
253         return additionalPropertyMap;
254     }
255
256     private Object handleResponse(final ResponseEntity<Object> responseEntity) {
257         if (responseEntity.getStatusCode() == HttpStatus.OK) {
258             return responseEntity.getBody();
259         } else {
260             throw new NcmpException("Not able to get resource data.",
261                 "DMI status code: " + responseEntity.getStatusCodeValue()
262                     + ", DMI response body: " + responseEntity.getBody());
263         }
264     }
265
266     private PersistenceCmHandle toPersistenceCmHandle(final DmiPluginRegistration dmiPluginRegistration,
267         final CmHandle cmHandle) {
268         final PersistenceCmHandle persistenceCmHandle = new PersistenceCmHandle();
269         persistenceCmHandle.setDmiServiceName(dmiPluginRegistration.getDmiPlugin());
270         persistenceCmHandle.setId(cmHandle.getCmHandleID());
271         if (cmHandle.getCmHandleProperties() == null) {
272             persistenceCmHandle.setAdditionalProperties(Collections.EMPTY_MAP);
273         } else {
274             persistenceCmHandle.setAdditionalProperties(cmHandle.getCmHandleProperties());
275         }
276         return persistenceCmHandle;
277     }
278
279 }