X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ncmp-service%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fcps%2Fncmp%2Fapi%2Fimpl%2Foperations%2FDmiDataOperations.java;h=a77e78a2e2bf7b7bbdf012491055a2a1ce0456ae;hb=cf57145a5b92335d00a566005d709b9e46158382;hp=229d4fc91781452e3c4fccc1f5c0ac6f626c9d9c;hpb=e557338803286d8aaa0f877aa25d52d18735f309;p=cps.git diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java index 229d4fc91..a77e78a2e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2022 Nordix Foundation + * Copyright (C) 2021-2023 Nordix Foundation + * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,71 +16,141 @@ * limitations under the License. * * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= + * ============LICENSE_END========================================================= */ package org.onap.cps.ncmp.api.impl.operations; -import static org.onap.cps.ncmp.api.impl.operations.DmiOperations.DataStoreEnum.PASSTHROUGH_RUNNING; -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum; -import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.READ; -import static org.onap.cps.ncmp.api.impl.operations.RequiredDmiService.DATA; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.DMI_SERVICE_NOT_RESPONDING; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNABLE_TO_READ_RESOURCE_DATA; +import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING; +import static org.onap.cps.ncmp.api.impl.operations.OperationType.READ; +import io.micrometer.core.annotation.Timed; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.NcmpResponseStatus; import org.onap.cps.ncmp.api.impl.client.DmiRestClient; import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration; +import org.onap.cps.ncmp.api.impl.exception.HttpClientRequestException; +import org.onap.cps.ncmp.api.impl.executor.TaskExecutor; +import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; +import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.impl.utils.DmiServiceUrlBuilder; +import org.onap.cps.ncmp.api.impl.utils.data.operation.ResourceDataOperationRequestUtils; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.spi.exceptions.CpsException; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.util.UriComponentsBuilder; /** * Operations class for DMI data. */ @Component +@Slf4j public class DmiDataOperations extends DmiOperations { - /** - * Constructor for {@code DmiOperations}. This method also manipulates url properties. - * - * @param dmiRestClient {@code DmiRestClient} - */ - public DmiDataOperations(final YangModelCmHandleRetriever cmHandlePropertiesRetriever, + private static final long DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS = 30000L; + + public DmiDataOperations(final InventoryPersistence inventoryPersistence, final JsonObjectMapper jsonObjectMapper, final NcmpConfiguration.DmiProperties dmiProperties, - final DmiRestClient dmiRestClient) { - super(cmHandlePropertiesRetriever, jsonObjectMapper, dmiProperties, dmiRestClient); + final DmiRestClient dmiRestClient, + final DmiServiceUrlBuilder dmiServiceUrlBuilder) { + super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder); } /** * This method fetches the resource data from operational data store for given cm handle * identifier on given resource using dmi client. * - * @param cmHandleId network resource identifier - * @param resourceId resource identifier + * @param dataStoreName name of data store + * @param cmHandleId network resource identifier + * @param resourceId resource identifier * @param optionsParamInQuery options query - * @param acceptParamInHeader accept parameter - * @param dataStore data store enum + * @param topicParamInQuery topic name for (triggering) async responses + * @param requestId requestId for async responses + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ - public ResponseEntity getResourceDataFromDmi(final String cmHandleId, - final String resourceId, - final String optionsParamInQuery, - final String acceptParamInHeader, - final DataStoreEnum dataStore) { - final YangModelCmHandle yangModelCmHandle = - yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId); - final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() - .operation(READ) - .build(); - dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties()); - final String jsonBody = jsonObjectMapper.asJsonString(dmiRequestBody); + @Timed(value = "cps.ncmp.dmi.get", + description = "Time taken to fetch the resource data from operational data store for given cm handle " + + "identifier on given resource using dmi client") + public ResponseEntity getResourceDataFromDmi(final String dataStoreName, + final String cmHandleId, + final String resourceId, + final String optionsParamInQuery, + final String topicParamInQuery, + final String requestId, + final String authorization) { + final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); + final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); + validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); + final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, + yangModelCmHandle); + final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, resourceId, optionsParamInQuery, + topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization); + } + + /** + * This method fetches all the resource data from operational data store for given cm handle + * identifier using dmi client. + * + * @param dataStoreName data store name + * @param cmHandleId network resource identifier + * @param requestId requestId for async responses + * @return {@code ResponseEntity} response entity + */ + public ResponseEntity getResourceDataFromDmi(final String dataStoreName, + final String cmHandleId, + final String requestId) { + final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); + final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, + yangModelCmHandle); + final String dmiResourceDataUrl = getDmiRequestUrl(dataStoreName, cmHandleId, "/", + null, null, + yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); + validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); + return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null); + } + + /** + * This method requests the resource data by data store for given list of cm handles using dmi client. + * The data wil be returned as message on the topic specified. + * + * @param topicParamInQuery topic name for (triggering) async responses + * @param dataOperationRequest data operation request to execute operations + * @param requestId requestId for as a response + * @param authorization contents of Authorization header, or null if not present + */ + public void requestResourceDataFromDmi(final String topicParamInQuery, + final DataOperationRequest dataOperationRequest, + final String requestId, + final String authorization) { - final var dmiResourceDataUrl = getDmiDatastoreUrlWithOptions( - yangModelCmHandle.resolveDmiServiceName(DATA), cmHandleId, resourceId, - optionsParamInQuery, dataStore); - final var httpHeaders = prepareHeader(acceptParamInHeader); - return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonBody, httpHeaders); + final Set cmHandlesIds + = getDistinctCmHandleIdsFromDataOperationRequest(dataOperationRequest); + + final Collection yangModelCmHandles + = inventoryPersistence.getYangModelCmHandles(cmHandlesIds); + + final Map> operationsOutPerDmiServiceName + = ResourceDataOperationRequestUtils.processPerDefinitionInDataOperationsRequest(topicParamInQuery, + requestId, dataOperationRequest, yangModelCmHandles); + + buildDataOperationRequestUrlAndSendToDmiService(topicParamInQuery, requestId, operationsOutPerDmiServiceName, + authorization); } /** @@ -87,54 +158,139 @@ public class DmiDataOperations extends DmiOperations { * identifier on given resource using dmi client. * * @param cmHandleId network resource identifier - * @param resourceId resource identifier - * @param operation operation enum - * @param requestData the request data - * @param dataType data type + * @param resourceId resource identifier + * @param operationType operation enum + * @param requestData the request data + * @param dataType data type + * @param authorization contents of Authorization header, or null if not present * @return {@code ResponseEntity} response entity */ public ResponseEntity writeResourceDataPassThroughRunningFromDmi(final String cmHandleId, final String resourceId, - final OperationEnum operation, + final OperationType operationType, final String requestData, - final String dataType) { - final YangModelCmHandle yangModelCmHandle = - yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId); + final String dataType, + final String authorization) { + final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmHandleId); + final String jsonRequestBody = getDmiRequestBody(operationType, null, requestData, dataType, + yangModelCmHandle); + final String dmiUrl = getDmiRequestUrl(PASSTHROUGH_RUNNING.getDatastoreName(), cmHandleId, resourceId, + null, null, + yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA)); + final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState(); + validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState); + return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization); + } + + private YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { + return inventoryPersistence.getYangModelCmHandle(cmHandleId); + } + + private String getDmiRequestBody(final OperationType operationType, + final String requestId, + final String requestData, + final String dataType, + final YangModelCmHandle yangModelCmHandle) { final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() - .operation(operation) - .data(requestData) - .dataType(dataType) - .build(); + .operationType(operationType) + .requestId(requestId) + .data(requestData) + .dataType(dataType) + .build(); dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties()); - final String jsonBody = jsonObjectMapper.asJsonString(dmiRequestBody); - final String dmiUrl = - getResourceInDataStoreUrl(yangModelCmHandle.resolveDmiServiceName(DATA), - cmHandleId, resourceId, PASSTHROUGH_RUNNING); - return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonBody, new HttpHeaders()); + return jsonObjectMapper.asJsonString(dmiRequestBody); } - private String getResourceInDataStoreUrl(final String dmiServiceName, - final String cmHandleId, - final String resourceId, - final DataStoreEnum dataStoreEnum) { - return getCmHandleUrl(dmiServiceName, cmHandleId) - + "data" - + URL_SEPARATOR - + "ds" - + URL_SEPARATOR - + dataStoreEnum.getValue() - + "?resourceIdentifier=" - + resourceId; + private String getDmiRequestUrl(final String dataStoreName, + final String cmHandleId, + final String resourceId, + final String optionsParamInQuery, + final String topicParamInQuery, + final String dmiServiceName) { + return dmiServiceUrlBuilder.getDmiDatastoreUrl( + dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery, + topicParamInQuery), dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName, + cmHandleId)); } - private String getDmiDatastoreUrlWithOptions(final String dmiServiceName, - final String cmHandleId, - final String resourceId, - final String optionsParamInQuery, - final DataStoreEnum dataStoreEnum) { - final String resourceInDataStoreUrl = getResourceInDataStoreUrl(dmiServiceName, - cmHandleId, resourceId, dataStoreEnum); - return appendOptionsQuery(resourceInDataStoreUrl, optionsParamInQuery); + private String getDmiServiceDataOperationRequestUrl(final String dmiServiceName, + final String topicParamInQuery, + final String requestId) { + final MultiValueMap dataOperationRequestQueryParams = dmiServiceUrlBuilder + .getDataOperationRequestQueryParams(topicParamInQuery, requestId); + return dmiServiceUrlBuilder.getDataOperationRequestUrl(dataOperationRequestQueryParams, + dmiServiceUrlBuilder.populateDataOperationRequestUriVariables(dmiServiceName)); } + private void validateIfCmHandleStateReady(final YangModelCmHandle yangModelCmHandle, + final CmHandleState cmHandleState) { + if (cmHandleState != CmHandleState.READY) { + throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. " + + "cm handle state is " + + yangModelCmHandle.getCompositeState().getCmHandleState()); + } + } + + private static Set getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest + dataOperationRequest) { + return dataOperationRequest.getDataOperationDefinitions().stream() + .flatMap(dataOperationDefinition -> + dataOperationDefinition.getCmHandleIds().stream()).collect(Collectors.toSet()); + } + + private void buildDataOperationRequestUrlAndSendToDmiService(final String topicParamInQuery, + final String requestId, + final Map> + groupsOutPerDmiServiceName, + final String authorization) { + + groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> { + final String dmiDataOperationResourceUrl = + getDmiServiceDataOperationRequestUrl(dmiServiceName, topicParamInQuery, requestId); + sendDataOperationRequestToDmiService(dmiDataOperationResourceUrl, dmiDataOperationRequestBodies, + authorization); + }); + } + + private void sendDataOperationRequestToDmiService(final String dataOperationResourceUrl, + final List dmiDataOperationRequestBodies, + final String authorization) { + final DmiDataOperationRequest dmiDataOperationRequest = DmiDataOperationRequest.builder() + .operations(dmiDataOperationRequestBodies).build(); + final String dmiDataOperationRequestAsJsonString = + jsonObjectMapper.asJsonString(dmiDataOperationRequest); + TaskExecutor.executeTask(() -> dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, + dmiDataOperationRequestAsJsonString, READ, authorization), + DEFAULT_ASYNC_TASK_EXECUTOR_TIMEOUT_IN_MILLISECONDS) + .whenCompleteAsync((response, throwable) -> handleTaskCompletionException(throwable, + dataOperationResourceUrl, dmiDataOperationRequestBodies)); + } + + private void handleTaskCompletionException(final Throwable throwable, + final String dataOperationResourceUrl, + final List dmiDataOperationRequestBodies) { + if (throwable != null) { + final MultiValueMap dataOperationResourceUrlParameters = + UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams(); + final String topicName = dataOperationResourceUrlParameters.get("topic").get(0); + final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0); + + final MultiValueMap>> + cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>(); + + dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> { + final List cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream() + .map(CmHandle::getId).toList(); + if (throwable.getCause() instanceof HttpClientRequestException) { + cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, + Map.of(UNABLE_TO_READ_RESOURCE_DATA, cmHandleIds)); + } else { + cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody, + Map.of(DMI_SERVICE_NOT_RESPONDING, cmHandleIds)); + } + }); + ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId, + cmHandleIdsPerResponseCodesPerOperation); + } + } }