/*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2022 Bell Canada
- *  Modifications Copyright (c) 2022-2023 Nordix Foundation
+ *  Modifications Copyright (c) 2022-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.
     }
 
     @Override
-    public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandle) {
+    public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+                                                                           final String moduleName,
+                                                                           final String revision) {
         return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
     }
 
 
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021-2023 Nordix Foundation
+#  Copyright (C) 2021-2024 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2022 Bell Canada
 #  ================================================================================
       schema:
         type: string
         example: my-cm-handle
+    moduleNameInQuery:
+      name: module-name
+      in: query
+      description: Filter for a module name.This is an optional parameter
+      required: false
+      schema:
+        type: string
+        example: my-module
+    revisionInQuery:
+      name: revision
+      in: query
+      description: Filter for a module revision.This is an optional parameter and ignored when no module name is supplied
+      required: false
+      schema:
+        type: string
+        example: 2024-01-22
     dataSyncEnabled:
       name: dataSyncEnabled
       in: query
 
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021-2023 Nordix Foundation
+#  Copyright (C) 2021-2024 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021-2022 Bell Canada
 #  ================================================================================
       500:
         $ref: 'components.yaml#/components/responses/InternalServerError'
 
-fetchModuleDefinitionsByCmHandle:
+getModuleDefinitions:
   get:
-    description: Fetch all module definitions (name, revision, yang resource) for a given cm handle
     tags:
       - network-cm-proxy
-    summary: Fetch all module definitions (name, revision, yang resource) for a given cm handle
-    operationId: getModuleDefinitionsByCmHandleId
+    summary: Get module definitions
+    description: Get module definitions (module name, revision, yang resource) with options to filter on module name and revision
+    operationId: getModuleDefinitions
     parameters:
       - $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+      - $ref: 'components.yaml#/components/parameters/moduleNameInQuery'
+      - $ref: 'components.yaml#/components/parameters/revisionInQuery'
     responses:
       200:
         description: OK
 
 #  ============LICENSE_START=======================================================
-#  Copyright (C) 2021-2023 Nordix Foundation
+#  Copyright (C) 2021-2024 Nordix Foundation
 #  Modifications Copyright (C) 2021 Pantheon.tech
 #  Modifications Copyright (C) 2021 Bell Canada
 #  ================================================================================
     $ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
 
   /v1/ch/{cm-handle}/modules/definitions:
-    $ref: 'ncmp.yml#/fetchModuleDefinitionsByCmHandle'
+    $ref: 'ncmp.yml#/getModuleDefinitions'
 
   /v1/ch/searches:
     $ref: 'ncmp.yml#/searchCmHandles'
 
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
- *  Modifications Copyright (C) 2021-2023 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021 highstreet technologies GmbH
  *  Modifications Copyright (C) 2021-2022 Bell Canada
  *  ================================================================================
 import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE;
 
 import io.micrometer.core.annotation.Timed;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState;
 import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
 import org.onap.cps.ncmp.rest.util.DeprecationHelper;
+import org.onap.cps.spi.model.ModuleDefinition;
 import org.onap.cps.utils.JsonObjectMapper;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
     }
 
     /**
-     * Return module definitions for a cm handle.
+     * Return module definitions.
      *
-     * @param cmHandleId cm-handle identifier
+     * @param cmHandleId    cm-handle identifier
+     * @param moduleName    module name
+     * @param revision      the revision of the module
      * @return list of module definitions (module name, revision, yang resource content)
      */
     @Override
-    public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandleId) {
-        final List<RestModuleDefinition> restModuleDefinitions =
-                networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId).stream()
-                        .map(ncmpRestInputMapper::toRestModuleDefinition)
-                        .collect(Collectors.toList());
-        return new ResponseEntity<>(restModuleDefinitions, HttpStatus.OK);
+    public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+                                                                           final String moduleName,
+                                                                           final String revision) {
+        final Collection<ModuleDefinition> moduleDefinitions;
+        if (StringUtils.hasText(moduleName)) {
+            moduleDefinitions =
+                networkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, revision);
+        } else {
+            moduleDefinitions = networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId);
+            if (StringUtils.hasText(revision)) {
+                log.warn("Ignoring revision filter as no module name is provided");
+            }
+        }
+        final List<RestModuleDefinition> response = new ArrayList<>();
+        for (final ModuleDefinition moduleDefinition: moduleDefinitions) {
+            response.add(ncmpRestInputMapper.toRestModuleDefinition(moduleDefinition));
+        }
+        return new ResponseEntity<>(response, HttpStatus.OK);
     }
 
     /**
 
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021 highstreet technologies GmbH
- *  Modifications Copyright (C) 2021-2023 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021-2022 Bell Canada.
  *  ================================================================================
  *  Licensed under the Apache License, Version 2.0 (the "License");
 
 package org.onap.cps.ncmp.rest.controller
 
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
-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.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
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.classic.spi.ILoggingEvent
+import ch.qos.logback.core.read.ListAppender
 import com.fasterxml.jackson.databind.ObjectMapper
 import org.mapstruct.factory.Mappers
 import org.onap.cps.TestUtils
+import org.onap.cps.events.EventsPublisher
 import org.onap.cps.ncmp.api.NetworkCmProxyDataService
 import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
 import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
 import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
 import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
 import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.rest.model.DataOperationRequest
-import org.onap.cps.ncmp.rest.model.DataOperationDefinition
 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.DataOperationRequestMapper
+import org.onap.cps.ncmp.rest.model.DataOperationDefinition
+import org.onap.cps.ncmp.rest.model.DataOperationRequest
 import org.onap.cps.ncmp.rest.util.DeprecationHelper
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.ModuleDefinition
 import org.onap.cps.spi.model.ModuleReference
 import org.onap.cps.utils.JsonObjectMapper
+import org.slf4j.LoggerFactory
 import org.spockframework.spring.SpringBean
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.beans.factory.annotation.Value
 import org.springframework.test.web.servlet.MockMvc
 import spock.lang.Shared
 import spock.lang.Specification
+
 import java.time.OffsetDateTime
 import java.time.ZoneOffset
 import java.time.format.DateTimeFormatter
 
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
+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.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 static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
+
 @WebMvcTest(NetworkCmProxyController)
 class NetworkCmProxyControllerSpec extends Specification {
 
     def NO_REQUEST_ID = null
     def TIMOUT_FOR_TEST = 1234
 
+    def logger = Spy(ListAppender<ILoggingEvent>)
+
     def setup() {
         ncmpCachedResourceRequestHandler.notificationFeatureEnabled = true
         ncmpCachedResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
         ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = true
         ncmpPassthroughResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
+        setupLogger()
+    }
+
+    def cleanup() {
+        ((Logger) LoggerFactory.getLogger(EventsPublisher.class)).detachAndStopAllAppenders()
     }
 
     def 'Get Resource Data from pass-through operational.'() {
             ':passthrough-running'     | 'passthrough-running'
     }
 
-    def 'Get module definitions based on cmHandleId.'() {
-        when: 'get module definition request is performed'
+    def 'Getting module definitions for a module'() {
+        when: 'get module definition request is performed with module name'
             def response = mvc.perform(
-                    get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions"))
-                    .andReturn().response
-        then: 'ncmp service method to get module definitions is called'
-            mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle')
-                    >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
-                    'module sampleModuleName{ sample module content }')]
+                get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=sampleModuleName"))
+                .andReturn().response
+        then: 'ncmp service method is invoked with correct parameters'
+            mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', 'sampleModuleName', _)
+                >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
+                'module sampleModuleName{ sample module content }')]
         and: 'response contains an array with the module name, revision and content'
             response.getContentAsString() == '[{"moduleName":"sampleModuleName","revision":"2021-10-03","content":"module sampleModuleName{ sample module content }"}]'
         and: 'response returns an OK http code'
             response.status == HttpStatus.OK.value()
     }
 
+    def 'Getting module definitions filtering on #scenario'() {
+        when: 'get module definition request is performed'
+            def response = mvc.perform(
+                get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=" + moduleName + "&revision=" + revision))
+                .andReturn().response
+        then: 'ncmp service method to get definitions by cm handle is invoked when needed'
+            numberOfCallsToByCmHandleId * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle') >> []
+        and: 'ncmp service method to get definitions by module is invoked when needed'
+            numberOfCallsToByModule * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', moduleName, revision) >> []
+        and: 'response returns an OK http code'
+            response.status == HttpStatus.OK.value()
+        and: 'the correct message is logged when needed'
+            if (expectLogWarning) {
+                def lastLoggingEvent = logger.list[0]
+                assert lastLoggingEvent.level == Level.WARN
+                assert lastLoggingEvent.formattedMessage.contains('Ignoring revision')
+            }
+        where: 'following parameters are used'
+            scenario                   | moduleName    | revision        || numberOfCallsToByCmHandleId | numberOfCallsToByModule | expectLogWarning
+            'module name'              | 'some-module' | ''              || 0                           | 1                       | false
+            'module name and revision' | 'some-module' | 'some-revision' || 0                           | 1                       | false
+            'no filtering'             | ''            | ''              || 1                           | 0                       | false
+            'only revision'            | ''            | 'some-revision' || 1                           | 0                       | true
+    }
+
     def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario'() {
         when: 'the set data sync enabled request is invoked'
             def response = mvc.perform(
         return dataOperationDefinition
     }
 
+    def setupLogger() {
+        def setupLogger = ((Logger) LoggerFactory.getLogger(NetworkCmProxyController.class))
+        setupLogger.setLevel(Level.DEBUG)
+        setupLogger.addAppender(logger)
+        logger.start()
+    }
+
 }
 
 
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 highstreet technologies GmbH
- *  Modifications Copyright (C) 2021-2023 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2022 Bell Canada
  *  ================================================================================
      */
     Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
 
+    /**
+     * Get module definitions for the given parameters.
+     *
+     * @param cmHandleId        cm-handle identifier
+     * @param moduleName        module name
+     * @param moduleRevision    the revision of the module
+     * @return list of module definitions (module name, revision, yang resource content)
+     */
+    Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+                                                                         String moduleName,
+                                                                         String moduleRevision);
+
     /**
      * Query cm handle details by cm handle's name.
      *
 
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2021 highstreet technologies GmbH
- *  Modifications Copyright (C) 2021-2023 Nordix Foundation
+ *  Modifications Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada
  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
         return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
     }
 
+    @Override
+    public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+                                                                                final String moduleName,
+                                                                                final String moduleRevision) {
+        return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
+    }
+
     /**
      * Retrieve cm handles with details for the given query parameters.
      *
 
      */
     Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
 
+    /**
+     * Method to return module definitions for the given parameters.
+     *
+     * @param cmHandleId        cm-handle identifier
+     * @param moduleName        module name
+     * @param moduleRevision    the revision of the module
+     * @return list of module definitions (module name, revision, yang resource content)
+     */
+    Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+                                                                         String moduleName,
+                                                                         String moduleRevision);
+
     /**
      * Method to return module references by cmHandleId.
      *
 
         return cpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
     }
 
+    @Override
+    public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+                                                                                final String moduleName,
+                                                                                final String moduleRevision) {
+        cpsValidator.validateNameCharacters(cmHandleId, moduleName);
+        return cpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+                    cmHandleId, moduleName, moduleRevision);
+    }
+
     @Override
     public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
         cpsValidator.validateNameCharacters(cmHandleId);
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2021-2023 Nordix Foundation
+ *  Copyright (C) 2021-2024 Nordix Foundation
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2021-2022 Bell Canada
  *  Modifications Copyright (C) 2023 TechMahindra Ltd.
             assert result == ['cm-handle-id-1']
     }
 
-    def 'Getting module definitions.'() {
-        when: 'get module definitions method is called with a valid cm handle ID'
+    def 'Getting module definitions by module'() {
+        when: 'get module definitions is performed with module name'
+            objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+        then: 'ncmp inventory persistence service is invoked once with correct parameters'
+            1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+    }
+
+    def 'Getting module definitions by cm handle id'() {
+        when: 'get module definitions is performed with cm handle id'
             objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
-        then: 'CPS module services is invoked once'
+        then: 'ncmp inventory persistence service is invoked once with correct parameter'
             1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
     }
 
 
             'DELETING'  | CmHandleState.DELETING || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
     }
 
-    def 'Get module definitions'() {
-        given: 'cps module service returns a collection of module definitions'
+    def 'Getting module definitions by module'() {
+        given: 'cps module service returns module definition for module name'
+            def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
+            mockCpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id', 'some-module', '2024-01-25') >> moduleDefinitions
+        when: 'get module definitions is invoked with module name'
+            def result = objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cmHandle-Id', 'some-module', '2024-01-25')
+        then: 'returned result are the same module definitions as returned from module service'
+            assert result == moduleDefinitions
+        and: 'cm handle id and module name validated'
+            1 * mockCpsValidator.validateNameCharacters('some-cmHandle-Id', 'some-module')
+    }
+
+    def 'Getting module definitions with cm handle id'() {
+        given: 'cps module service returns module definitions for cm handle id'
             def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
             mockCpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleDefinitions
-        when: 'get module definitions by cmHandle is invoked'
+        when: 'get module definitions is invoked with cm handle id'
             def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id')
         then: 'the returned result are the same module definitions as returned from the module service'
             assert result == moduleDefinitions
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2023 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2021 Pantheon.tech
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceService {
 
     private static final String YANG_RESOURCE_CHECKSUM_CONSTRAINT_NAME = "yang_resource_checksum_key";
+    private static final String NO_MODULE_NAME_FILTER = null;
+    private static final String NO_MODULE_REVISION = null;
     private static final Pattern CHECKSUM_EXCEPTION_PATTERN = Pattern.compile(".*\\(checksum\\)=\\((\\w+)\\).*");
     private static final Pattern RFC6020_RECOMMENDED_FILENAME_PATTERN = Pattern
             .compile("([\\w-]+)@(\\d{4}-\\d{2}-\\d{2})(?:\\.yang)?", Pattern.CASE_INSENSITIVE);
     public Collection<ModuleDefinition> getYangResourceDefinitions(final String dataspaceName,
                                                                    final String anchorName) {
         final Set<YangResourceEntity> yangResourceEntities =
-                yangResourceRepository
-                        .findAllModuleDefinitionsByDataspaceAndAnchor(dataspaceName, anchorName);
-        return yangResourceEntities.stream().map(CpsModulePersistenceServiceImpl::toModuleDefinition)
-                .collect(Collectors.toList());
+                yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+                    NO_MODULE_NAME_FILTER, NO_MODULE_REVISION);
+        return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+    }
+
+    @Override
+    public Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(final String dataspaceName,
+                                                                                    final String anchorName,
+                                                                                    final String moduleName,
+                                                                                    final String moduleRevision) {
+        final Set<YangResourceEntity> yangResourceEntities =
+            yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+                moduleName, moduleRevision);
+        return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+    }
+
+    private List<ModuleDefinition> convertYangResourceEntityToModuleDefinition(final Set<YangResourceEntity>
+                                                                                   yangResourceEntities) {
+        final List<ModuleDefinition> resultModuleDefinitions = new ArrayList<>(yangResourceEntities.size());
+        for (final YangResourceEntity yangResourceEntity: yangResourceEntities) {
+            resultModuleDefinitions.add(toModuleDefinition(yangResourceEntity));
+        }
+        return resultModuleDefinitions;
     }
 
     @Override
 
 /*
  *  ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Pantheon.tech
- *  Modifications Copyright (C) 2021-2023 Nordix Foundation
+ *  Modifications Copyright (C) 2021-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.
             WHERE
                     dataspace.name = :dataspaceName
                 AND anchor.name = :anchorName
+                AND (:moduleName IS NULL OR yang_resource.module_name = :moduleName)
+                AND (:revision IS NULL OR yang_resource.revision = :revision)
             """, nativeQuery = true)
-    Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchor(
-            @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName);
+    Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchorAndModule(
+            @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName,
+            @Param("moduleName") String moduleName, @Param("revision") String revision);
 
     @Query(value = """
             SELECT DISTINCT
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2023 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2021 Pantheon.tech
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
  *  ================================================================================
      */
     Collection<ModuleDefinition> getModuleDefinitionsByAnchorName(String dataspaceName, String anchorName);
 
+    /**
+     * Retrieve module definitions for the given parameters.
+     *
+     * @param dataspaceName     dataspace name
+     * @param anchorName        anchor name
+     * @param moduleName        module name
+     * @param moduleRevision    the revision of the module
+     * @return a collection of module definitions (moduleName, revision, yang resource content)
+     */
+    Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+                                                                  String moduleName, String moduleRevision);
+
     /**
      * Identify previously unknown Yang Resource module references.
      * The system will ignore the namespace of all module references.
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2023 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2021 Pantheon.tech
  *  Modifications Copyright (C) 2022 Bell Canada
  *  Modifications Copyright (C) 2022 TechMahindra Ltd
         return cpsModulePersistenceService.getYangResourceDefinitions(dataspaceName, anchorName);
     }
 
+    @Override
+    public Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(final String dataspaceName,
+                                                                              final String anchorName,
+                                                                              final String moduleName,
+                                                                              final String moduleRevision) {
+        return cpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule(dataspaceName, anchorName,
+            moduleName, moduleRevision);
+    }
+
     @Override
     public Collection<ModuleReference> identifyNewModuleReferences(
         final Collection<ModuleReference> moduleReferencesToCheck) {
 
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2023 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
  *  ================================================================================
      */
     Collection<ModuleDefinition> getYangResourceDefinitions(String dataspaceName, String anchorName);
 
+    /**
+     * Get YANG resource definitions for the given parameters.
+     *
+     * @param dataspaceName  dataspace name
+     * @param anchorName     anchor name
+     * @param moduleName     module name
+     * @param moduleRevision the revision of the module
+     * @return a collection of module definitions (moduleName, revision and yang resource content)
+     */
+    Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+                                                                             String moduleName, String moduleRevision);
+
     /**
      * Remove unused Yang Resource Modules.
      */
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2020-2023 Nordix Foundation
+ *  Copyright (C) 2020-2024 Nordix Foundation
  *  Modifications Copyright (C) 2020-2021 Pantheon.tech
  *  Modifications Copyright (C) 2020-2022 Bell Canada.
  *  Modifications Copyright (C) 2022 TechMahindra Ltd.
             1 * mockCpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck)
     }
 
-    def 'Getting module definitions.'() {
-        given: 'the module persistence service returns a collection of module definitions'
+    def 'Getting module definitions with module name'() {
+        given: 'module persistence service returns module definitions for module name'
+            def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
+            mockCpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01')  >> moduleDefinitionsFromPersistenceService
+        when: 'get module definitions method is called with anchor and module name'
+            def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01')
+        then: 'the result is the same collection returned by the persistence service'
+            assert result == moduleDefinitionsFromPersistenceService
+    }
+
+    def 'Getting module definitions with anchor name'() {
+        given: 'the module persistence service returns module definitions for cm handle id'
             def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
             mockCpsModulePersistenceService.getYangResourceDefinitions('some-dataspace-name', 'some-anchor-name')  >> moduleDefinitionsFromPersistenceService
         when: 'get module definitions method is called with a valid dataspace and anchor name'
             def result = objectUnderTest.getModuleDefinitionsByAnchorName('some-dataspace-name', 'some-anchor-name')
         then: 'the result is the same collection returned by the persistence service'
             assert result == moduleDefinitionsFromPersistenceService
-        and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
+        and: 'cps validator is called on the dataspace and anchor name'
             1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name')
     }
 
 
 /*
  *  ============LICENSE_START=======================================================
- *  Copyright (C) 2023 Nordix Foundation
+ *  Copyright (C) 2023-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.
 package org.onap.cps.integration.functional
 
 import org.onap.cps.api.CpsModuleService
-import org.onap.cps.api.impl.CpsModuleServiceImpl
 import org.onap.cps.integration.base.FunctionalSpecBase
 import org.onap.cps.spi.CascadeDeleteAllowed
 import org.onap.cps.spi.exceptions.AlreadyDefinedException
             result == [new ModuleDefinition('stores','2020-09-15','')]
     }
 
+    def 'Retrieving module definitions: #scenarios'() {
+        when: 'module definitions for module name are retrieved'
+            def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, moduleName, moduleRevision)
+        then: 'the correct module definitions are returned'
+            result == [new ModuleDefinition('stores','2020-09-15','')]
+        where: 'following parameters are used'
+            scenarios               | moduleName | moduleRevision
+            'both specified'        | 'stores'   | '2020-09-15'
+            'module name specified' | 'stores'   | null
+    }
+
     def 'Retrieving yang resource module references by anchor.'() {
         when: 'the yang resource module references for an anchor are retrieved'
             def result = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1)