Support for Patch across multiple data nodes
[cps.git] / cps-ncmp-service / src / main / java / org / onap / cps / ncmp / api / impl / operations / DmiDataOperations.java
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2021-2023 Nordix Foundation
4  *  Modifications Copyright (C) 2022 Bell Canada
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 package org.onap.cps.ncmp.api.impl.operations;
23
24 import static org.onap.cps.ncmp.api.impl.operations.DataStoreEnum.PASSTHROUGH_RUNNING;
25 import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.READ;
26
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30 import lombok.extern.slf4j.Slf4j;
31 import org.onap.cps.ncmp.api.impl.client.DmiRestClient;
32 import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
33 import org.onap.cps.ncmp.api.impl.executor.TaskExecutor;
34 import org.onap.cps.ncmp.api.impl.utils.DmiServiceNameOrganizer;
35 import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder;
36 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
37 import org.onap.cps.ncmp.api.inventory.CmHandleState;
38 import org.onap.cps.ncmp.api.inventory.InventoryPersistence;
39 import org.onap.cps.spi.exceptions.CpsException;
40 import org.onap.cps.utils.JsonObjectMapper;
41 import org.springframework.http.HttpStatus;
42 import org.springframework.http.ResponseEntity;
43 import org.springframework.stereotype.Component;
44
45 /**
46  * Operations class for DMI data.
47  */
48 @Component
49 @Slf4j
50 public class DmiDataOperations extends DmiOperations {
51
52     private static final long DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS = 30000L;
53     private static final String NO_CM_HANDLE_ID = "";
54
55     public DmiDataOperations(final InventoryPersistence inventoryPersistence,
56                              final JsonObjectMapper jsonObjectMapper,
57                              final NcmpConfiguration.DmiProperties dmiProperties,
58                              final DmiRestClient dmiRestClient,
59                              final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
60         super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
61     }
62
63     /**
64      * This method fetches the resource data from operational data store for given cm handle
65      * identifier on given resource using dmi client.
66      *
67      * @param dataStoreName       name of data store
68      * @param cmHandleId          network resource identifier
69      * @param resourceId          resource identifier
70      * @param optionsParamInQuery options query
71      * @param topicParamInQuery   topic name for (triggering) async responses
72      * @param requestId           requestId for async responses
73      * @return {@code ResponseEntity} response entity
74      */
75     public ResponseEntity<Object> getResourceDataFromDmi(final String dataStoreName,
76                                                          final String cmHandleId,
77                                                          final String resourceId,
78                                                          final String optionsParamInQuery,
79                                                          final String topicParamInQuery,
80                                                          final String requestId) {
81         final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
82         final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
83         validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
84         final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null,
85                 yangModelCmHandle);
86         final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, resourceId, optionsParamInQuery,
87                 topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA));
88         return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ);
89     }
90
91     /**
92      * This method fetches the resource data by data store for given list of cm handles using dmi client.
93      *
94      * @param dataStoreName           data store name
95      * @param cmHandleIds         list of cm handles
96      * @param resourceId          resource identifier
97      * @param optionsParamInQuery options query
98      * @param topicParamInQuery   topic name for (triggering) async responses
99      * @param requestId           requestId for async responses
100      * @return {@code ResponseEntity} response entity
101      */
102     public ResponseEntity<Object> getResourceDataFromDmi(final String dataStoreName,
103                                                          final List<String> cmHandleIds,
104                                                          final String resourceId,
105                                                          final String optionsParamInQuery,
106                                                          final String topicParamInQuery,
107                                                          final String requestId) {
108         final Collection<YangModelCmHandle> yangModelCmHandles
109                 = inventoryPersistence.getYangModelCmHandles(cmHandleIds);
110         final Map<String, Map<String, Map<String, String>>> dmiServiceNameCmHandlePropertiesMap =
111                 DmiServiceNameOrganizer.getDmiPropertiesPerCmHandleIdPerServiceName(yangModelCmHandles);
112
113         buildBulkResourceDataRequestAndSend(dataStoreName, resourceId, optionsParamInQuery,
114                 topicParamInQuery, requestId, dmiServiceNameCmHandlePropertiesMap);
115         return new ResponseEntity<>(HttpStatus.ACCEPTED);
116     }
117
118     /**
119      * This method fetches all the resource data from operational data store for given cm handle
120      * identifier using dmi client.
121      *
122      * @param dataStoreName  data store name
123      * @param cmHandleId network resource identifier
124      * @param requestId  requestId for async responses
125      * @return {@code ResponseEntity} response entity
126      */
127     public ResponseEntity<Object> getResourceDataFromDmi(final String dataStoreName,
128                                                          final String cmHandleId,
129                                                          final String requestId) {
130         final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
131         final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null,
132                 yangModelCmHandle);
133         final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, "/", null,
134                 null, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA));
135         final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
136         validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
137         return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody,
138                 READ);
139     }
140
141     /**
142      * This method creates the resource data from pass-through running data store for given cm handle
143      * identifier on given resource using dmi client.
144      *
145      * @param cmHandleId    network resource identifier
146      * @param resourceId  resource identifier
147      * @param operation   operation enum
148      * @param requestData the request data
149      * @param dataType    data type
150      * @return {@code ResponseEntity} response entity
151      */
152     public ResponseEntity<Object> writeResourceDataPassThroughRunningFromDmi(final String cmHandleId,
153                                                                              final String resourceId,
154                                                                              final OperationEnum operation,
155                                                                              final String requestData,
156                                                                              final String dataType) {
157         final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId);
158         final String jsonRequestBody = getDmiRequestBody(operation, null, requestData, dataType,
159                 yangModelCmHandle);
160         final String dmiUrl = getDmiRequestUrl(PASSTHROUGH_RUNNING.getValue(), cmHandleId, resourceId,
161                 null, null,
162                 yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA));
163         final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
164         validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
165         return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operation);
166     }
167
168     private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) {
169         return inventoryPersistence.getYangModelCmHandle(cmHandleId);
170     }
171
172     private String getDmiRequestBody(final OperationEnum operation, final String requestId, final String requestData,
173                                      final String dataType, final YangModelCmHandle yangModelCmHandle) {
174         final DmiRequestBody dmiRequestBody = DmiRequestBody.builder()
175                 .operation(operation)
176                 .requestId(requestId)
177                 .data(requestData)
178                 .dataType(dataType)
179                 .build();
180         dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties());
181         return jsonObjectMapper.asJsonString(dmiRequestBody);
182     }
183
184     private String getDmiBulkRequestBody(final OperationEnum operation,
185                                          final String requestId,
186                                          final String requestData) {
187         final DmiRequestBody dmiBulkRequestBody = DmiRequestBody.builder()
188                 .operation(operation)
189                 .requestId(requestId)
190                 .data(requestData)
191                 .build();
192         return jsonObjectMapper.asJsonString(dmiBulkRequestBody);
193     }
194
195     private String getDmiRequestUrl(final String dataStoreName,
196                                     final String cmHandleId,
197                                     final String resourceId,
198                                     final String optionsParamInQuery,
199                                     final String topicParamInQuery,
200                                     final String dmiServiceName) {
201         return dmiServiceUrlBuilder.getDmiDatastoreUrl(
202                 dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery,
203                         topicParamInQuery), dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName,
204                         cmHandleId));
205     }
206
207     private String getDmiServiceBulkRequestUrl(final String dataStoreName,
208                                                final String resourceId,
209                                                final String optionsParamInQuery,
210                                                final String topicParamInQuery,
211                                                final String dmiServiceName) {
212         return dmiServiceUrlBuilder.getBulkRequestUrl(
213                 dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery,
214                         topicParamInQuery), dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName,
215                         NO_CM_HANDLE_ID));
216     }
217
218     private void validateIfCmHandleStateReady(final YangModelCmHandle yangModelCmHandle,
219                                               final CmHandleState cmHandleState) {
220         if (cmHandleState != CmHandleState.READY) {
221             throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. "
222                     + "cm handle state is "
223                     + yangModelCmHandle.getCompositeState().getCmHandleState());
224         }
225     }
226
227     private void buildBulkResourceDataRequestAndSend(final String dataStoreName,
228                                                      final String resourceId,
229                                                      final String optionsParamInQuery,
230                                                      final String topicParamInQuery,
231                                                      final String requestId,
232                                                      final Map<String, Map<String, Map<String, String>>>
233                                                              dmiServiceNameCmHandlePropertiesMap) {
234         dmiServiceNameCmHandlePropertiesMap.entrySet().parallelStream().forEach(
235                 dmiServiceNameCmHandlePropertiesEntry -> {
236                     final String dmiBulkResourceDataUrl = getDmiServiceBulkRequestUrl(dataStoreName, resourceId,
237                             optionsParamInQuery, topicParamInQuery, dmiServiceNameCmHandlePropertiesEntry.getKey());
238                     final String jsonRequestBodyAsJsonString =
239                             jsonObjectMapper.asJsonString(dmiServiceNameCmHandlePropertiesEntry.getValue());
240                     final String jsonRequestBody
241                             = getDmiBulkRequestBody(READ, requestId, jsonRequestBodyAsJsonString);
242                     sendDmiResourceDataRequestToDmiService(dmiBulkResourceDataUrl, jsonRequestBody);
243                 });
244     }
245
246     private void sendDmiResourceDataRequestToDmiService(final String dmiBulkResourceDataUrl,
247                                                         final String dmiResourceDataRequestAsJsonString) {
248         TaskExecutor.executeTask(() ->
249                                 dmiRestClient.postOperationWithJsonData(dmiBulkResourceDataUrl,
250                                         dmiResourceDataRequestAsJsonString, READ),
251                         DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS)
252                 .whenCompleteAsync(this::handleTaskCompletion);
253     }
254
255     private void handleTaskCompletion(final Object response, final Throwable throwable) {
256         // TODO Need to publish an error response to client given topic.
257         //  Code should be implemented into https://jira.onap.org/browse/CPS-1558 (
258         //  NCMP : Handle non responding DMI-Plugin)
259     }
260 }