Merge "NCMP : Replacing the word 'Batch' as 'DataOperation'."
[cps.git] / cps-ncmp-rest / src / main / java / org / onap / cps / ncmp / rest / controller / handlers / NcmpDatastoreRequestHandler.java
1 /*
2  *  ============LICENSE_START=======================================================
3  *  Copyright (C) 2022-2023 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *  SPDX-License-Identifier: Apache-2.0
18  *  ============LICENSE_END=========================================================
19  */
20
21 package org.onap.cps.ncmp.rest.controller.handlers;
22
23 import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL;
24 import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ;
25
26 import java.util.Map;
27 import java.util.UUID;
28 import java.util.function.Supplier;
29 import lombok.RequiredArgsConstructor;
30 import lombok.extern.slf4j.Slf4j;
31 import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException;
32 import org.onap.cps.ncmp.api.impl.operations.DatastoreType;
33 import org.onap.cps.ncmp.api.impl.operations.OperationType;
34 import org.onap.cps.ncmp.api.models.DataOperationRequest;
35 import org.onap.cps.ncmp.rest.exceptions.OperationNotSupportedException;
36 import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor;
37 import org.onap.cps.ncmp.rest.util.TopicValidator;
38 import org.springframework.beans.factory.annotation.Value;
39 import org.springframework.http.HttpStatus;
40 import org.springframework.http.ResponseEntity;
41 import org.springframework.stereotype.Service;
42
43 @Slf4j
44 @Service
45 @RequiredArgsConstructor
46 public class NcmpDatastoreRequestHandler implements TaskManagementDefaultHandler {
47
48     @Value("${notification.async.executor.time-out-value-in-ms:2000}")
49     protected int timeOutInMilliSeconds;
50
51     @Value("${notification.enabled:true}")
52     protected boolean notificationFeatureEnabled;
53
54     private final CpsNcmpTaskExecutor cpsNcmpTaskExecutor;
55
56     /**
57      * Executes synchronous/asynchronous request for given cm handle.
58      *
59      * @param datastoreName       the name of the datastore
60      * @param cmHandleId          the cm handle
61      * @param resourceIdentifier  the resource identifier
62      * @param optionsParamInQuery the options param in query
63      * @param topicParamInQuery   the topic param in query
64      * @param includeDescendants  whether include descendants
65      * @return the response entity
66      */
67     public ResponseEntity<Object> executeRequest(final String datastoreName,
68                                                  final String cmHandleId,
69                                                  final String resourceIdentifier,
70                                                  final String optionsParamInQuery,
71                                                  final String topicParamInQuery,
72                                                  final boolean includeDescendants) {
73
74         final boolean asyncResponseRequested = topicParamInQuery != null;
75         if (asyncResponseRequested && notificationFeatureEnabled) {
76             return executeAsyncTaskAndGetResponseEntity(datastoreName, cmHandleId, resourceIdentifier,
77                 optionsParamInQuery, topicParamInQuery, includeDescendants);
78         }
79
80         if (asyncResponseRequested) {
81             log.warn("Asynchronous request is unavailable as notification feature is currently disabled, "
82                     + "will use synchronous operation.");
83         }
84         final Supplier<Object> taskSupplier = getTaskSupplierForGetRequest(datastoreName, cmHandleId,
85                 resourceIdentifier, optionsParamInQuery, NO_TOPIC, NO_REQUEST_ID, includeDescendants);
86         return executeTaskSync(taskSupplier);
87     }
88
89     /**
90      * Executes a synchronous request for given cm handle.
91      * Note. Currently only ncmp-datastore:operational supports query operations.
92      *
93      * @param cmHandleId         the cm handle
94      * @param resourceIdentifier the resource identifier
95      * @param includeDescendants whether include descendants
96      * @return the response entity
97      */
98     public ResponseEntity<Object> executeRequest(final String cmHandleId,
99                                                  final String resourceIdentifier,
100                                                  final boolean includeDescendants) {
101
102         final Supplier<Object> taskSupplier = getTaskSupplierForQueryRequest(cmHandleId, resourceIdentifier,
103                 includeDescendants);
104         return executeTaskSync(taskSupplier);
105     }
106
107     /**
108      * Executes asynchronous request for group of cm handles to resource data.
109      *
110      * @param topicParamInQuery        the topic param in query
111      * @param dataOperationRequest     data operation request details for resource data
112      * @return the response entity
113      */
114     public ResponseEntity<Object> executeRequest(final String topicParamInQuery,
115                                                  final DataOperationRequest
116                                                          dataOperationRequest) {
117         validateDataOperationRequest(topicParamInQuery, dataOperationRequest);
118         if (!notificationFeatureEnabled) {
119             return ResponseEntity.ok(Map.of("status",
120                     "Asynchronous request is unavailable as notification feature is currently disabled."));
121         }
122         return getRequestIdAndSendDataOperationRequestToDmiService(topicParamInQuery, dataOperationRequest);
123     }
124
125     protected ResponseEntity<Object> executeTaskAsync(final String topicParamInQuery,
126                                                       final String requestId,
127                                                       final Supplier<Object> taskSupplier) {
128
129         TopicValidator.validateTopicName(topicParamInQuery);
130         log.debug("Received Async request with id {}", requestId);
131         cpsNcmpTaskExecutor.executeTask(taskSupplier, timeOutInMilliSeconds);
132         return ResponseEntity.ok(Map.of("requestId", requestId));
133     }
134
135     protected ResponseEntity<Object> executeTaskSync(final Supplier<Object> taskSupplier) {
136         return ResponseEntity.ok(taskSupplier.get());
137     }
138
139     private ResponseEntity<Object> executeAsyncTaskAndGetResponseEntity(final String datastoreName,
140                                                                         final String cmHandleId,
141                                                                         final String resourceIdentifier,
142                                                                         final String optionsParamInQuery,
143                                                                         final String topicParamInQuery,
144                                                                         final boolean includeDescendants) {
145         final String requestId = UUID.randomUUID().toString();
146         final Supplier<Object> taskSupplier = getTaskSupplierForGetRequest(datastoreName, cmHandleId,
147                 resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, includeDescendants);
148         if (taskSupplier == NO_OBJECT_SUPPLIER) {
149             return new ResponseEntity<>(Map.of("status", "Unable to execute request as "
150                     + "datastore is not implemented."), HttpStatus.NOT_IMPLEMENTED);
151         }
152         return executeTaskAsync(topicParamInQuery, requestId, taskSupplier);
153     }
154
155     private ResponseEntity<Object> getRequestIdAndSendDataOperationRequestToDmiService(final String topicParamInQuery,
156                                                                                        final DataOperationRequest
157                                                                                        dataOperationRequest) {
158         final String requestId = UUID.randomUUID().toString();
159         sendDataOperationRequestAsynchronously(topicParamInQuery, dataOperationRequest, requestId);
160         return ResponseEntity.ok(Map.of("requestId", requestId));
161     }
162
163     private void validateDataOperationRequest(final String topicParamInQuery,
164                                               final DataOperationRequest
165                                               dataOperationRequest) {
166         TopicValidator.validateTopicName(topicParamInQuery);
167         dataOperationRequest.getDataOperationDefinitions().forEach(dataOperationDetail -> {
168             if (OperationType.fromOperationName(dataOperationDetail.getOperation()) != READ) {
169                 throw new OperationNotSupportedException(
170                         dataOperationDetail.getOperation() + " operation not yet supported for target ids :"
171                                 + dataOperationDetail.getCmHandleIds());
172             } else if (DatastoreType.fromDatastoreName(dataOperationDetail.getDatastore()) == OPERATIONAL) {
173                 throw new InvalidDatastoreException(dataOperationDetail.getDatastore()
174                         + " datastore is not supported for target ids : "
175                         + dataOperationDetail.getCmHandleIds());
176             }
177         });
178     }
179 }