Merge "CPS-2187 - #6 Add module Set Tag to ncmp (single cm handle) data request to...
authorToine Siebelink <toine.siebelink@est.tech>
Mon, 20 May 2024 08:46:02 +0000 (08:46 +0000)
committerGerrit Code Review <gerrit@onap.org>
Mon, 20 May 2024 08:46:02 +0000 (08:46 +0000)
1  2 
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilder.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy

@@@ -21,6 -21,8 +21,6 @@@
  
  package org.onap.cps.ncmp.api.impl.operations;
  
 -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;
  
@@@ -33,8 -35,8 +33,8 @@@ 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.config.DmiWebClientConfiguration.DmiProperties;
 +import org.onap.cps.ncmp.api.impl.exception.DmiClientRequestException;
  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;
@@@ -59,7 -61,7 +59,7 @@@ public class DmiDataOperations extends 
  
      public DmiDataOperations(final InventoryPersistence inventoryPersistence,
                               final JsonObjectMapper jsonObjectMapper,
 -                             final NcmpConfiguration.DmiProperties dmiProperties,
 +                             final DmiProperties dmiProperties,
                               final DmiRestClient dmiRestClient,
                               final DmiServiceUrlBuilder dmiServiceUrlBuilder) {
          super(inventoryPersistence, jsonObjectMapper, dmiProperties, dmiRestClient, dmiServiceUrlBuilder);
          final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
          validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
          final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
-         final String dmiResourceDataUrl = getDmiRequestUrl(cmResourceAddress.datastoreName(),
-             cmResourceAddress.cmHandleId(), cmResourceAddress.resourceIdentifier(), optionsParamInQuery,
-                 topicParamInQuery, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA));
+         final MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap(
+                 cmResourceAddress.resourceIdentifier(), optionsParamInQuery,
+                 topicParamInQuery, yangModelCmHandle.getModuleSetTag());
+         final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(cmResourceAddress.datastoreName(),
+                 yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmResourceAddress.cmHandleId());
+         final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
          return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, authorization);
      }
  
          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 MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap("/", null,
+                 null, yangModelCmHandle.getModuleSetTag());
+         final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(dataStoreName,
+                 yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId);
+         final String dmiResourceDataUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
          final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
          validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
          return dmiRestClient.postOperationWithJsonData(dmiResourceDataUrl, jsonRequestBody, READ, null);
          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 MultiValueMap<String, String> uriQueryParamsMap = getUriQueryParamsMap(resourceId, null,
+                 null, yangModelCmHandle.getModuleSetTag());
+         final Map<String, Object> uriVariableParamsMap = getUriVariableParamsMap(PASSTHROUGH_RUNNING.getDatastoreName(),
+                 yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), cmHandleId);
+         final String dmiUrl = getDmiRequestUrl(uriQueryParamsMap, uriVariableParamsMap);
          final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
          validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
          return dmiRestClient.postOperationWithJsonData(dmiUrl, jsonRequestBody, operationType, authorization);
          return jsonObjectMapper.asJsonString(dmiRequestBody);
      }
  
-     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 getDmiRequestUrl(final MultiValueMap<String, String> uriQueryParamsMap,
+                                     final Map<String, Object> uriVariableParamsMap) {
+         return dmiServiceUrlBuilder.getDmiDatastoreUrl(uriQueryParamsMap, uriVariableParamsMap);
+     }
+     private MultiValueMap<String, String> getUriQueryParamsMap(final String resourceId,
+                                                                final String optionsParamInQuery,
+                                                                final String topicParamInQuery,
+                                                                final String moduleSetTagParamInQuery) {
+         return dmiServiceUrlBuilder.populateQueryParams(resourceId, optionsParamInQuery,
+                 topicParamInQuery, moduleSetTagParamInQuery);
+     }
+     private Map<String, Object> getUriVariableParamsMap(final String dataStoreName,
+                                                         final String dmiServiceName,
+                                                         final String cmHandleId) {
+         return dmiServiceUrlBuilder.populateUriVariables(dataStoreName, dmiServiceName, cmHandleId);
      }
  
      private String getDmiServiceDataOperationRequestUrl(final String dmiServiceName,
      }
  
      private static Set<String> getDistinctCmHandleIdsFromDataOperationRequest(final DataOperationRequest
 -                                                                              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<String, List<DmiDataOperation>>
 -                                                                groupsOutPerDmiServiceName,
 +                                                                         groupsOutPerDmiServiceName,
                                                                   final String authorization) {
  
          groupsOutPerDmiServiceName.forEach((dmiServiceName, dmiDataOperationRequestBodies) -> {
          try {
              dmiRestClient.postOperationWithJsonData(dataOperationResourceUrl, dmiDataOperationRequestAsJsonString, READ,
                      authorization);
 -        } catch (final Exception exception) {
 -            handleTaskCompletionException(exception, dataOperationResourceUrl, dmiDataOperationRequestBodies);
 +        } catch (final DmiClientRequestException e) {
 +            handleTaskCompletionException(e, dataOperationResourceUrl, dmiDataOperationRequestBodies);
          }
      }
  
 -    private void handleTaskCompletionException(final Throwable throwable,
 +    private void handleTaskCompletionException(final DmiClientRequestException dmiClientRequestException,
                                                 final String dataOperationResourceUrl,
                                                 final List<DmiDataOperation> dmiDataOperationRequestBodies) {
 -        if (throwable != null) {
 -            final MultiValueMap<String, String> dataOperationResourceUrlParameters =
 -                    UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams();
 -            final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
 -            final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
 -
 -            final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
 -                    cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
 -
 -            dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> {
 -                final List<String> 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);
 -        }
 +        final MultiValueMap<String, String> dataOperationResourceUrlParameters =
 +                UriComponentsBuilder.fromUriString(dataOperationResourceUrl).build().getQueryParams();
 +        final String topicName = dataOperationResourceUrlParameters.get("topic").get(0);
 +        final String requestId = dataOperationResourceUrlParameters.get("requestId").get(0);
 +
 +        final MultiValueMap<DmiDataOperation, Map<NcmpResponseStatus, List<String>>>
 +                cmHandleIdsPerResponseCodesPerOperation = new LinkedMultiValueMap<>();
 +
 +        dmiDataOperationRequestBodies.forEach(dmiDataOperationRequestBody -> {
 +            final List<String> cmHandleIds = dmiDataOperationRequestBody.getCmHandles().stream()
 +                    .map(CmHandle::getId).toList();
 +            cmHandleIdsPerResponseCodesPerOperation.add(dmiDataOperationRequestBody,
 +                    Map.of(dmiClientRequestException.getNcmpResponseStatus(), cmHandleIds));
 +        });
 +        ResourceDataOperationRequestUtils.publishErrorMessageToClientTopic(topicName, requestId,
 +                cmHandleIdsPerResponseCodesPerOperation);
      }
  }
  
  package org.onap.cps.ncmp.api.impl.utils;
  
 +import java.net.URLEncoder;
 +import java.nio.charset.StandardCharsets;
  import java.util.HashMap;
  import java.util.Map;
  import lombok.RequiredArgsConstructor;
  import org.apache.logging.log4j.util.Strings;
  import org.apache.logging.log4j.util.TriConsumer;
 -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration;
 +import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration.DmiProperties;
  import org.onap.cps.spi.utils.CpsValidator;
  import org.springframework.stereotype.Component;
  import org.springframework.util.LinkedMultiValueMap;
@@@ -37,7 -35,8 +37,7 @@@ import org.springframework.web.util.Uri
  @Component
  @RequiredArgsConstructor
  public class DmiServiceUrlBuilder {
 -
 -    private final NcmpConfiguration.DmiProperties dmiProperties;
 +    private final DmiProperties dmiProperties;
      private final CpsValidator cpsValidator;
  
      /**
       * This method is used to populate map from query params.
       *
       * @param resourceId          unique id of response for valid topic
-      * @param optionsParamInQuery options into url param
-      * @param topicParamInQuery   topic into url param
+      * @param optionsParamInQuery options as provided by client
+      * @param topicParamInQuery   topic as provided by client
+      * @param moduleSetTag   module set tag associated with the given cm handle
       * @return all valid query params as map
       */
      public MultiValueMap<String, String> populateQueryParams(final String resourceId,
                                                               final String optionsParamInQuery,
-                                                              final String topicParamInQuery) {
+                                                              final String topicParamInQuery,
+                                                              final String moduleSetTag) {
          final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
 -        getQueryParamConsumer().accept("resourceIdentifier",
 -                resourceId, queryParams);
 +        getQueryParamConsumer().accept("resourceIdentifier", resourceId, queryParams);
          getQueryParamConsumer().accept("options", optionsParamInQuery, queryParams);
          if (Strings.isNotEmpty(topicParamInQuery)) {
              getQueryParamConsumer().accept("topic", topicParamInQuery, queryParams);
          }
+         if (Strings.isNotEmpty(moduleSetTag)) {
+             getQueryParamConsumer().accept("moduleSetTag", moduleSetTag, queryParams);
+         }
          return queryParams;
      }
  
      private TriConsumer<String, String, MultiValueMap<String, String>> getQueryParamConsumer() {
          return (paramName, paramValue, paramMap) -> {
              if (Strings.isNotEmpty(paramValue)) {
 -                paramMap.add(paramName, paramValue);
 +                paramMap.add(paramName, URLEncoder.encode(paramValue, StandardCharsets.UTF_8));
              }
          };
      }
@@@ -22,10 -22,10 +22,10 @@@ package org.onap.cps.ncmp.api.impl.util
  
  import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
  
 +import org.onap.cps.ncmp.api.impl.config.DmiWebClientConfiguration
  import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService
  import org.onap.cps.spi.utils.CpsValidator
  import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
 -import org.onap.cps.ncmp.api.impl.config.NcmpConfiguration
  import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
  import spock.lang.Specification
  
@@@ -34,7 -34,7 +34,7 @@@ class DmiServiceUrlBuilderSpec extends 
      static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
          'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'my-module-set-tag', 'my-alternate-id', 'my-data-producer-identifier')
  
 -    NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
 +    DmiWebClientConfiguration.DmiProperties dmiProperties = new DmiWebClientConfiguration.DmiProperties()
  
      def mockCpsValidator = Mock(CpsValidator)
  
          given: 'uri variables'
              def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
          and: 'query params'
-             def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic)
+             def uriQueries = objectUnderTest.populateQueryParams(resourceId, 'optionsParamInQuery', topic, moduleSetTag)
          when: 'a dmi datastore service url is generated'
              def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
          then: 'service url is generated as expected'
              assert dmiServiceUrl == expectedDmiServiceUrl
          where: 'the following parameters are used'
-             scenario                       | topic               | resourceId   || expectedDmiServiceUrl
-             'With valid resourceId'        | 'topicParamInQuery' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
-             'With Empty resourceId'        | 'topicParamInQuery' | ''           || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?options=optionsParamInQuery&topic=topicParamInQuery'
-             'With Empty dmi base path'     | 'topicParamInQuery' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
-             'With Empty topicParamInQuery' | ''                  | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery'
+             scenario                       | topic               | moduleSetTag | resourceId   || expectedDmiServiceUrl
+             'With valid resourceId'        | 'topicParamInQuery' | ''                | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+             'With Empty resourceId'        | 'topicParamInQuery' | ''                | ''           || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?options=optionsParamInQuery&topic=topicParamInQuery'
+             'With valid moduleSetTag'      | 'topicParamInQuery' | 'module-set-tag1' | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery&moduleSetTag=module-set-tag1'
+             'With Empty moduleSetTag'      | 'topicParamInQuery' | ''                | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+             'With Empty dmi base path'     | 'topicParamInQuery' | ''                | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery&topic=topicParamInQuery'
+             'With Empty topicParamInQuery' | ''                  | ''                | 'resourceId' || 'dmiServiceName/dmi/v1/ch/cmHandle/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=resourceId&options=optionsParamInQuery'
      }
  
      def 'Populate dmi data store url #scenario.'() {
@@@ -66,7 -68,7 +68,7 @@@
              dmiProperties.dmiBasePath = dmiBasePath
              def uriVars = objectUnderTest.populateUriVariables(PASSTHROUGH_RUNNING.datastoreName, yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA), 'cmHandle')
          and: 'null query params'
-             def uriQueries = objectUnderTest.populateQueryParams(null, null, null)
+             def uriQueries = objectUnderTest.populateQueryParams(null, null, null, null)
          when: 'a dmi datastore service url is generated'
              def dmiServiceUrl = objectUnderTest.getDmiDatastoreUrl(uriQueries, uriVars)
          then: 'the created dmi service url matches the expected'
@@@ -85,7 -87,7 +87,7 @@@
          when: 'a URL is created'
              def result = objectUnderTest.getDataOperationRequestUrl(batchRequestQueryParams, batchRequestUriVariables)
          then: 'it is formed correctly'
 -            assert result.toString() == 'some-service/testBase/v1/data?topic=some topic&requestId=some id'
 +            assert result.toString() == 'some-service/testBase/v1/data?topic=some+topic&requestId=some+id'
      }
  
      def 'Populate batch uri variables.'() {