From 9500d29a3edceee521d16bb1256974222cf37214 Mon Sep 17 00:00:00 2001 From: juhi arora Date: Thu, 19 May 2022 14:14:17 -0400 Subject: Extend Template API to retrieve resolutions by occurrence 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 --- .../resolution/db/TemplateResolutionRepository.kt | 65 +++++++++++++++ .../resolution/db/TemplateResolutionService.kt | 95 ++++++++++++++++++++++ .../resolution/db/TemplateResolutionServiceTest.kt | 70 ++++++++++++++++ .../resource/api/TemplateController.kt | 54 ++++++++++++ 4 files changed, 284 insertions(+) (limited to 'ms/blueprintsprocessor') diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt index 3df613745..38d61e78d 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionRepository.kt @@ -41,6 +41,71 @@ interface TemplateResolutionRepository : JpaRepository + + @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 + + @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 + + fun findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey: String, + blueprintName: String, + blueprintVersion: String, + artifactPrefix: String + ): List + @Query( "select tr.resolutionKey from TemplateResolution tr where tr.blueprintName = :blueprintName and tr.blueprintVersion = :blueprintVersion and tr.artifactName = :artifactName and tr.occurrence = :occurrence" ) diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt index 8789ade99..906aedf09 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionService.kt @@ -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> = 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> = 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> = 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 = withContext(Dispatchers.IO) { + + templateResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName( + resolutionKey, + blueprintName, + blueprintVersion, + artifactPrefix + ) + } } diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt index 71d895574..a2550ed5f 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/db/TemplateResolutionServiceTest.kt @@ -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() diff --git a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/TemplateController.kt b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/TemplateController.kt index 2d32d0e1d..2840f8016 100644 --- a/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/TemplateController.kt +++ b/ms/blueprintsprocessor/modules/inbounds/resource-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/resource/api/TemplateController.kt @@ -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>> = 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] -- cgit 1.2.3-korg