API to resolve resources based on optional 'occurrence' options 04/129304/17
authorkuldipr <kuldip.rai@amdocs.com>
Thu, 24 Mar 2022 21:13:47 +0000 (17:13 -0400)
committerJozsef Csongvai <jozsef.csongvai@bell.ca>
Tue, 24 May 2022 23:26:45 +0000 (23:26 +0000)
User can specificy options to get firstN, lastN and by the Range
(begin, end) of 'occurrence' to get the resolutions. If no options
are specified, all the resolutions are returned in decending
oder (latest on top).

Map of resolutions are returned with 'occurrence' as the key to the
corresponding list of resolutions.

Issue-ID: CCSDK-3665
Signed-off-by: kuldipr <kuldip.rai@amdocs.com>
Change-Id: I9ecbfb339bde76510e81cd695e03cc1e061396ee

ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBService.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionRepository.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/ResourceResolutionDBServiceTest.kt
ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/ResourceController.kt

index 1f0171f..ed9e6d1 100644 (file)
@@ -116,6 +116,87 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso
         )
     }
 
+    /**
+     * This returns the resolutions of first N 'occurrences'.
+     *
+     * @param blueprintName
+     * @param blueprintVersion
+     * @param artifactPrefix
+     * @param resolutionKey
+     * @param firstN
+     */
+    suspend fun findFirstNOccurrences(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String,
+        firstN: Int
+    ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
+
+        resourceResolutionRepository.findFirstNOccurrences(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            firstN
+        ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
+    /**
+     * This returns the resolutions of last N 'occurrences'.
+     *
+     * @param blueprintName
+     * @param blueprintVersion
+     * @param artifactPrefix
+     * @param resolutionKey
+     * @param lastN
+     */
+    suspend fun findLastNOccurrences(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String,
+        lastN: Int
+    ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
+
+        resourceResolutionRepository.findLastNOccurrences(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            lastN
+        ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
+    /**
+     * This returns the resolutions with 'occurrence' value between begin and end.
+     *
+     * @param blueprintName
+     * @param blueprintVersion
+     * @param artifactPrefix
+     * @param resolutionKey
+     * @param begin
+     * @param end
+     */
+    suspend fun findOccurrencesWithinRange(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String,
+        begin: Int,
+        end: Int
+    ): Map<Int, List<ResourceResolution>> = withContext(Dispatchers.IO) {
+
+        resourceResolutionRepository.findOccurrencesWithinRange(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            begin,
+            end
+        ).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
     suspend fun readWithResourceIdAndResourceType(
         blueprintName: String,
         blueprintVersion: String,
index 8513bda..4b707b0 100644 (file)
@@ -37,7 +37,67 @@ interface ResourceResolutionRepository : JpaRepository<ResourceResolution, Strin
     ): ResourceResolution?
 
     @Query(
-        value = "SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE resolution_key = :key AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName ",
+        value = """
+        SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key
+           AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion
+           AND artifact_name = :artifactName AND occurrence <=  :firstN
+    """,
+        nativeQuery = true
+    )
+    fun findFirstNOccurrences(
+        @Param("key")key: String,
+        @Param("blueprintName")blueprintName: String,
+        @Param("blueprintVersion")blueprintVersion: String,
+        @Param("artifactName")artifactName: String,
+        @Param("firstN")begin: Int
+    ): List<ResourceResolution>
+
+    @Query(
+        value = """
+        SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key
+            AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion
+            AND artifact_name = :artifactName
+            AND occurrence > (
+                select max(occurrence) - :lastN from RESOURCE_RESOLUTION
+                WHERE resolution_key = :key AND blueprint_name = :blueprintName
+                      AND blueprint_version = :blueprintVersion AND artifact_name = :artifactName
+                )
+            ORDER BY occurrence DESC, creation_date DESC
+    """,
+        nativeQuery = true
+    )
+    fun findLastNOccurrences(
+        @Param("key")key: String,
+        @Param("blueprintName")blueprintName: String,
+        @Param("blueprintVersion")blueprintVersion: String,
+        @Param("artifactName")artifactName: String,
+        @Param("lastN")begin: Int
+    ): List<ResourceResolution>
+
+    @Query(
+        value = """
+        SELECT * FROM RESOURCE_RESOLUTION WHERE resolution_key = :key
+            AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion
+            AND artifact_name = :artifactName AND occurrence BETWEEN :begin AND :end
+            ORDER BY occurrence DESC, creation_date DESC
+    """,
+        nativeQuery = true
+    )
+    fun findOccurrencesWithinRange(
+        @Param("key")key: String,
+        @Param("blueprintName")blueprintName: String,
+        @Param("blueprintVersion")blueprintVersion: String,
+        @Param("artifactName")artifactName: String,
+        @Param("begin")begin: Int,
+        @Param("end")end: Int
+    ): List<ResourceResolution>
+
+    @Query(
+        value = """
+        SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE resolution_key = :key
+            AND blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion
+            AND artifact_name = :artifactName
+    """,
         nativeQuery = true
     )
     fun findMaxOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
@@ -48,7 +108,11 @@ interface ResourceResolutionRepository : JpaRepository<ResourceResolution, Strin
     ): Int?
 
     @Query(
-        value = "SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE blueprint_name = :blueprintName AND blueprint_version = :blueprintVersion AND resource_id = :resourceId AND resource_type = :resourceType ",
+        value = """
+        SELECT max(occurrence) FROM RESOURCE_RESOLUTION WHERE blueprint_name = :blueprintName
+            AND blueprint_version = :blueprintVersion AND resource_id = :resourceId
+            AND resource_type = :resourceType
+    """,
         nativeQuery = true
     )
     fun findMaxOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
index 635ce0e..8d4109f 100644 (file)
@@ -186,6 +186,75 @@ open class ResourceResolutionDBServiceTest {
         }
     }
 
+    @Test
+    fun findFirstNOccurrencesTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val rr1 = ResourceResolution()
+        val rr2 = ResourceResolution()
+        val list = listOf(rr1, rr2)
+        every {
+            resourceResolutionRepository.findFirstNOccurrences(
+                any(), any(), any(), any(), 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                resourceResolutionDBService.findFirstNOccurrences(
+                    blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1
+                )
+            assertEquals(false, res.isEmpty(), "find first N occurrences test failed")
+            assertEquals(1, res.size)
+            assertNotEquals(null, res[0])
+            res[0]?.let { assertEquals(2, it.size) }
+        }
+    }
+
+    @Test
+    fun findLastNOccurrencesTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val rr1 = ResourceResolution()
+        val rr2 = ResourceResolution()
+        val list = listOf(rr1, rr2)
+        every {
+            resourceResolutionRepository.findLastNOccurrences(
+                any(), any(), any(), any(), 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                resourceResolutionDBService.findLastNOccurrences(
+                    blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1
+                )
+            assertEquals(false, res.isEmpty(), "find last N occurrences test failed")
+            assertEquals(1, res.size)
+            assertNotEquals(null, res[0])
+            res[0]?.let { assertEquals(2, it.size) }
+        }
+    }
+
+    @Test
+    fun findOccurrencesWithinRangeTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val rr1 = ResourceResolution()
+        val rr2 = ResourceResolution()
+        val list = listOf(rr1, rr2)
+        every {
+            resourceResolutionRepository.findOccurrencesWithinRange(
+                any(), any(), any(), any(), 0, 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                resourceResolutionDBService.findOccurrencesWithinRange(
+                    blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 0, 1
+                )
+            assertEquals(false, res.isEmpty(), "find occurrences within a range test failed")
+            assertEquals(1, res.size)
+            assertNotEquals(null, res[0])
+            res[0]?.let { assertEquals(2, it.size) }
+        }
+    }
+
     @Test
     fun readWithResourceIdAndResourceTypeTest() {
         val rr1 = ResourceResolution()
index 4a2a559..d2b7ac3 100644 (file)
@@ -111,6 +111,60 @@ open class ResourceController(private var resourceResolutionDBService: ResourceR
             }
         }
 
+    @RequestMapping(
+        path = ["/occurrences"],
+        method = [RequestMethod.GET], produces = [MediaType.APPLICATION_JSON_VALUE]
+    )
+    @ApiOperation(
+        value = "Get the map of resolved resources with 'occurrence' as the keys to the resolved resources ",
+        notes = "With optional 'occurrence' options, subset of stored resolved resources can be retrieved " +
+            "using the blueprint name, blueprint version, artifact name and the resolution-key.",
+        response = ResourceResolution::class,
+        responseContainer = "List",
+        produces = MediaType.APPLICATION_JSON_VALUE
+    )
+    @ResponseBody
+    @PreAuthorize("hasRole('USER')")
+    fun getOccurrences(
+        @ApiParam(value = "Name of the CBA.", required = true)
+        @RequestParam(value = "bpName", required = true) bpName: String,
+        @ApiParam(value = "Version of the CBA.", required = true)
+        @RequestParam(value = "bpVersion", required = true) bpVersion: String,
+        @ApiParam(value = "Artifact name for which to retrieve a resolved resource.", required = true)
+        @RequestParam(value = "artifactName", required = true, defaultValue = "") artifactName: String,
+        @ApiParam(value = "Resolution Key associated with the resolution.", required = true)
+        @RequestParam(value = "resolutionKey", required = true, defaultValue = "") resolutionKey: String,
+        @ApiParam(value = "Number of earlier N occurrences of the resolutions.", required = false)
+        @RequestParam(value = "firstN", required = false) firstN: Int?,
+        @ApiParam(value = "Number of latest N occurrences of the resolutions.", required = false)
+        @RequestParam(value = "lastN", required = false) lastN: Int?,
+        @ApiParam(value = "For Range option - 'begin' is the start occurrence of range of the resolutions.", required = false)
+        @RequestParam(value = "begin", required = false) begin: Int?,
+        @ApiParam(value = "For Range option - 'end' is the end occurrence of the range of the resolutions.", required = false)
+        @RequestParam(value = "end", required = false) end: Int?
+    ): ResponseEntity<Map<Int, List<ResourceResolution>>> = runBlocking {
+        when {
+            artifactName.isEmpty() -> "'artifactName' must not be empty"
+            resolutionKey.isEmpty() -> "'resolutionKey' must not be empty"
+            // Optional options - validate if provided
+            (firstN != null && lastN != null) -> "Retrieve occurrences using either 'firstN'  OR 'lastN' option"
+            ((firstN != null || lastN != null) && (begin != null || end != null)) -> "Retrieve occurrences using either 'firstN'  OR 'lastN' OR 'begin' and 'end' option."
+            ((begin != null && end == null) || (begin == null && end != null)) -> " Retrieving occurrences within range - please provide both 'begin' and 'end' option"
+            else -> null
+        }?.let { throw httpProcessorException(ErrorCatalogCodes.REQUEST_NOT_FOUND, ResourceApiDomains.RESOURCE_API, it) }
+
+        when {
+            firstN != null ->
+                resourceResolutionDBService.findFirstNOccurrences(bpName, bpVersion, artifactName, resolutionKey, firstN)
+            lastN != null ->
+                resourceResolutionDBService.findLastNOccurrences(bpName, bpVersion, artifactName, resolutionKey, lastN)
+            begin != null && end != null ->
+                resourceResolutionDBService.findOccurrencesWithinRange(bpName, bpVersion, artifactName, resolutionKey, begin, end)
+            else ->
+                resourceResolutionDBService.readWithResolutionKey(bpName, bpVersion, artifactName, resolutionKey).groupBy(ResourceResolution::occurrence).toSortedMap(reverseOrder())
+        }.let { result -> ResponseEntity.ok().body(result) }
+    }
+
     @RequestMapping(
         method = [RequestMethod.DELETE], produces = [MediaType.APPLICATION_JSON_VALUE]
     )