Enable versioned resource resolution by using occurrence
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / db / ResourceResolutionDBService.kt
index 81239be..1f0171f 100644 (file)
@@ -24,100 +24,173 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeServ
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.slf4j.LoggerFactory
-import org.springframework.dao.DataIntegrityViolationException
+import org.springframework.dao.EmptyResultDataAccessException
 import org.springframework.stereotype.Service
-import java.util.*
+import java.util.UUID
 
 @Service
 class ResourceResolutionDBService(private val resourceResolutionRepository: ResourceResolutionRepository) {
 
     private val log = LoggerFactory.getLogger(ResourceResolutionDBService::class.toString())
 
-    suspend fun readValue(blueprintName: String,
-                          blueprintVersion: String,
-                          artifactPrefix: String,
-                          resolutionKey: String,
-                          name: String): ResourceResolution = withContext(Dispatchers.IO) {
+    suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
+        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        key: String,
+        occurrence: Int,
+        artifactPrefix: String
+    ): List<ResourceResolution> {
+        return try {
+            val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
+
+            val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
+            val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
+
+            resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
+                blueprintName,
+                blueprintVersion,
+                artifactPrefix,
+                key,
+                occurrence
+            )
+        } catch (e: EmptyResultDataAccessException) {
+            emptyList()
+        }
+    }
+
+    suspend fun findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
+        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        resourceId: String,
+        resourceType: String,
+        occurrence: Int,
+        artifactPrefix: String
+    ): List<ResourceResolution> {
+        return try {
+
+            val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
+
+            val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
+            val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
+
+            resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
+                blueprintName,
+                blueprintVersion,
+                artifactPrefix,
+                resourceId,
+                resourceType,
+                occurrence
+            )
+        } catch (e: EmptyResultDataAccessException) {
+            emptyList()
+        }
+    }
+
+    suspend fun readValue(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String,
+        name: String
+    ): ResourceResolution? = withContext(Dispatchers.IO) {
 
         resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactNameAndName(
             resolutionKey,
             blueprintName,
             blueprintVersion,
             artifactPrefix,
-            name)
+            name
+        )
     }
 
-    suspend fun readWithResolutionKey(blueprintName: String,
-                                      blueprintVersion: String,
-                                      artifactPrefix: String,
-                                      resolutionKey: String): List<ResourceResolution> = withContext(Dispatchers.IO) {
+    suspend fun readWithResolutionKey(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String,
+        resolutionKey: String
+    ): List<ResourceResolution> = withContext(Dispatchers.IO) {
 
         resourceResolutionRepository.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
             resolutionKey,
             blueprintName,
             blueprintVersion,
-            artifactPrefix)
+            artifactPrefix
+        )
     }
 
-    suspend fun readWithResourceIdAndResourceType(blueprintName: String,
-                                                  blueprintVersion: String,
-                                                  resourceId: String,
-                                                  resourceType: String): List<ResourceResolution> = withContext(Dispatchers.IO) {
+    suspend fun readWithResourceIdAndResourceType(
+        blueprintName: String,
+        blueprintVersion: String,
+        resourceId: String,
+        resourceType: String
+    ): List<ResourceResolution> =
+        withContext(Dispatchers.IO) {
 
-        resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
-            blueprintName,
-            blueprintVersion,
-            resourceId,
-            resourceType)
-    }
+            resourceResolutionRepository.findByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
+                blueprintName,
+                blueprintVersion,
+                resourceId,
+                resourceType
+            )
+        }
 
-    suspend fun write(properties: Map<String, Any>,
-                      bluePrintRuntimeService: BluePrintRuntimeService<*>,
-                      artifactPrefix: String,
-                      resourceAssignment: ResourceAssignment): ResourceResolution = withContext(Dispatchers.IO) {
+    suspend fun write(
+        properties: Map<String, Any>,
+        bluePrintRuntimeService: BluePrintRuntimeService<*>,
+        artifactPrefix: String,
+        resourceAssignment: ResourceAssignment
+    ): ResourceResolution = withContext(Dispatchers.IO) {
 
         val metadata = bluePrintRuntimeService.bluePrintContext().metadata!!
 
         val blueprintVersion = metadata[BluePrintConstants.METADATA_TEMPLATE_VERSION]!!
         val blueprintName = metadata[BluePrintConstants.METADATA_TEMPLATE_NAME]!!
-        val resolutionKey =
-            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_KEY].toString()
-        val resourceType =
-            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE].toString()
-        val resourceId =
-            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID].toString()
-
-        write(blueprintName,
+
+        val resolutionKey = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] as String
+        val resourceId = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] as String
+        val resourceType = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] as String
+        val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int
+
+        write(
+            blueprintName,
             blueprintVersion,
             resolutionKey,
             resourceId,
             resourceType,
             artifactPrefix,
-            resourceAssignment)
+            resourceAssignment,
+            occurrence
+        )
     }
 
-    suspend fun write(blueprintName: String,
-                      blueprintVersion: String,
-                      resolutionKey: String,
-                      resourceId: String,
-                      resourceType: String,
-                      artifactPrefix: String,
-                      resourceAssignment: ResourceAssignment): ResourceResolution = withContext(Dispatchers.IO) {
+    suspend fun write(
+        blueprintName: String,
+        blueprintVersion: String,
+        resolutionKey: String,
+        resourceId: String,
+        resourceType: String,
+        artifactPrefix: String,
+        resourceAssignment: ResourceAssignment,
+        occurrence: Int = 0
+    ): ResourceResolution = withContext(Dispatchers.IO) {
 
         val resourceResolution = ResourceResolution()
         resourceResolution.id = UUID.randomUUID().toString()
         resourceResolution.artifactName = artifactPrefix
+        resourceResolution.occurrence = occurrence
         resourceResolution.blueprintVersion = blueprintVersion
         resourceResolution.blueprintName = blueprintName
         resourceResolution.resolutionKey = resolutionKey
         resourceResolution.resourceType = resourceType
         resourceResolution.resourceId = resourceId
-        resourceResolution.value = JacksonUtils.getValue(resourceAssignment.property?.value!!).toString()
+        resourceResolution.value = resourceAssignment.property?.value?.let {
+            if (BluePrintConstants.STATUS_SUCCESS == resourceAssignment.status)
+                JacksonUtils.getValue(it).toString()
+            else ""
+        } ?: ""
         resourceResolution.name = resourceAssignment.name
         resourceResolution.dictionaryName = resourceAssignment.dictionaryName
         resourceResolution.dictionaryVersion = resourceAssignment.version
         resourceResolution.dictionarySource = resourceAssignment.dictionarySource
-        resourceResolution.status = resourceAssignment.status
+        resourceResolution.status = resourceAssignment.status ?: BluePrintConstants.STATUS_FAILURE
 
         try {
             resourceResolutionRepository.saveAndFlush(resourceResolution)
@@ -125,4 +198,83 @@ class ResourceResolutionDBService(private val resourceResolutionRepository: Reso
             throw BluePrintException("Failed to store resource resolution result.", ex)
         }
     }
-}
\ No newline at end of file
+
+    /**
+     * This is a deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey method to delete resources
+     * associated to a specific resolution-key
+     *
+     * @param blueprintName name of the CBA
+     * @param blueprintVersion version of the CBA
+     * @param artifactName name of the artifact
+     * @param resolutionKey value of the resolution-key
+     */
+    suspend fun deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactName: String,
+        resolutionKey: String
+    ) {
+        resourceResolutionRepository.deleteByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKey(
+            blueprintName,
+            blueprintVersion,
+            artifactName,
+            resolutionKey
+        )
+    }
+
+    suspend fun deleteResourceResolutionList(listResourceResolution: List<ResourceResolution>) = withContext(Dispatchers.IO) {
+        try {
+            resourceResolutionRepository.deleteInBatch(listResourceResolution)
+        } catch (ex: Exception) {
+            throw BluePrintException("Failed to batch delete resource resolution", ex)
+        }
+    }
+
+    /**
+     * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise.
+     * The 'occurrence' is used to persist new resource resolution in the DB.
+     *
+     * @param resolutionKey
+     * @param blueprintName
+     * @param blueprintVersion
+     * @param artifactPrefix
+     */
+    suspend fun findNextOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
+        resolutionKey: String,
+        blueprintName: String,
+        blueprintVersion: String,
+        artifactPrefix: String
+    ) = withContext(Dispatchers.IO) {
+        val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
+            resolutionKey,
+            blueprintName,
+            blueprintVersion,
+            artifactPrefix
+        )
+        maxOccurrence?.inc() ?: 1
+    }
+
+    /**
+     * This method returns the (highest occurrence + 1) of resource resolutions if present in DB, returns 1 otherwise.
+     * The 'occurrence' is used to persist new resource resolution in the DB.
+     *
+     * @param blueprintName
+     * @param blueprintVersion
+     * @param resourceId
+     * @param resourceType
+     */
+    suspend fun findNextOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
+        blueprintName: String,
+        blueprintVersion: String,
+        resourceId: String,
+        resourceType: String
+    ) = withContext(Dispatchers.IO) {
+        val maxOccurrence = resourceResolutionRepository.findMaxOccurrenceByBlueprintNameAndBlueprintVersionAndResourceIdAndResourceType(
+            blueprintName,
+            blueprintVersion,
+            resourceId,
+            resourceType
+        )
+        maxOccurrence?.inc() ?: 1
+    }
+}