Support alternate Id interface for CPS-E-05 #2

- Supports Alternate Ids for getResourceDataForCmHandle

Issue-Id: CPS-2279
Change-Id: I1f145308cec5b545fab2d5c96efbc00fc3a110f4
Signed-off-by: seanbeirne <sean.beirne@est.tech>
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 a482cf5..af5f226 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
@@ -86,7 +86,7 @@
      * Get resource data from datastore.
      *
      * @param datastoreName        name of the datastore
-     * @param cmHandle             cm handle identifier
+     * @param cmHandleReference    cm handle or alternate id identifier
      * @param resourceIdentifier   resource identifier
      * @param optionsParamInQuery  options query parameter
      * @param topicParamInQuery    topic query parameter
@@ -97,15 +97,16 @@
     @Override
     @Timed(value = "cps.ncmp.controller.get", description = "Time taken to get resource data from datastore")
     public ResponseEntity<Object> getResourceDataForCmHandle(final String datastoreName,
-                                                             final String cmHandle,
+                                                             final String cmHandleReference,
                                                              final String resourceIdentifier,
                                                              final String optionsParamInQuery,
                                                              final String topicParamInQuery,
                                                              final Boolean includeDescendants,
                                                              final String authorization) {
-        final CmResourceAddress cmResourceAddress = new CmResourceAddress(datastoreName, cmHandle, resourceIdentifier);
+        final CmResourceAddress cmResourceAddress = new CmResourceAddress(datastoreName, cmHandleReference,
+            resourceIdentifier);
         final Object result = networkCmProxyFacade.getResourceDataForCmHandle(cmResourceAddress, optionsParamInQuery,
-                                                               topicParamInQuery, includeDescendants, authorization);
+            topicParamInQuery, includeDescendants, authorization);
         return ResponseEntity.ok(result);
     }
 
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 f7d80ad..9f5331d 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
@@ -41,6 +41,7 @@
 import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState
 import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
 import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
 import org.onap.cps.ncmp.rest.model.DataOperationDefinition
 import org.onap.cps.ncmp.rest.model.DataOperationRequest
 import org.onap.cps.ncmp.rest.util.CmHandleStateMapper
@@ -94,6 +95,9 @@
     NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
 
     @SpringBean
+    AlternateIdMatcher mockalternateIdMatcher = Mock()
+
+    @SpringBean
     ObjectMapper objectMapper = new ObjectMapper()
 
     @SpringBean
@@ -136,12 +140,10 @@
     def 'Get Resource Data from pass-through operational.'() {
         given: 'resource data url'
             def getUrl = "$ncmpBasePathV1/ch/testCmHandle/data/ds/ncmp-datastore:passthrough-operational?resourceIdentifier=parent/child&options=(a=1,b=2)"
-        and: 'the expected cm resource address'
-            def expectedCmResourceAddress = new CmResourceAddress(PASSTHROUGH_OPERATIONAL.datastoreName, 'testCmHandle', 'parent/child')
         when: 'get data resource request is performed'
             def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
         then: 'the NCMP data service is called with correct parameters'
-            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(expectedCmResourceAddress, '(a=1,b=2)', NO_TOPIC, false, NO_AUTH_HEADER) >> Mono.just(new ResponseEntity<Object>(HttpStatus.OK))
+            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, '(a=1,b=2)', NO_TOPIC, false, NO_AUTH_HEADER) >> Mono.just(new ResponseEntity<Object>(HttpStatus.OK))
         and: 'response status is Ok'
             assert response.status == HttpStatus.OK.value()
     }
@@ -150,11 +152,10 @@
         given: 'resource data url'
             def getUrl = "$ncmpBasePathV1/ch/h123/data/ds/ncmp-datastore:operational?resourceIdentifier=parent/child${additionalUrlParam}"
         and: 'the expected cm resource address'
-            def expectedCmResourceAddress = new CmResourceAddress('ncmp-datastore:operational', 'h123', 'parent/child')
         when: 'get data resource request is performed'
             def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
         then: 'the NCMP data service is called with correct parameters'
-            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(expectedCmResourceAddress, NO_OPTIONS, NO_TOPIC, expectedIncludeDescendants, NO_AUTH_HEADER)
+            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, NO_OPTIONS, NO_TOPIC, expectedIncludeDescendants, NO_AUTH_HEADER)
         and: 'response status is OK'
             assert response.status == HttpStatus.OK.value()
         where: 'the following parameters are used'
@@ -206,8 +207,7 @@
         given: 'resource data url'
             def getUrl = "$ncmpBasePathV1/ch/ch-1/data/ds/ncmp-datastore:passthrough-running?resourceIdentifier=$resourceIdentifier&options=(a=1)"
         and: 'ncmp service returns json object'
-            def expectedCmResourceAddress = new CmResourceAddress(PASSTHROUGH_RUNNING.datastoreName, 'ch-1', resourceIdentifier)
-            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(expectedCmResourceAddress, '(a=1)', NO_TOPIC, false, NO_AUTH_HEADER)
+            1 * mockNetworkCmProxyFacade.getResourceDataForCmHandle(_, '(a=1)', NO_TOPIC, false, NO_AUTH_HEADER)
                     >> new ResponseEntity<Object>('{valid-json}', HttpStatus.OK)
         when: 'get data resource request is performed'
             def response = mvc.perform(get(getUrl).contentType(MediaType.APPLICATION_JSON)).andReturn().response
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
index 97f3e03..e6288ff 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -34,6 +34,7 @@
 import org.onap.cps.ncmp.impl.data.NcmpCachedResourceRequestHandler
 import org.onap.cps.ncmp.impl.data.NcmpPassthroughResourceRequestHandler
 import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence
 import org.onap.cps.ncmp.rest.util.CmHandleStateMapper
 import org.onap.cps.ncmp.rest.util.DataOperationRequestMapper
 import org.onap.cps.ncmp.rest.util.DeprecationHelper
@@ -77,6 +78,9 @@
     NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
 
     @SpringBean
+    InventoryPersistence mockInventoryPersistence = Mock()
+
+    @SpringBean
     JsonObjectMapper stubbedJsonObjectMapper = Stub()
 
     @SpringBean
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java
index e93aa4c..98a343b 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/data/models/CmResourceAddress.java
@@ -20,6 +20,22 @@
 
 package org.onap.cps.ncmp.api.data.models;
 
-public record CmResourceAddress(String datastoreName, String cmHandleId, String resourceIdentifier) {
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.ncmp.config.CpsApplicationContext;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
 
+@Getter
+@RequiredArgsConstructor
+public class CmResourceAddress {
+
+    private final String datastoreName;
+    @Getter(AccessLevel.NONE)
+    private final String cmHandleReference;
+    private final String resourceIdentifier;
+
+    public String getResolvedCmHandleId() {
+        return CpsApplicationContext.getCpsBean(AlternateIdMatcher.class).getCmHandleId(cmHandleReference);
+    }
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java
index 4cbf9d4..90783a8 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java
@@ -92,12 +92,12 @@
                                                                final String topic,
                                                                final String requestId,
                                                                final String authorization) {
-        final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.cmHandleId());
+        final YangModelCmHandle yangModelCmHandle = getYangModelCmHandle(cmResourceAddress.getResolvedCmHandleId());
         final CmHandleState cmHandleState = yangModelCmHandle.getCompositeState().getCmHandleState();
         validateIfCmHandleStateReady(yangModelCmHandle, cmHandleState);
         final String jsonRequestBody = getDmiRequestBody(READ, requestId, null, null, yangModelCmHandle);
         final UrlTemplateParameters urlTemplateParameters = getUrlTemplateParameters(cmResourceAddress
-                .datastoreName(), yangModelCmHandle, cmResourceAddress.resourceIdentifier(), options, topic);
+                .getDatastoreName(), yangModelCmHandle, cmResourceAddress.getResourceIdentifier(), options, topic);
         return dmiRestClient.asynchronousPostOperationWithJsonData(DATA, urlTemplateParameters, jsonRequestBody, READ,
                 authorization);
     }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java
index bff2f63..01022cc 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandler.java
@@ -61,9 +61,9 @@
                                                       final String authorization) {
         final FetchDescendantsOption fetchDescendantsOption = getFetchDescendantsOption(includeDescendants);
 
-        final DataNode dataNode = cpsDataService.getDataNodes(cmResourceAddress.datastoreName(),
-            cmResourceAddress.cmHandleId(),
-            cmResourceAddress.resourceIdentifier(),
+        final DataNode dataNode = cpsDataService.getDataNodes(cmResourceAddress.getDatastoreName(),
+            cmResourceAddress.getResolvedCmHandleId(),
+            cmResourceAddress.getResourceIdentifier(),
             fetchDescendantsOption).iterator().next();
         return Mono.justOrEmpty(dataNode);
     }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java
index 5039157..b97088a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacade.java
@@ -33,6 +33,7 @@
 import org.onap.cps.ncmp.api.data.models.DataOperationRequest;
 import org.onap.cps.ncmp.api.data.models.DatastoreType;
 import org.onap.cps.ncmp.api.data.models.OperationType;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
 import org.onap.cps.spi.model.DataNode;
 import org.springframework.stereotype.Service;
 
@@ -44,34 +45,35 @@
     private final NcmpCachedResourceRequestHandler ncmpCachedResourceRequestHandler;
     private final NcmpPassthroughResourceRequestHandler ncmpPassthroughResourceRequestHandler;
     private final DmiDataOperations dmiDataOperations;
+    private final AlternateIdMatcher alternateIdMatcher;
 
     /**
      * Fetches resource data for a given data store using DMI (Data Management Interface).
      * This method retrieves data based on the provided CmResourceAddress and additional query parameters.
      * It supports asynchronous processing and handles authorization if required.
      *
-     * @param cmResourceAddress  The target data store, including the CM handle and resource identifier.
-     *                           This parameter must not be null.
-     * @param options            Additional query parameters that may influence the data retrieval process,
-     *                           such as filters or limits. This parameter can be null.
-     * @param topic              The topic name for triggering asynchronous responses. If specified,
-     *                           the response will be sent to this topic. This parameter can be null.
-     * @param includeDescendants include (all) descendants or not
-     * @param authorization      The contents of the Authorization header. This parameter can be null
-     *                           if authorization is not required.
+     * @param cmResourceAddress     The target data store, including the CM handle and resource identifier.
+     *                              This parameter must not be null.
+     * @param optionsParamInQuery   Additional query parameters that may influence the data retrieval process,
+     *                              such as filters or limits. This parameter can be null.
+     * @param topicParamInQuery     The topic name for triggering asynchronous responses. If specified,
+     *                              the response will be sent to this topic. This parameter can be null.
+     * @param includeDescendants    include (all) descendants or not
+     * @param authorization         The contents of the Authorization header. This parameter can be null
+     *                              if authorization is not required.
      * @return the result object, depends on use op topic. With topic a map object with request id is returned
      *         otherwise the result of the request.
      */
     public Object getResourceDataForCmHandle(final CmResourceAddress cmResourceAddress,
-                                             final String options,
-                                             final String topic,
+                                             final String optionsParamInQuery,
+                                             final String topicParamInQuery,
                                              final Boolean includeDescendants,
                                              final String authorization) {
-        final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler
-            = getNcmpDatastoreRequestHandler(cmResourceAddress.datastoreName());
 
-        return ncmpDatastoreRequestHandler.executeRequest(cmResourceAddress, options, topic, includeDescendants,
-                                                          authorization);
+        final NcmpDatastoreRequestHandler ncmpDatastoreRequestHandler
+            = getNcmpDatastoreRequestHandler(cmResourceAddress.getDatastoreName());
+        return ncmpDatastoreRequestHandler.executeRequest(cmResourceAddress, optionsParamInQuery,
+            topicParamInQuery, includeDescendants, authorization);
     }
 
     /**
@@ -117,7 +119,6 @@
             operationType, requestData, dataType, authorization);
     }
 
-
     private NcmpDatastoreRequestHandler getNcmpDatastoreRequestHandler(final String datastoreName) {
         if (OPERATIONAL.equals(DatastoreType.fromDatastoreName(datastoreName))) {
             return ncmpCachedResourceRequestHandler;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java
index cb4b04e..beef752 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistence.java
@@ -144,4 +144,12 @@
      * @return Collection of CM handle Ids
      */
     Collection<String> getCmHandleIdsWithGivenModules(Collection<String> moduleNamesForQuery);
+
+    /**
+     * Check database if cm handle id exists if not return false.
+     *
+     * @param cmHandleId cmHandle Id
+     * @return Boolean
+     */
+    boolean isExistingCmHandleId(String cmHandleId);
 }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
index 0ca2cd3..083b25d 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java
@@ -195,6 +195,15 @@
         return cpsAnchorService.queryAnchorNames(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, moduleNamesForQuery);
     }
 
+    @Override
+    public boolean isExistingCmHandleId(final String cmHandleId) {
+        try {
+            return getCmHandleDataNodeByCmHandleId(cmHandleId).size() > 0;
+        } catch (final DataNodeNotFoundException exception) {
+            return false;
+        }
+    }
+
     private static String getXPathForCmHandleById(final String cmHandleId) {
         return NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']";
     }
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java
index 832e576..c408ff9 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/AlternateIdMatcher.java
@@ -56,6 +56,21 @@
         throw new NoAlternateIdMatchFoundException(alternateId);
     }
 
+    /**
+     * Get cm handle Id from given cmHandleReference.
+     *
+     * @param cmHandleReference alternate ID
+     * @return cm handle id string
+     */
+    public String getCmHandleId(final String cmHandleReference) {
+        if (inventoryPersistence.isExistingCmHandleId(cmHandleReference)) {
+            return cmHandleReference;
+        } else {
+            return inventoryPersistence.getCmHandleDataNodeByAlternateId(cmHandleReference)
+              .getLeaves().get("id").toString();
+        }
+    }
+
     private String getParentPath(final String path, final String separator) {
         final int lastSeparatorIndex = path.lastIndexOf(separator);
         return lastSeparatorIndex < 0 ? "" : path.substring(0, lastSeparatorIndex);
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy
index 970444f..8b369bf 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/DmiDataOperationsSpec.groovy
@@ -32,6 +32,7 @@
 import org.onap.cps.ncmp.impl.dmi.DmiProperties
 import org.onap.cps.ncmp.impl.dmi.UrlTemplateParameters
 import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
 import org.onap.cps.ncmp.utils.TestUtils
 import org.onap.cps.utils.JsonObjectMapper
 import org.spockframework.spring.SpringBean
@@ -76,6 +77,9 @@
     @SpringBean
     PolicyExecutor policyExecutor = Mock()
 
+    @SpringBean
+    AlternateIdMatcher alternateIdMatcher = Mock()
+
     def 'call get resource data for #expectedDataStore from DMI without topic #scenario.'() {
         given: 'a cm handle for #cmHandleId'
             mockYangModelCmHandleRetrieval(dmiProperties)
@@ -86,6 +90,7 @@
             mockDmiRestClient.asynchronousPostOperationWithJsonData(DATA, expectedUrlTemplateWithVariables, expectedJson, READ, NO_AUTH_HEADER) >> responseFromDmi
         when: 'get resource data is invoked'
             def cmResourceAddress = new CmResourceAddress(expectedDataStore.datastoreName, cmHandleId, resourceIdentifier)
+            alternateIdMatcher.getCmHandleId(cmHandleId) >> cmHandleId
             def result = objectUnderTest.getResourceDataFromDmi(cmResourceAddress, expectedOptions, NO_TOPIC, NO_REQUEST_ID, NO_AUTH_HEADER).block()
         then: 'the result is the response from the DMI service'
             assert result.body == '{some-key:some-value}'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy
index 9c696dc..314b761 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NcmpCachedResourceRequestHandlerSpec.groovy
@@ -21,19 +21,35 @@
 package org.onap.cps.ncmp.impl.data
 
 import org.onap.cps.api.CpsDataService
+import org.onap.cps.events.EventsPublisher
 import org.onap.cps.ncmp.api.data.models.CmResourceAddress
+import org.onap.cps.ncmp.config.CpsApplicationContext
+import org.onap.cps.ncmp.impl.dmi.DmiProperties
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
 import org.onap.cps.spi.model.DataNode
+import org.spockframework.spring.SpringBean
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.context.ApplicationContext
+import org.springframework.test.context.ContextConfiguration
 import reactor.core.publisher.Mono
 import spock.lang.Specification
 
 import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
 import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
 
+@SpringBootTest
+@ContextConfiguration(classes = [CpsApplicationContext])
 class NcmpCachedResourceRequestHandlerSpec extends Specification {
 
     def cpsDataService = Mock(CpsDataService)
     def networkCmProxyQueryService= Mock(NetworkCmProxyQueryService)
 
+    @SpringBean
+    AlternateIdMatcher alternateIdMatcher = Mock()
+
+    @SpringBean
+    ApplicationContext applicationContext = Mock()
+
     def objectUnderTest = new NcmpCachedResourceRequestHandler(cpsDataService, networkCmProxyQueryService)
 
     def 'Execute a request with include descendants = #includeDescendants.'() {
@@ -54,6 +70,7 @@
             def dataNode2 = new DataNode(xpath:'p2')
             cpsDataService.getDataNodes('datastore','ch-1','resource',OMIT_DESCENDANTS) >> [dataNode1, dataNode2]
         when: 'getting the resource data'
+            alternateIdMatcher.getCmHandleId('ch-1') >> 'ch-1'
             def result = objectUnderTest.getResourceDataForCmHandle(cmResourceAddress, 'options', 'topic', 'request id', false, 'authorization')
         then: 'the result is a "Mono" holding just the first data node'
             assert result instanceof Mono
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy
index f4e4499..5f83ad5 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/NetworkCmProxyFacadeSpec.groovy
@@ -26,6 +26,7 @@
 
 import org.onap.cps.ncmp.api.data.models.CmResourceAddress
 import org.onap.cps.ncmp.api.data.models.DataOperationRequest
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
 import org.onap.cps.spi.model.DataNode
 import reactor.core.publisher.Mono
 import spock.lang.Specification
@@ -41,8 +42,9 @@
     def mockDmiDataOperations = Mock(DmiDataOperations)
     def mockNcmpCachedResourceRequestHandler = Mock(NcmpCachedResourceRequestHandler)
     def mockNcmpPassthroughResourceRequestHandler = Mock(NcmpPassthroughResourceRequestHandler)
+    def mockAlternateIdMatcher =  Mock(AlternateIdMatcher)
 
-    def objectUnderTest = new NetworkCmProxyFacade(mockNcmpCachedResourceRequestHandler, mockNcmpPassthroughResourceRequestHandler, mockDmiDataOperations)
+    def objectUnderTest = new NetworkCmProxyFacade(mockNcmpCachedResourceRequestHandler, mockNcmpPassthroughResourceRequestHandler, mockDmiDataOperations, mockAlternateIdMatcher)
 
     def NO_TOPIC = null
 
@@ -87,6 +89,7 @@
         given: 'a cm resource address for datastore operational'
             def cmResourceAddress = new CmResourceAddress('ncmp-datastore:operational', 'some CM Handle', 'some resource Id')
         and: 'get resource data from DMI is called'
+            mockAlternateIdMatcher.getCmHandleId('some CM Handle') >> 'some CM Handle'
             mockNcmpCachedResourceRequestHandler.executeRequest(cmResourceAddress, 'options', NO_TOPIC, false, 'authorization') >>
                     Mono.just('dmi response')
         when: 'get resource data operational for the given cm resource address is called'
@@ -103,6 +106,4 @@
         then: 'DMI called with correct data'
             1 * mockDmiDataOperations.writeResourceDataPassThroughRunningFromDmi('testCmHandle', 'testResourceId', UPDATE, '{some-json}', 'application/json', 'authorization')
     }
-
-
 }
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy
index ad84495..a497b45 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/AlternateIdMatcherSpec.groovy
@@ -63,4 +63,18 @@
             'no match for other child' | '/a/c'
             'no match at all'          | '/x/y'
     }
+
+    def 'Get cmHandle id from passed cmHandleReference (cmHandleId scenario)' () {
+        when: 'a cmHandleCmReference is passed in'
+            def result = objectUnderTest.getCmHandleId(cmHandleReference)
+        then: 'the inventory persistence service returns a cm handle (or not)'
+            mockInventoryPersistence.isExistingCmHandleId(cmHandleReference) >> existingCmHandleIdResponse
+            mockInventoryPersistence.getCmHandleDataNodeByAlternateId(cmHandleReference) >> alternateIdGetResponse
+        and: 'correct result is returned'
+            assert result == cmHandleReference
+        where:
+            cmHandleReference | existingCmHandleIdResponse | alternateIdGetResponse
+            'ch-1'            |  true                      |  ''
+            'alt-1'           |  false                     |  new DataNode(leaves: [id:'alt-1'])
+    }
 }
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy
new file mode 100644
index 0000000..222b3c0
--- /dev/null
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/AlternateIdSpec.groovy
@@ -0,0 +1,54 @@
+/*
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2024 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.integration.functional.ncmp
+
+import org.onap.cps.integration.base.CpsIntegrationSpecBase
+import org.springframework.http.HttpStatus
+import org.springframework.http.MediaType
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+
+class AlternateIdSpec extends CpsIntegrationSpecBase {
+
+    def setup() {
+        dmiDispatcher1.moduleNamesPerCmHandleId['ch-1'] = ['M1', 'M2']
+        registerCmHandle(DMI1_URL, 'ch-1', NO_MODULE_SET_TAG, 'alternateId')
+    }
+
+    def cleanup() {
+        deregisterCmHandle(DMI1_URL, 'ch-1')
+    }
+
+    def 'AlternateId in pass-through data operations should return OK status.'() {
+        given: 'the URL for the pass-through data request'
+            def url = '/ncmp/v1/ch/alternateId/data/ds/ncmp-datastore:passthrough-running'
+        when: 'a pass-through data request is sent to NCMP'
+            def response = mvc.perform(get(url)
+                    .queryParam('resourceIdentifier', 'my-resource-id')
+                    .contentType(MediaType.APPLICATION_JSON))
+                    .andReturn().response
+        then: 'response status is Ok'
+            assert response.status == HttpStatus.OK.value()
+    }
+
+
+
+}