package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution
+import com.fasterxml.jackson.databind.JsonNode
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
-import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionResultService
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolution
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.ResourceResolutionDBService
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.TemplateResolutionService
import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
-import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceDefinitionUtils.createResourceAssignments
+import org.onap.ccsdk.cds.controllerblueprints.core.*
import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintTemplateService
import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
import org.slf4j.LoggerFactory
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Service
+import java.util.*
interface ResourceResolutionService {
artifactNames: List<String>, properties: Map<String, Any>): MutableMap<String, String>
suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
- artifactPrefix: String, properties: Map<String, Any>): String
+ artifactPrefix: String, properties: Map<String, Any>): String
- suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
- artifactMapping: String, artifactTemplate: String?): String
+ /** Resolve resources for all the sources defined in a particular resource Definition[resolveDefinition]
+ * with other [resourceDefinitions] dependencies for the sources [sources]
+ * Used to get the same resource values from multiple sources. **/
+ suspend fun resolveResourceDefinition(blueprintRuntimeService: BluePrintRuntimeService<*>,
+ resourceDefinitions: MutableMap<String, ResourceDefinition>,
+ resolveDefinition: String, sources: List<String>)
+ : MutableMap<String, JsonNode>
suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
resourceDefinitions: MutableMap<String, ResourceDefinition>,
resourceAssignments: MutableList<ResourceAssignment>,
- identifierName: String)
+ artifactPrefix: String,
+ properties: Map<String, Any>)
}
@Service(ResourceResolutionConstants.SERVICE_RESOURCE_RESOLUTION)
open class ResourceResolutionServiceImpl(private var applicationContext: ApplicationContext,
- private var resolutionResultService: ResourceResolutionResultService) :
+ private var templateResolutionDBService: TemplateResolutionService,
+ private var blueprintTemplateService: BluePrintTemplateService,
+ private var resourceResolutionDBService: ResourceResolutionDBService) :
ResourceResolutionService {
private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java)
override suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>,
artifactTemplate: String,
resolutionKey: String): String {
- return resolutionResultService.read(bluePrintRuntimeService, artifactTemplate, resolutionKey)
+ return templateResolutionDBService.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
+ bluePrintRuntimeService,
+ artifactTemplate,
+ resolutionKey)
}
override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
- artifactNames: List<String>, properties: Map<String, Any>): MutableMap<String, String> {
+ artifactNames: List<String>,
+ properties: Map<String, Any>): MutableMap<String, String> {
+
+ val resourceAssignmentRuntimeService =
+ ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString())
val resolvedParams: MutableMap<String, String> = hashMapOf()
artifactNames.forEach { artifactName ->
- val resolvedContent = resolveResources(bluePrintRuntimeService, nodeTemplateName,
+ val resolvedContent = resolveResources(resourceAssignmentRuntimeService, nodeTemplateName,
artifactName, properties)
+
resolvedParams[artifactName] = resolvedContent
}
return resolvedParams
}
+
override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
- artifactPrefix: String, properties: Map<String, Any>): String {
+ artifactPrefix: String, properties: Map<String, Any>): String {
// Velocity Artifact Definition Name
val artifactTemplate = "$artifactPrefix-template"
// Resource Assignment Artifact Definition Name
val artifactMapping = "$artifactPrefix-mapping"
- val result = resolveResources(bluePrintRuntimeService, nodeTemplateName,
- artifactMapping, artifactTemplate)
-
- if (properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)
- && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean) {
- resolutionResultService.write(properties, result, bluePrintRuntimeService, artifactPrefix)
- log.info("resolution saved into database successfully : ($properties)")
- }
-
- return result
- }
-
-
- override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
- artifactMapping: String, artifactTemplate: String?): String {
-
val resolvedContent: String
log.info("Resolving resource for template artifact($artifactTemplate) with resource assignment artifact($artifactMapping)")
- val identifierName = artifactTemplate ?: "no-template"
-
val resourceAssignmentContent =
bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
as? MutableList<ResourceAssignment>
?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
+ if (isToStore(properties)) {
+ val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix)
+ if (existingResourceResolution.isNotEmpty()) {
+ updateResourceAssignmentWithExisting(bluePrintRuntimeService as ResourceAssignmentRuntimeService,
+ existingResourceResolution, resourceAssignments)
+ }
+ }
+
// Get the Resource Dictionary Name
val resourceDefinitions: MutableMap<String, ResourceDefinition> = ResourceAssignmentUtils
.resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath)
// Resolve resources
- resolveResourceAssignments(bluePrintRuntimeService, resourceDefinitions, resourceAssignments, identifierName)
+ resolveResourceAssignments(bluePrintRuntimeService,
+ resourceDefinitions,
+ resourceAssignments,
+ artifactPrefix,
+ properties)
val resolvedParamJsonContent =
ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
- // Check Template is there
- if (artifactTemplate != null) {
- val blueprintTemplateService = BluePrintTemplateService(bluePrintRuntimeService, nodeTemplateName, artifactTemplate)
- val templateContent =
- bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactTemplate)
-
- resolvedContent = blueprintTemplateService.generateContent(templateContent, resolvedParamJsonContent)
+ resolvedContent = blueprintTemplateService.generateContent(bluePrintRuntimeService, nodeTemplateName,
+ artifactTemplate, resolvedParamJsonContent)
- } else {
- resolvedContent = resolvedParamJsonContent
+ if (isToStore(properties)) {
+ templateResolutionDBService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix)
+ log.info("Template resolution saved into database successfully : ($properties)")
}
return resolvedContent
}
+ override suspend fun resolveResourceDefinition(blueprintRuntimeService: BluePrintRuntimeService<*>,
+ resourceDefinitions: MutableMap<String, ResourceDefinition>,
+ resolveDefinition: String, sources: List<String>)
+ : MutableMap<String, JsonNode> {
+
+ // Populate Dummy Resource Assignments
+ val resourceAssignments = createResourceAssignments(resourceDefinitions, resolveDefinition, sources)
+
+ resolveResourceAssignments(blueprintRuntimeService, resourceDefinitions, resourceAssignments,
+ UUID.randomUUID().toString(), hashMapOf())
+
+ // Get the data from Resource Assignments
+ return ResourceAssignmentUtils.generateResourceForAssignments(resourceAssignments)
+ }
+
/**
* Iterate the Batch, get the Resource Assignment, dictionary Name, Look for the Resource definition for the
* name, then get the type of the Resource Definition, Get the instance for the Resource Type and process the
override suspend fun resolveResourceAssignments(blueprintRuntimeService: BluePrintRuntimeService<*>,
resourceDefinitions: MutableMap<String, ResourceDefinition>,
resourceAssignments: MutableList<ResourceAssignment>,
- identifierName: String) {
+ artifactPrefix: String,
+ properties: Map<String, Any>) {
val bulkSequenced = BulkResourceSequencingUtils.process(resourceAssignments)
- val resourceAssignmentRuntimeService =
- ResourceAssignmentUtils.transformToRARuntimeService(blueprintRuntimeService, identifierName)
+
+ // Check the BlueprintRuntime Service Should be ResourceAssignmentRuntimeService
+ val resourceAssignmentRuntimeService = if (blueprintRuntimeService !is ResourceAssignmentRuntimeService) {
+ ResourceAssignmentUtils.transformToRARuntimeService(blueprintRuntimeService, artifactPrefix)
+ } else {
+ blueprintRuntimeService
+ }
+
coroutineScope {
bulkSequenced.forEach { batchResourceAssignments ->
// Execute Non Dependent Assignments in parallel ( ie asynchronously )
- val deferred = batchResourceAssignments.filter { it.name != "*" && it.name != "start" }
+ val deferred = batchResourceAssignments
+ .filter { it.name != "*" && it.name != "start" }
+ .filter { it.status != BluePrintConstants.STATUS_SUCCESS }
.map { resourceAssignment ->
async {
val dictionaryName = resourceAssignment.dictionaryName
val dictionarySource = resourceAssignment.dictionarySource
- /**
- * Get the Processor name
- */
+
val processorName = processorName(dictionaryName!!, dictionarySource!!, resourceDefinitions)
val resourceAssignmentProcessor =
resourceAssignmentProcessor.resourceDictionaries = resourceDefinitions
// Invoke Apply Method
resourceAssignmentProcessor.applyNB(resourceAssignment)
+
+ if (isToStore(properties)) {
+ resourceResolutionDBService.write(properties,
+ blueprintRuntimeService,
+ artifactPrefix,
+ resourceAssignment)
+ log.info("Resource resolution saved into database successfully : ($resourceAssignment)")
+ }
+
// Set errors from RA
blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
} catch (e: RuntimeException) {
+ log.error("Fail in processing ${resourceAssignment.name}", e)
throw BluePrintProcessorException(e)
}
}
}
-
/**
* If the Source instance is "input", then it is not mandatory to have source Resource Definition, So it can
* derive the default input processor.
return processorName
}
+
+ // Check whether to store or not the resolution of resource and template
+ private fun isToStore(properties: Map<String, Any>): Boolean {
+ return properties.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT)
+ && properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] as Boolean
+ }
+
+ // Check whether resolution already exist in the database for the specified resolution-key or resourceId/resourceType
+ private suspend fun isNewResolution(bluePrintRuntimeService: BluePrintRuntimeService<*>,
+ properties: Map<String, Any>,
+ artifactPrefix: String): List<ResourceResolution> {
+ val occurrence = properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] as Int
+ 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
+
+ if (resolutionKey.isNotEmpty()) {
+ val existingResourceAssignments =
+ resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
+ bluePrintRuntimeService,
+ resolutionKey,
+ occurrence,
+ artifactPrefix)
+ if (existingResourceAssignments.isNotEmpty()) {
+ log.info("Resolution with resolutionKey=($resolutionKey) already exist - will resolve all resources not already resolved.",
+ resolutionKey)
+ }
+ return existingResourceAssignments
+ } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) {
+ val existingResourceAssignments =
+ resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
+ bluePrintRuntimeService,
+ resourceId,
+ resourceType,
+
+ occurrence,
+ artifactPrefix)
+ if (existingResourceAssignments.isNotEmpty()) {
+ log.info("Resolution with resourceId=($resourceId) and resourceType=($resourceType) already exist - will resolve " +
+ "all resources not already resolved.")
+ }
+ return existingResourceAssignments
+ }
+ return emptyList()
+ }
+
+ // Update the resource assignment list with the status of the resource that have already been resolved
+ private fun updateResourceAssignmentWithExisting(raRuntimeService : ResourceAssignmentRuntimeService,
+ resourceResolutionList: List<ResourceResolution>,
+ resourceAssignmentList: MutableList<ResourceAssignment>) {
+ resourceResolutionList.forEach { resourceResolution ->
+ if (resourceResolution.status == BluePrintConstants.STATUS_SUCCESS) {
+ resourceAssignmentList.forEach {
+ if (compareOne(resourceResolution, it)) {
+ log.info("Resource ({}) already resolve: value=({})", it.name, resourceResolution.value)
+ val value = resourceResolution.value!!.asJsonPrimitive()
+ it.property!!.value = value
+ it.status = resourceResolution.status
+ ResourceAssignmentUtils.setResourceDataValue(it, raRuntimeService, value)
+ }
+ }
+ }
+ }
+ }
+
+ // Comparision between what we have in the database vs what we have to assign.
+ private fun compareOne(resourceResolution: ResourceResolution, resourceAssignment: ResourceAssignment): Boolean {
+ return (resourceResolution.name == resourceAssignment.name
+ && resourceResolution.dictionaryName == resourceAssignment.dictionaryName
+ && resourceResolution.dictionarySource == resourceAssignment.dictionarySource
+ && resourceResolution.dictionaryVersion == resourceAssignment.version)
+ }
+
}