diff options
Diffstat (limited to 'cps-ncmp-rest')
12 files changed, 272 insertions, 104 deletions
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml index 7fc1063a12..2781f572f2 100644 --- a/cps-ncmp-rest/docs/openapi/components.yaml +++ b/cps-ncmp-rest/docs/openapi/components.yaml @@ -285,6 +285,43 @@ components: properties: state: $ref: '#/components/schemas/CmHandleCompositeState' + # Batch Request Schemas + ResourceDataBatchRequest: + type: object + title: get resource data for given array of operations + properties: + operations: + type: array + items: + type: object + $ref: '#/components/schemas/BatchOperationDefinition' + description: contains batch request details + BatchOperationDefinition: + required: + - operation + - datastore + - operationId + properties: + operation: + type: string + example: 'read' + operationId: + type: string + example: '12' + datastore: + type: string + example: 'ncmp-datastore:passthrough-operational' + options: + type: string + example: '(fields=schemas/schema)' + resourceIdentifier: + type: string + example: 'parent/child' + targetIds: + type: array + items: + type: string + example: [ "da310eecdb8d44c2acc0ddaae01174b1","c748c58f8e0b438f9fd1f28370b17d47" ] examples: dataSampleRequest: diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index 2b70d94892..957a3b8735 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp.yml @@ -202,17 +202,13 @@ getResourceDataForCmHandleBatch: description: This request will be handled asynchronously using messaging to the supplied topic. The rest response will be an acknowledge with a requestId to identify the relevant messages. operationId: getResourceDataForCmHandleBatch parameters: - - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - - $ref: 'components.yaml#/components/parameters/optionsParamInQuery' - $ref: 'components.yaml#/components/parameters/requiredTopicParamInQuery' - - $ref: 'components.yaml#/components/parameters/includeDescendantsOptionInQuery' requestBody: required: true content: application/json: schema: - type: object + $ref: 'components.yaml#/components/schemas/ResourceDataBatchRequest' responses: 200: description: OK diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml index 5b4c0d3496..b63b568234 100755 --- a/cps-ncmp-rest/docs/openapi/openapi.yml +++ b/cps-ncmp-rest/docs/openapi/openapi.yml @@ -34,7 +34,7 @@ paths: /v1/ch/{cm-handle}/data/ds/{datastore-name}: $ref: 'ncmp.yml#/resourceDataForCmHandle' - /v1/batch/data/ds/{datastore-name}: + /v1/data: $ref: 'ncmp.yml#/getResourceDataForCmHandleBatch' /v1/ch/{cm-handle}/data/ds/{datastore-name}/query: diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index fca1d6310f..1b78fa0343 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -23,10 +23,12 @@ package org.onap.cps.ncmp.rest.controller; -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.CREATE; -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.DELETE; -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.PATCH; -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.UPDATE; +import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL; +import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE; import java.util.Collection; import java.util.List; @@ -44,8 +46,10 @@ import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandl import org.onap.cps.ncmp.rest.controller.handlers.NcmpDatastoreRequestHandler; import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler; import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper; +import org.onap.cps.ncmp.rest.mapper.ResourceDataBatchRequestMapper; import org.onap.cps.ncmp.rest.model.CmHandlePublicProperties; import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters; +import org.onap.cps.ncmp.rest.model.ResourceDataBatchRequest; import org.onap.cps.ncmp.rest.model.RestModuleDefinition; import org.onap.cps.ncmp.rest.model.RestModuleReference; import org.onap.cps.ncmp.rest.model.RestOutputCmHandle; @@ -72,6 +76,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { private final CmHandleStateMapper cmHandleStateMapper; private final NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler; private final NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler; + private final ResourceDataBatchRequestMapper resourceDataBatchRequestMapper; /** * Get resource data from datastore. @@ -100,19 +105,11 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { } @Override - public ResponseEntity<Object> getResourceDataForCmHandleBatch(final String resourceIdentifier, - final String topicParamInQuery, - final String datastoreName, - final Object requestBody, - final String optionsParamInQuery, - final Boolean includeDescendants) { - - final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler = getNcmpDatastoreRequestHandler(datastoreName); - - final List<String> cmHandleIds = jsonObjectMapper.convertJsonString(jsonObjectMapper.asJsonString(requestBody), - List.class); - return ncmpDatastoreRequestHandler.executeRequest(datastoreName, cmHandleIds, resourceIdentifier, - optionsParamInQuery, topicParamInQuery, includeDescendants); + public ResponseEntity<Object> getResourceDataForCmHandleBatch(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest) { + return ncmpPassthroughResourceRequestHandler.executeRequest(topicParamInQuery, + resourceDataBatchRequestMapper.toResourceDataBatchRequest(resourceDataBatchRequest)); } /** @@ -134,7 +131,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String optionsParamInQuery, final String topicParamInQuery, final Boolean includeDescendants) { - validateDataStore(DatastoreType.OPERATIONAL, datastoreName); + validateDataStore(OPERATIONAL, datastoreName); return ncmpCachedResourceRequestHandler.executeRequest(cmHandle, cpsPath, includeDescendants); } @@ -156,7 +153,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final Object requestBody, final String contentType) { - validateDataStore(DatastoreType.PASSTHROUGH_RUNNING, datastoreName); + validateDataStore(PASSTHROUGH_RUNNING, datastoreName); final Object responseObject = networkCmProxyDataService .writeResourceDataPassThroughRunningForCmHandle( @@ -182,7 +179,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final Object requestBody, final String contentType) { - validateDataStore(DatastoreType.PASSTHROUGH_RUNNING, datastoreName); + validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, resourceIdentifier, CREATE, jsonObjectMapper.asJsonString(requestBody), contentType); @@ -206,7 +203,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String cmHandle, final Object requestBody, final String contentType) { - validateDataStore(DatastoreType.PASSTHROUGH_RUNNING, datastoreName); + validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, resourceIdentifier, UPDATE, jsonObjectMapper.asJsonString(requestBody), contentType); @@ -228,7 +225,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { final String resourceIdentifier, final String contentType) { - validateDataStore(DatastoreType.PASSTHROUGH_RUNNING, datastoreName); + validateDataStore(PASSTHROUGH_RUNNING, datastoreName); networkCmProxyDataService.writeResourceDataPassThroughRunningForCmHandle(cmHandle, resourceIdentifier, DELETE, NO_BODY, contentType); @@ -381,7 +378,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { } private NcmpDatastoreRequestHandler getNcmpDatastoreRequestHandler(final String datastoreName) { - if (DatastoreType.OPERATIONAL.equals(DatastoreType.fromDatastoreName(datastoreName))) { + if (OPERATIONAL.equals(DatastoreType.fromDatastoreName(datastoreName))) { return ncmpCachedResourceRequestHandler; } return ncmpPassthroughResourceRequestHandler; diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java index a32c462e76..a8ca13a752 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpDatastoreRequestHandler.java @@ -20,12 +20,19 @@ package org.onap.cps.ncmp.rest.controller.handlers; -import java.util.List; +import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; + import java.util.Map; import java.util.UUID; import java.util.function.Supplier; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; +import org.onap.cps.ncmp.api.impl.operations.DatastoreType; +import org.onap.cps.ncmp.api.impl.operations.OperationType; +import org.onap.cps.ncmp.api.models.ResourceDataBatchRequest; +import org.onap.cps.ncmp.rest.exceptions.OperationNotSupportedException; import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor; import org.onap.cps.ncmp.rest.util.TopicValidator; import org.springframework.beans.factory.annotation.Value; @@ -67,7 +74,7 @@ public class NcmpDatastoreRequestHandler implements TaskManagementDefaultHandler final boolean asyncResponseRequested = topicParamInQuery != null; if (asyncResponseRequested && notificationFeatureEnabled) { return executeAsyncTaskAndGetResponseEntity(datastoreName, cmHandleId, resourceIdentifier, - optionsParamInQuery, topicParamInQuery, includeDescendants, false); + optionsParamInQuery, topicParamInQuery, includeDescendants); } if (asyncResponseRequested) { @@ -98,26 +105,21 @@ public class NcmpDatastoreRequestHandler implements TaskManagementDefaultHandler } /** - * Executes synchronous/asynchronous request for batch of cm handles. + * Executes asynchronous request for batch of cm handles to resource data. * - * @param datastoreName the name of the datastore - * @param cmHandleIds list of cm handles - * @param resourceIdentifier the resource identifier - * @param optionsParamInQuery the options param in query - * @param topicParamInQuery the topic param in query - * @param includeDescendants whether to include descendants or not + * @param topicParamInQuery the topic param in query + * @param resourceDataBatchRequest batch request details for resource data * @return the response entity */ - public ResponseEntity<Object> executeRequest(final String datastoreName, - final List<String> cmHandleIds, - final String resourceIdentifier, - final String optionsParamInQuery, - final String topicParamInQuery, - final boolean includeDescendants) { - - return executeAsyncTaskAndGetResponseEntity(datastoreName, cmHandleIds, resourceIdentifier, optionsParamInQuery, - topicParamInQuery, includeDescendants, true); - + public ResponseEntity<Object> executeRequest(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest) { + validateBatchRequest(topicParamInQuery, resourceDataBatchRequest); + if (!notificationFeatureEnabled) { + return ResponseEntity.ok(Map.of("status", + "Asynchronous request is unavailable as notification feature is currently disabled.")); + } + return getRequestIdAndSendBatchRequestToDmiService(topicParamInQuery, resourceDataBatchRequest); } protected ResponseEntity<Object> executeTaskAsync(final String topicParamInQuery, @@ -127,7 +129,6 @@ public class NcmpDatastoreRequestHandler implements TaskManagementDefaultHandler TopicValidator.validateTopicName(topicParamInQuery); log.debug("Received Async request with id {}", requestId); cpsNcmpTaskExecutor.executeTask(taskSupplier, timeOutInMilliSeconds); - return ResponseEntity.ok(Map.of("requestId", requestId)); } @@ -136,25 +137,43 @@ public class NcmpDatastoreRequestHandler implements TaskManagementDefaultHandler } private ResponseEntity<Object> executeAsyncTaskAndGetResponseEntity(final String datastoreName, - final Object targetObject, + final String cmHandleId, final String resourceIdentifier, final String optionsParamInQuery, final String topicParamInQuery, - final boolean includeDescendants, - final boolean isBulkRequest) { + final boolean includeDescendants) { final String requestId = UUID.randomUUID().toString(); - final Supplier<Object> taskSupplier; - if (isBulkRequest) { - taskSupplier = getTaskSupplierForBulkRequest(datastoreName, (List<String>) targetObject, - resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, includeDescendants); - } else { - taskSupplier = getTaskSupplierForGetRequest(datastoreName, targetObject.toString(), resourceIdentifier, - optionsParamInQuery, topicParamInQuery, requestId, includeDescendants); - } + final Supplier<Object> taskSupplier = getTaskSupplierForGetRequest(datastoreName, cmHandleId, + resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId, includeDescendants); if (taskSupplier == NO_OBJECT_SUPPLIER) { return new ResponseEntity<>(Map.of("status", "Unable to execute request as " + "datastore is not implemented."), HttpStatus.NOT_IMPLEMENTED); } return executeTaskAsync(topicParamInQuery, requestId, taskSupplier); } + + private ResponseEntity<Object> getRequestIdAndSendBatchRequestToDmiService(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest) { + final String requestId = UUID.randomUUID().toString(); + sendResourceDataBatchRequestAsynchronously(topicParamInQuery, resourceDataBatchRequest, requestId); + return ResponseEntity.ok(Map.of("requestId", requestId)); + } + + private void validateBatchRequest(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest) { + TopicValidator.validateTopicName(topicParamInQuery); + resourceDataBatchRequest.getBatchOperationDefinitions().forEach(batchOperationDetail -> { + if (OperationType.fromOperationName(batchOperationDetail.getOperation()) != READ) { + throw new OperationNotSupportedException( + batchOperationDetail.getOperation() + " operation not yet supported for target ids :" + + batchOperationDetail.getCmHandleIds()); + } else if (DatastoreType.fromDatastoreName(batchOperationDetail.getDatastore()) == OPERATIONAL) { + throw new InvalidDatastoreException(batchOperationDetail.getDatastore() + + " datastore is not supported for target ids : " + + batchOperationDetail.getCmHandleIds()); + } + }); + } } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java index 18e5a9f5ac..5c35818a3a 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/NcmpPassthroughResourceRequestHandler.java @@ -20,10 +20,11 @@ package org.onap.cps.ncmp.rest.controller.handlers; -import java.util.List; import java.util.function.Supplier; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.models.ResourceDataBatchRequest; import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component @@ -56,17 +57,14 @@ public class NcmpPassthroughResourceRequestHandler extends NcmpDatastoreRequestH datastoreName, cmHandleId, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId); } + @Async @Override - public Supplier<Object> getTaskSupplierForBulkRequest(final String datastoreName, - final List<String> cmHandleIds, - final String resourceIdentifier, - final String optionsParamInQuery, - final String topicParamInQuery, - final String requestId, - final boolean includeDescendants) { + public void sendResourceDataBatchRequestAsynchronously(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest, + final String requestId) { + networkCmProxyDataService.requestResourceDataForCmHandleBatch(topicParamInQuery, resourceDataBatchRequest, + requestId); - return () -> networkCmProxyDataService.getResourceDataForCmHandleBatch( - datastoreName, cmHandleIds, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId); } - } diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/TaskManagementDefaultHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/TaskManagementDefaultHandler.java index 6d68f76802..937935bec4 100644 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/TaskManagementDefaultHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/handlers/TaskManagementDefaultHandler.java @@ -20,8 +20,8 @@ package org.onap.cps.ncmp.rest.controller.handlers; -import java.util.List; import java.util.function.Supplier; +import org.onap.cps.ncmp.api.models.ResourceDataBatchRequest; import org.onap.cps.spi.FetchDescendantsOption; public interface TaskManagementDefaultHandler { @@ -46,14 +46,10 @@ public interface TaskManagementDefaultHandler { return NO_OBJECT_SUPPLIER; } - default Supplier<Object> getTaskSupplierForBulkRequest(final String datastoreName, - final List<String> cmHandleIds, - final String resourceIdentifier, - final String optionsParamInQuery, - final String topicParamInQuery, - final String requestId, - final boolean includeDescendant) { - return NO_OBJECT_SUPPLIER; + default void sendResourceDataBatchRequestAsynchronously(final String topicParamInQuery, + final ResourceDataBatchRequest + resourceDataBatchRequest, + final String requestId) { } static FetchDescendantsOption getFetchDescendantsOption(final boolean includeDescendants) { diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java index 5faeee69fc..f459acec25 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandler.java @@ -77,7 +77,7 @@ public class NetworkCmProxyRestExceptionHandler { return wrapDmiErrorResponse(HttpStatus.BAD_GATEWAY, httpClientRequestException); } - @ExceptionHandler({DmiRequestException.class, DataValidationException.class, + @ExceptionHandler({DmiRequestException.class, DataValidationException.class, OperationNotSupportedException.class, HttpMessageNotReadableException.class, InvalidTopicException.class, InvalidDatastoreException.class}) public static ResponseEntity<Object> handleDmiRequestExceptions(final Exception exception) { return buildErrorResponse(HttpStatus.BAD_REQUEST, exception); diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java new file mode 100644 index 0000000000..e1daf3df6f --- /dev/null +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/exceptions/OperationNotSupportedException.java @@ -0,0 +1,32 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.exceptions; + +public class OperationNotSupportedException extends RuntimeException { + /** + * Instantiates a new not implemented operation exception. + * + * @param message the message + */ + public OperationNotSupportedException(final String message) { + super(message); + } +} diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/ResourceDataBatchRequestMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/ResourceDataBatchRequestMapper.java new file mode 100644 index 0000000000..d045e31610 --- /dev/null +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/ResourceDataBatchRequestMapper.java @@ -0,0 +1,41 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.rest.mapper; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.NullValueCheckStrategy; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.onap.cps.ncmp.api.models.BatchOperationDefinition; +import org.onap.cps.ncmp.api.models.ResourceDataBatchRequest; + +@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT) +public interface ResourceDataBatchRequestMapper { + + @Mapping(source = "operations", target = "batchOperationDefinitions") + ResourceDataBatchRequest toResourceDataBatchRequest( + org.onap.cps.ncmp.rest.model.ResourceDataBatchRequest resourceDataBatchRequest); + + @Mapping(source = "targetIds", target = "cmHandleIds") + BatchOperationDefinition toBatchOperationDefinition( + org.onap.cps.ncmp.rest.model.BatchOperationDefinition batchOperationDefinition); +} diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index fb411c054a..31e83aa7a1 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -32,11 +32,14 @@ import org.onap.cps.ncmp.api.inventory.CmHandleState import org.onap.cps.ncmp.api.inventory.CompositeState import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import org.onap.cps.ncmp.api.inventory.LockReasonCategory +import org.onap.cps.ncmp.rest.model.BatchOperationDefinition import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper +import org.onap.cps.ncmp.rest.mapper.ResourceDataBatchRequestMapper +import org.onap.cps.ncmp.rest.model.ResourceDataBatchRequest import org.onap.cps.ncmp.rest.util.DeprecationHelper import org.onap.cps.spi.FetchDescendantsOption import org.onap.cps.spi.model.ModuleDefinition @@ -62,10 +65,10 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.CREATE -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.UPDATE -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.PATCH -import static org.onap.cps.ncmp.api.impl.operations.OperationEnum.DELETE +import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE +import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE +import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH +import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL @@ -98,6 +101,9 @@ class NetworkCmProxyControllerSpec extends Specification { CmHandleStateMapper cmHandleStateMapper = Mappers.getMapper(CmHandleStateMapper) @SpringBean + ResourceDataBatchRequestMapper resourceDataBatchRequestMapper = Mappers.getMapper(ResourceDataBatchRequestMapper) + + @SpringBean CpsNcmpTaskExecutor spiedCpsTaskExecutor = Spy() @SpringBean @@ -113,7 +119,6 @@ class NetworkCmProxyControllerSpec extends Specification { def ncmpBasePathV1 def requestBody = '{"some-key":"some-value"}' - def bulkRequestBody = '["testCmHandle"]' def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(OffsetDateTime.of(2022, 12, 31, 20, 30, 40, 1, ZoneOffset.UTC)) @@ -200,44 +205,69 @@ class NetworkCmProxyControllerSpec extends Specification { 'invalid non-empty topic value in url' | 'passthrough-operational' | '&topic=1_5_*_#' } - def 'Get (async) bulk resource data from dmi service.'() { - given: 'bulk resource data url' - def getUrl = "$ncmpBasePathV1/batch/data/ds/${datastore.datastoreName}" + - "?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=myTopic" + def 'Get (async) batch resource data from dmi service.'() { + given: 'batch resource data url' + def getUrl = "$ncmpBasePathV1/data?topic=my-topic-name" + def resourceDataBatchRequestJsonData = jsonObjectMapper.asJsonString( + getResourceDataBatchRequest("read", datastore.datastoreName)) + def expectedDmiResourceDataBatchRequest + = jsonObjectMapper.convertJsonString(resourceDataBatchRequestJsonData, org.onap.cps.ncmp.api.models.ResourceDataBatchRequest.class) when: 'post data resource request is performed' def response = mvc.perform( post(getUrl) .contentType(MediaType.APPLICATION_JSON) - .content(bulkRequestBody) + .content(resourceDataBatchRequestJsonData) ).andReturn().response then: 'response status is Ok' response.status == HttpStatus.OK.value() and: 'async request id is generated' assert response.contentAsString.contains("requestId") then: 'wait a little to allow execution of service method by task executor (on separate thread)' - Thread.sleep(100); + Thread.sleep(100) then: 'the service has been invoked with the correct parameters ' - 1 * mockNetworkCmProxyDataService.getResourceDataForCmHandleBatch(datastore.datastoreName, ['testCmHandle'], - 'parent/child', - '(a=1,b=2)', - 'myTopic', - _) + 1 * mockNetworkCmProxyDataService.requestResourceDataForCmHandleBatch('my-topic-name', expectedDmiResourceDataBatchRequest, _) where: 'the following data stores are used' datastore << [PASSTHROUGH_RUNNING, PASSTHROUGH_OPERATIONAL] } - def 'Get bulk resource data for non-supported #datastoreName from dmi service.'() { - given: 'bulk resource data url' - def getUrl = "$ncmpBasePathV1/batch/data/ds/ncmp-datastore:operational" + - "?resourceIdentifier=parent/child&options=(a=1,b=2)&topic=myTopic" + def 'Get batch resource data for #scenario from dmi service.'() { + given: 'batch resource data url' + def getUrl = "$ncmpBasePathV1/data?topic=my-topic-name" + def resourceDataBatchRequestJsonData = jsonObjectMapper.asJsonString( + getResourceDataBatchRequest(operation, datastore)) + when: 'post data resource request is performed' + def response = mvc.perform( + post(getUrl) + .contentType(MediaType.APPLICATION_JSON) + .content(resourceDataBatchRequestJsonData) + ).andReturn().response + then: 'response status is BAD_REQUEST' + response.status == HttpStatus.BAD_REQUEST.value() + where: 'the following parameters are used' + scenario | datastore | operation + 'non-supported datastoreName' | OPERATIONAL.datastoreName | 'read' + 'non-supported operation (passthrough-running)' | PASSTHROUGH_RUNNING.datastoreName | 'create' + 'non-supported operation (passthrough-operational)' | PASSTHROUGH_OPERATIONAL.datastoreName | 'create' + } + + def 'Get batch resource data when notification feature is disabled for datastore: #datastore.'() { + given: 'batch resource data url' + def getUrl = "$ncmpBasePathV1/data?topic=my-topic-name" + def resourceDataBatchRequestJsonData = jsonObjectMapper.asJsonString( + getResourceDataBatchRequest("read", datastore.datastoreName)) + ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = false when: 'post data resource request is performed' def response = mvc.perform( post(getUrl) .contentType(MediaType.APPLICATION_JSON) - .content(bulkRequestBody) + .content(resourceDataBatchRequestJsonData) ).andReturn().response - then: 'response status code is 501 not implemented' - response.status == HttpStatus.NOT_IMPLEMENTED.value() + then: 'response status is Ok' + response.status == HttpStatus.OK.value() + and: 'async request id is unavailable' + assert response.contentAsString == '{"status":"Asynchronous request is unavailable as notification feature is currently disabled."}' + where: 'the following data stores are used' + datastore << [PASSTHROUGH_RUNNING, PASSTHROUGH_OPERATIONAL] } def 'Query Resource Data from operational.'() { @@ -656,5 +686,23 @@ class NetworkCmProxyControllerSpec extends Specification { return assertContainsAll(response, expectedContent) } + def getResourceDataBatchRequest(operation, datastore) { + def resourceDataBatchRequest = new ResourceDataBatchRequest() + def batchOperationDefinitions = new ArrayList() + batchOperationDefinitions.add(getBatchOperationDefinition(operation, datastore)) + resourceDataBatchRequest.addOperationsItem(batchOperationDefinitions) + } + + def getBatchOperationDefinition(operation, datastore) { + def batchOperationDefinition = new BatchOperationDefinition() + batchOperationDefinition.setOperation(operation) + batchOperationDefinition.setOperationId("operational-12") + batchOperationDefinition.setDatastore(datastore) + batchOperationDefinition.setOptions("some option") + batchOperationDefinition.setResourceIdentifier("some resource identifier") + batchOperationDefinition.addTargetIdsItem("some-cm-handle") + return batchOperationDefinition + } + } diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy index f44d6c9907..a3afc5546f 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/exceptions/NetworkCmProxyRestExceptionHandlerSpec.groovy @@ -33,6 +33,7 @@ import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandl import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper +import org.onap.cps.ncmp.rest.mapper.ResourceDataBatchRequestMapper import org.onap.cps.ncmp.rest.util.DeprecationHelper import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.AlreadyDefinedExceptionBatch @@ -75,6 +76,9 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification { CmHandleStateMapper cmHandleStateMapper = Mappers.getMapper(CmHandleStateMapper) @SpringBean + ResourceDataBatchRequestMapper resourceDataBatchRequestMapper = Mappers.getMapper(ResourceDataBatchRequestMapper) + + @SpringBean CpsNcmpTaskExecutor stubbedCpsTaskExecutor = Stub() @SpringBean |