Post impl for passthrough running (Ncmp impl.)
[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  *  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
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 com.fasterxml.jackson.core.JsonProcessingException;
27 import com.fasterxml.jackson.databind.ObjectMapper;
28 import java.time.OffsetDateTime;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.LinkedHashMap;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.Map;
35 import javax.validation.constraints.NotNull;
36 import lombok.extern.slf4j.Slf4j;
37 import org.onap.cps.api.CpsDataService;
38 import org.onap.cps.api.CpsQueryService;
39 import org.onap.cps.ncmp.api.NetworkCmProxyDataService;
40 import org.onap.cps.ncmp.api.impl.exception.NcmpException;
41 import org.onap.cps.ncmp.api.impl.operation.DmiOperations;
42 import org.onap.cps.ncmp.api.models.CmHandle;
43 import org.onap.cps.ncmp.api.models.DmiPluginRegistration;
44 import org.onap.cps.ncmp.api.models.GenericRequestBody;
45 import org.onap.cps.ncmp.api.models.PersistenceCmHandle;
46 import org.onap.cps.ncmp.api.models.PersistenceCmHandlesList;
47 import org.onap.cps.spi.FetchDescendantsOption;
48 import org.onap.cps.spi.exceptions.DataNodeNotFoundException;
49 import org.onap.cps.spi.exceptions.DataValidationException;
50 import org.onap.cps.spi.model.DataNode;
51 import org.springframework.http.HttpStatus;
52 import org.springframework.http.ResponseEntity;
53 import org.springframework.stereotype.Service;
54 import org.springframework.util.StringUtils;
55
56 @Slf4j
57 @Service
58 public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService {
59
60     private static final String NF_PROXY_DATASPACE_NAME = "NFP-Operational";
61
62     private static final String NCMP_DATASPACE_NAME = "NCMP-Admin";
63
64     private static final String NCMP_DMI_REGISTRY_ANCHOR = "ncmp-dmi-registry";
65
66     private static final OffsetDateTime NO_TIMESTAMP = null;
67
68     private static  final String NCMP_DMI_SERVICE_NAME = "dmi-service-name";
69
70     private CpsDataService cpsDataService;
71
72     private ObjectMapper objectMapper;
73
74     private CpsQueryService cpsQueryService;
75
76     private DmiOperations dmiOperations;
77
78     /**
79      * Constructor Injection for Dependencies.
80      * @param dmiOperations DMI operation
81      * @param cpsDataService Data Service Interface
82      * @param cpsQueryService Query Service Interface
83      * @param objectMapper Object Mapper
84      */
85     public NetworkCmProxyDataServiceImpl(final DmiOperations dmiOperations, final CpsDataService cpsDataService,
86                                          final CpsQueryService cpsQueryService, final ObjectMapper objectMapper) {
87         this.dmiOperations = dmiOperations;
88         this.cpsDataService = cpsDataService;
89         this.cpsQueryService = cpsQueryService;
90         this.objectMapper = objectMapper;
91     }
92
93     private String getDataspaceName() {
94         return NF_PROXY_DATASPACE_NAME;
95     }
96
97     @Override
98     public DataNode getDataNode(final String cmHandle, final String xpath,
99                                 final FetchDescendantsOption fetchDescendantsOption) {
100         return cpsDataService.getDataNode(getDataspaceName(), cmHandle, xpath, fetchDescendantsOption);
101     }
102
103     @Override
104     public Collection<DataNode> queryDataNodes(final String cmHandle, final String cpsPath,
105                                                final FetchDescendantsOption fetchDescendantsOption) {
106         return cpsQueryService.queryDataNodes(getDataspaceName(), cmHandle, cpsPath, fetchDescendantsOption);
107     }
108
109     @Override
110     public void createDataNode(final String cmHandle, final String parentNodeXpath, final String jsonData) {
111         if (!StringUtils.hasText(parentNodeXpath) || "/".equals(parentNodeXpath)) {
112             cpsDataService.saveData(getDataspaceName(), cmHandle, jsonData, NO_TIMESTAMP);
113         } else {
114             cpsDataService.saveData(getDataspaceName(), cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
115         }
116     }
117
118     @Override
119     public void addListNodeElements(final String cmHandle, final String parentNodeXpath, final String jsonData) {
120         cpsDataService.saveListNodeData(getDataspaceName(), cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
121     }
122
123     @Override
124     public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) {
125         cpsDataService.updateNodeLeaves(getDataspaceName(), cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
126     }
127
128     @Override
129     public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) {
130         cpsDataService.replaceNodeTree(getDataspaceName(), cmHandle, parentNodeXpath, jsonData, NO_TIMESTAMP);
131     }
132
133     @Override
134     public void updateDmiPluginRegistration(final DmiPluginRegistration dmiPluginRegistration) {
135         if (dmiPluginRegistration.getCreatedCmHandles() != null) {
136             parseAndCreateCmHandlesInDmiRegistration(dmiPluginRegistration);
137         }
138         if (dmiPluginRegistration.getUpdatedCmHandles() != null) {
139             parseAndUpdateCmHandlesInDmiRegistration(dmiPluginRegistration);
140         }
141         if (dmiPluginRegistration.getRemovedCmHandles() != null) {
142             parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration);
143         }
144     }
145
146     @Override
147     public Object getResourceDataOperationalForCmHandle(final @NotNull String cmHandle,
148                                                         final @NotNull String resourceIdentifier,
149                                                         final String acceptParam,
150                                                         final String fieldsQueryParam,
151                                                         final Integer depthQueryParam) {
152
153         final var cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
154         final var dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
155         final String dmiRequestBody = getGenericRequestBody(cmHandleDataNode);
156         final ResponseEntity<Object> response = dmiOperations.getResourceDataOperationalFromDmi(dmiServiceName,
157                 cmHandle,
158                 resourceIdentifier,
159                 fieldsQueryParam,
160                 depthQueryParam,
161                 acceptParam,
162                 dmiRequestBody);
163         return handleResponse(response);
164     }
165
166     @Override
167     public Object getResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
168                                                                final @NotNull String resourceIdentifier,
169                                                                final String acceptParam,
170                                                                final String fields,
171                                                                final Integer depth) {
172         final var cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
173         final var dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
174         final String dmiRequestBody = getGenericRequestBody(cmHandleDataNode);
175         final ResponseEntity<Object> response = dmiOperations.getResourceDataPassThroughRunningFromDmi(dmiServiceName,
176                 cmHandle,
177                 resourceIdentifier,
178                 fields,
179                 depth,
180                 acceptParam,
181                 dmiRequestBody);
182         return handleResponse(response);
183     }
184
185     @Override
186     public void createResourceDataPassThroughRunningForCmHandle(final @NotNull String cmHandle,
187                                                                 final @NotNull String resourceIdentifier,
188                                                                 final @NotNull Object requestBody,
189                                                                 final String contentType) {
190         final var cmHandleDataNode = fetchDataNodeFromDmiRegistryForCmHandle(cmHandle);
191         final var dmiServiceName = String.valueOf(cmHandleDataNode.getLeaves().get(NCMP_DMI_SERVICE_NAME));
192         final Collection<DataNode> cmHandlePropertiesList = cmHandleDataNode.getChildDataNodes();
193         final Map<String, String> cmHandlePropertiesMap = getCmHandlePropertiesAsMap(cmHandlePropertiesList);
194         final var dmiRequestBodyObject = GenericRequestBody.builder()
195                 .operation(GenericRequestBody.OperationEnum.CREATE)
196                 .dataType(contentType)
197                 .data(requestBody)
198                 .cmHandleProperties(cmHandlePropertiesMap)
199                 .build();
200         final var dmiRequestBody = prepareOperationBody(dmiRequestBodyObject);
201         final ResponseEntity<Void> responseEntity = dmiOperations
202                 .createResourceDataPassThroughRunningFromDmi(dmiServiceName,
203                         cmHandle,
204                         resourceIdentifier,
205                         dmiRequestBody);
206         handleResponseForPost(responseEntity);
207     }
208
209     private DataNode fetchDataNodeFromDmiRegistryForCmHandle(final String cmHandle) {
210         final String xpathForDmiRegistryToFetchCmHandle = "/dmi-registry/cm-handles[@id='" + cmHandle + "']";
211         final var dataNode = cpsDataService.getDataNode(NCMP_DATASPACE_NAME,
212                 NCMP_DMI_REGISTRY_ANCHOR,
213                 xpathForDmiRegistryToFetchCmHandle,
214                 FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
215         return dataNode;
216     }
217
218     private String prepareOperationBody(final GenericRequestBody requestBodyObject) {
219         try {
220             return objectMapper.writeValueAsString(requestBodyObject);
221         } catch (final JsonProcessingException je) {
222             log.error("Parsing error occurred while converting Object to JSON.");
223             throw new NcmpException("Parsing error occurred while converting given object to JSON.",
224                     je.getMessage());
225         }
226     }
227
228     private Map<String, String> getCmHandlePropertiesAsMap(final Collection<DataNode> cmHandlePropertiesList) {
229         if (cmHandlePropertiesList == null || cmHandlePropertiesList.size() == 0) {
230             return null;
231         }
232         final Map<String, String> cmHandlePropertiesMap = new LinkedHashMap<>();
233         for (final var node: cmHandlePropertiesList) {
234             cmHandlePropertiesMap.put(String.valueOf(node.getLeaves().get("name")),
235                     String.valueOf(node.getLeaves().get("value")));
236         }
237         return cmHandlePropertiesMap;
238     }
239
240     private Object handleResponse(final @NotNull ResponseEntity<Object> responseEntity) {
241         if (responseEntity.getStatusCode() == HttpStatus.OK) {
242             return responseEntity.getBody();
243         } else {
244             throw new NcmpException("Not able to get resource data.",
245                     "DMI status code: " + responseEntity.getStatusCodeValue()
246                             + ", DMI response body: " + responseEntity.getBody());
247         }
248     }
249
250     private void handleResponseForPost(final @NotNull ResponseEntity<Void> responseEntity) {
251         if (responseEntity.getStatusCode() != HttpStatus.CREATED) {
252             throw new NcmpException("Not able to create resource data.",
253                     "DMI status code: " + responseEntity.getStatusCodeValue()
254                             + ", DMI response body: " + responseEntity.getBody());
255         }
256     }
257
258     private String getGenericRequestBody(final DataNode cmHandleDataNode) {
259         final Collection<DataNode> cmHandlePropertiesList = cmHandleDataNode.getChildDataNodes();
260         final Map<String, String> cmHandlePropertiesMap = getCmHandlePropertiesAsMap(cmHandlePropertiesList);
261         final var requetBodyObject = GenericRequestBody.builder()
262                 .operation(GenericRequestBody.OperationEnum.READ)
263                 .cmHandleProperties(cmHandlePropertiesMap)
264                 .build();
265         return prepareOperationBody(requetBodyObject);
266     }
267
268     private PersistenceCmHandle toPersistenceCmHandle(final String dmiPluginService,
269                                                       final CmHandle cmHandle) {
270         final PersistenceCmHandle persistenceCmHandle = new PersistenceCmHandle();
271         persistenceCmHandle.setDmiServiceName(dmiPluginService);
272         persistenceCmHandle.setId(cmHandle.getCmHandleID());
273         if (cmHandle.getCmHandleProperties() == null) {
274             persistenceCmHandle.setAdditionalProperties(Collections.EMPTY_MAP);
275         } else {
276             persistenceCmHandle.setAdditionalProperties(cmHandle.getCmHandleProperties());
277         }
278         return persistenceCmHandle;
279     }
280
281     private void parseAndCreateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
282         try {
283             final List<PersistenceCmHandle> createdPersistenceCmHandles =
284                     new LinkedList<>();
285             for (final CmHandle cmHandle: dmiPluginRegistration.getCreatedCmHandles()) {
286                 createdPersistenceCmHandles.add(toPersistenceCmHandle(dmiPluginRegistration.getDmiPlugin(), cmHandle));
287             }
288             final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
289             persistenceCmHandlesList.setCmHandles(createdPersistenceCmHandles);
290             final String cmHandleJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
291             cpsDataService.saveListNodeData(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry",
292                     cmHandleJsonData, NO_TIMESTAMP);
293         } catch (final JsonProcessingException e) {
294             log.error("Parsing error occurred while converting Object to JSON for DMI Registry.");
295             throw new DataValidationException(
296                     "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
297                     .getMessage(), e);
298         }
299     }
300
301     private void parseAndUpdateCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
302         try {
303             final List<PersistenceCmHandle> updatedPersistenceCmHandles =
304                     new LinkedList<>();
305             for (final CmHandle cmHandle: dmiPluginRegistration.getUpdatedCmHandles()) {
306                 updatedPersistenceCmHandles.add(toPersistenceCmHandle(dmiPluginRegistration.getDmiPlugin(), cmHandle));
307             }
308             final PersistenceCmHandlesList persistenceCmHandlesList = new PersistenceCmHandlesList();
309             persistenceCmHandlesList.setCmHandles(updatedPersistenceCmHandles);
310             final String cmHandlesJsonData = objectMapper.writeValueAsString(persistenceCmHandlesList);
311             cpsDataService.updateNodeLeavesAndExistingDescendantLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
312                     "/dmi-registry", cmHandlesJsonData, NO_TIMESTAMP);
313         } catch (final JsonProcessingException e) {
314             log.error("Parsing error occurred while converting Object to JSON DMI Registry.");
315             throw new DataValidationException(
316                     "Parsing error occurred while processing DMI Plugin Registration" + dmiPluginRegistration, e
317                     .getMessage(), e);
318         }
319     }
320
321     private void parseAndRemoveCmHandlesInDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
322         for (final String cmHandle: dmiPluginRegistration.getRemovedCmHandles()) {
323             try {
324                 cpsDataService.deleteListNodeData(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR,
325                         "/dmi-registry/cm-handles[@id='" + cmHandle + "']", NO_TIMESTAMP);
326             } catch (final DataNodeNotFoundException e) {
327                 log.warn("Datanode {} not deleted message {}", cmHandle, e.getMessage());
328             }
329         }
330     }
331 }