Extend Template API to retrieve resolutions by occurrence 61/129361/3
authorjuhi arora <j.arora@cgi.com>
Thu, 19 May 2022 18:14:17 +0000 (14:14 -0400)
committerJUHI ARORA <juhi.arora1@bell.ca>
Tue, 24 May 2022 18:27:15 +0000 (18:27 +0000)
Add new endpoints - template to get firstN, lastN and by Range (begin, end) of 'occurrence' to get the templates

Issue-ID: CCSDK-3666
Change-Id: I242626e826022ed8b70a0abc287560ea634121b7
Signed-off-by: juhi arora <juhi.arora1@bell.ca>
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt
ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/TemplateController.kt

index 3df6137..38d61e7 100644 (file)
@@ -41,6 +41,71 @@ interface TemplateResolutionRepository : JpaRepository<TemplateResolution, Strin
         occurrence: Int
     ): TemplateResolution?
 
+    @Query(
+        value = """
+         SELECT * FROM TEMPLATE_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<TemplateResolution>
+
+    @Query(
+        value = """
+        SELECT * FROM TEMPLATE_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<TemplateResolution>
+
+    @Query(
+        value = """
+        SELECT * FROM TEMPLATE_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<TemplateResolution>
+
+    fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
+        resolutionKey: String,
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String
+    ): List<TemplateResolution>
+
     @Query(
         "select tr.resolutionKey from TemplateResolution tr where tr.blueprintName = :blueprintName and tr.blueprintVersion = :blueprintVersion and tr.artifactName = :artifactName and tr.occurrence = :occurrence"
     )
index 8789ade..906aedf 100644 (file)
@@ -241,4 +241,99 @@ class TemplateResolutionService(private val templateResolutionRepository: Templa
                 throw BluePrintException("Failed to store resource api result.", ex)
             }
         }
+    /**
+     * This returns the templates 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<TemplateResolution>> = withContext(Dispatchers.IO) {
+
+        templateResolutionRepository.findFirstNOccurrences(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            firstN
+        ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
+    /**
+     * This returns the templates 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<TemplateResolution>> = withContext(Dispatchers.IO) {
+
+        templateResolutionRepository.findLastNOccurrences(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            lastN
+        ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
+    /**
+     * This returns the templates 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<TemplateResolution>> = withContext(Dispatchers.IO) {
+
+        templateResolutionRepository.findOccurrencesWithinRange(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix,
+            begin,
+            end
+        ).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
+    }
+
+    suspend fun readWithResolutionKey(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String
+    ): List<TemplateResolution> = withContext(Dispatchers.IO) {
+
+        templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix
+        )
+    }
 }
index 71d8955..a2550ed 100644 (file)
@@ -12,6 +12,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
 import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService
 import org.springframework.dao.EmptyResultDataAccessException
 import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
 
 class TemplateResolutionServiceTest {
 
@@ -95,6 +96,75 @@ class TemplateResolutionServiceTest {
         }
     }
 
+    @Test
+    fun findFirstNOccurrencesTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val tr1 = TemplateResolution()
+        val tr2 = TemplateResolution()
+        val list = listOf(tr1, tr2)
+        every {
+            templateResolutionRepository.findFirstNOccurrences(
+                any(), any(), any(), any(), 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                templateResolutionService.findFirstNOccurrences(
+                    blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1
+                )
+            assertEquals(false, res.isEmpty(), "find first N occurrences test failed")
+            assertEquals(1, res.size)
+            assertNotEquals(null, res[1])
+            res[1]?.let { assertEquals(2, it.size) }
+        }
+    }
+
+    @Test
+    fun findLastNOccurrencesTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val tr1 = TemplateResolution()
+        val tr2 = TemplateResolution()
+        val list = listOf(tr1, tr2)
+        every {
+            templateResolutionRepository.findLastNOccurrences(
+                any(), any(), any(), any(), 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                templateResolutionService.findLastNOccurrences(
+                    blueprintName, blueprintVersion, artifactPrefix, resolutionKey, 1
+                )
+            assertEquals(false, res.isEmpty(), "find last N occurrences test failed")
+            assertEquals(1, res.size)
+            assertNotEquals(null, res[1])
+            res[1]?.let { assertEquals(2, it.size) }
+        }
+    }
+
+    @Test
+    fun findOccurrencesWithinRangeTest() {
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        val tr1 = TemplateResolution()
+        val tr2 = TemplateResolution()
+        val list = listOf(tr1, tr2)
+        every {
+            templateResolutionRepository.findOccurrencesWithinRange(
+                any(), any(), any(), any(), 0, 1
+            )
+        } returns list
+        runBlocking {
+            val res =
+                templateResolutionService.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[1])
+            res[1]?.let { assertEquals(2, it.size) }
+        }
+    }
+
     @Test
     fun writeWithResolutionKeyExistingTest() {
         val tr = TemplateResolution()
index 2d32d0e..2840f80 100644 (file)
@@ -169,6 +169,60 @@ open class TemplateController(private val templateResolutionService: TemplateRes
         ResponseEntity.ok().body(resultStored)
     }
 
+    @RequestMapping(
+        path = ["/occurrences"],
+        method = [RequestMethod.GET], produces = [MediaType.APPLICATION_JSON_VALUE]
+    )
+    @ApiOperation(
+        value = "Get the map of resolved templates with 'occurrence' as the keys to the resolved templates ",
+        notes = "With optional 'occurrence' options, subset of stored resolved templates can be retrieved " +
+            "using the blueprint name, blueprint version, artifact name and the resolution-key.",
+        response = TemplateResolution::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 templates.", required = false)
+        @RequestParam(value = "firstN", required = false) firstN: Int?,
+        @ApiParam(value = "Number of latest N occurrences of the templates.", required = false)
+        @RequestParam(value = "lastN", required = false) lastN: Int?,
+        @ApiParam(value = "For Range option - 'begin' is the start occurrence of range of the templates.", required = false)
+        @RequestParam(value = "begin", required = false) begin: Int?,
+        @ApiParam(value = "For Range option - 'end' is the end occurrence of the range of the templates.", required = false)
+        @RequestParam(value = "end", required = false) end: Int?
+    ): ResponseEntity<Map<Int, List<TemplateResolution>>> = 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 ->
+                templateResolutionService.findFirstNOccurrences(bpName, bpVersion, artifactName, resolutionKey, firstN)
+            lastN != null ->
+                templateResolutionService.findLastNOccurrences(bpName, bpVersion, artifactName, resolutionKey, lastN)
+            begin != null && end != null ->
+                templateResolutionService.findOccurrencesWithinRange(bpName, bpVersion, artifactName, resolutionKey, begin, end)
+            else ->
+                templateResolutionService.readWithResolutionKey(bpName, bpVersion, artifactName, resolutionKey).groupBy(TemplateResolution::occurrence).toSortedMap(reverseOrder())
+        }.let { result -> ResponseEntity.ok().body(result) }
+    }
+
     @PostMapping(
         "/{bpName}/{bpVersion}/{artifactName}/{resourceType}/{resourceId}",
         produces = [MediaType.APPLICATION_JSON_VALUE]