Merge "Resource resolution should return a string"
[ccsdk/cds.git] / ms / blueprintsprocessor / functions / resource-resolution / src / main / kotlin / org / onap / ccsdk / cds / blueprintsprocessor / functions / resource / resolution / ResourceResolutionService.kt
index 0e97267..641175c 100644 (file)
@@ -17,6 +17,7 @@
 
 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
@@ -25,10 +26,8 @@ import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.db.R
 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.BluePrintConstants
-import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
-import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
-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
@@ -38,6 +37,7 @@ import org.onap.ccsdk.cds.controllerblueprints.resource.dict.utils.BulkResourceS
 import org.slf4j.LoggerFactory
 import org.springframework.context.ApplicationContext
 import org.springframework.stereotype.Service
+import java.util.*
 
 interface ResourceResolutionService {
 
@@ -52,6 +52,14 @@ interface ResourceResolutionService {
     suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
                                  artifactPrefix: String, properties: Map<String, Any>): 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>,
@@ -64,37 +72,37 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
                                          private var templateResolutionDBService: TemplateResolutionService,
                                          private var blueprintTemplateService: BluePrintTemplateService,
                                          private var resourceResolutionDBService: ResourceResolutionDBService) :
-    ResourceResolutionService {
+        ResourceResolutionService {
 
     private val log = LoggerFactory.getLogger(ResourceResolutionService::class.java)
 
     override fun registeredResourceSources(): List<String> {
         return applicationContext.getBeanNamesForType(ResourceAssignmentProcessor::class.java)
-            .filter { it.startsWith(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
-            .map { it.substringAfter(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
+                .filter { it.startsWith(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
+                .map { it.substringAfter(ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR) }
     }
 
     override suspend fun resolveFromDatabase(bluePrintRuntimeService: BluePrintRuntimeService<*>,
                                              artifactTemplate: String,
                                              resolutionKey: String): String {
         return templateResolutionDBService.findByResolutionKeyAndBlueprintNameAndBlueprintVersionAndArtifactName(
-            bluePrintRuntimeService,
-            artifactTemplate,
-            resolutionKey)
+                bluePrintRuntimeService,
+                artifactTemplate,
+                resolutionKey)
     }
 
     override suspend fun resolveResources(bluePrintRuntimeService: BluePrintRuntimeService<*>, nodeTemplateName: String,
                                           artifactNames: List<String>,
                                           properties: Map<String, Any>): MutableMap<String, String> {
 
-
         val resourceAssignmentRuntimeService =
-            ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString())
+                ResourceAssignmentUtils.transformToRARuntimeService(bluePrintRuntimeService, artifactNames.toString())
 
         val resolvedParams: MutableMap<String, String> = hashMapOf()
         artifactNames.forEach { artifactName ->
             val resolvedContent = resolveResources(resourceAssignmentRuntimeService, nodeTemplateName,
-                artifactName, properties)
+                    artifactName, properties)
+
             resolvedParams[artifactName] = resolvedContent
         }
         return resolvedParams
@@ -113,36 +121,37 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
         log.info("Resolving resource for template artifact($artifactTemplate) with resource assignment artifact($artifactMapping)")
 
         val resourceAssignmentContent =
-            bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
+                bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactMapping)
 
         val resourceAssignments: MutableList<ResourceAssignment> =
-            JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java)
-                    as? MutableList<ResourceAssignment>
-                ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
+                JacksonUtils.getListFromJson(resourceAssignmentContent, ResourceAssignment::class.java)
+                        as? MutableList<ResourceAssignment>
+                        ?: throw BluePrintProcessorException("couldn't get Dictionary Definitions")
 
         if (isToStore(properties)) {
             val existingResourceResolution = isNewResolution(bluePrintRuntimeService, properties, artifactPrefix)
             if (existingResourceResolution.isNotEmpty()) {
-                updateResourceAssignmentWithExisting(existingResourceResolution, resourceAssignments)
+                updateResourceAssignmentWithExisting(bluePrintRuntimeService as ResourceAssignmentRuntimeService,
+                    existingResourceResolution, resourceAssignments)
             }
         }
 
         // Get the Resource Dictionary Name
         val resourceDefinitions: MutableMap<String, ResourceDefinition> = ResourceAssignmentUtils
-            .resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath)
+                .resourceDefinitions(bluePrintRuntimeService.bluePrintContext().rootPath)
 
         // Resolve resources
         resolveResourceAssignments(bluePrintRuntimeService,
-            resourceDefinitions,
-            resourceAssignments,
-            artifactPrefix,
-            properties)
+                resourceDefinitions,
+                resourceAssignments,
+                artifactPrefix,
+                properties)
 
         val resolvedParamJsonContent =
-            ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
+                ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
 
         resolvedContent = blueprintTemplateService.generateContent(bluePrintRuntimeService, nodeTemplateName,
-            artifactTemplate, resolvedParamJsonContent)
+                artifactTemplate, resolvedParamJsonContent)
 
         if (isToStore(properties)) {
             templateResolutionDBService.write(properties, resolvedContent, bluePrintRuntimeService, artifactPrefix)
@@ -152,6 +161,21 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
         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
@@ -164,49 +188,56 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
                                                     properties: Map<String, Any>) {
 
         val bulkSequenced = BulkResourceSequencingUtils.process(resourceAssignments)
-        val resourceAssignmentRuntimeService = blueprintRuntimeService as ResourceAssignmentRuntimeService
+
+        // 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" }
-                    .filter { it.status != BluePrintConstants.STATUS_SUCCESS }
-                    .map { resourceAssignment ->
-                        async {
-                            val dictionaryName = resourceAssignment.dictionaryName
-                            val dictionarySource = resourceAssignment.dictionarySource
-
-                            val processorName = processorName(dictionaryName!!, dictionarySource!!, resourceDefinitions)
-
-                            val resourceAssignmentProcessor =
-                                applicationContext.getBean(processorName) as? ResourceAssignmentProcessor
-                                    ?: throw BluePrintProcessorException("failed to get resource processor ($processorName) " +
-                                            "for resource assignment(${resourceAssignment.name})")
-                            try {
-                                // Set BluePrint Runtime Service
-                                resourceAssignmentProcessor.raRuntimeService = resourceAssignmentRuntimeService
-                                // Set Resource Dictionaries
-                                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)")
+                        .filter { it.name != "*" && it.name != "start" }
+                        .filter { it.status != BluePrintConstants.STATUS_SUCCESS }
+                        .map { resourceAssignment ->
+                            async {
+                                val dictionaryName = resourceAssignment.dictionaryName
+                                val dictionarySource = resourceAssignment.dictionarySource
+
+                                val processorName = processorName(dictionaryName!!, dictionarySource!!, resourceDefinitions)
+
+                                val resourceAssignmentProcessor =
+                                        applicationContext.getBean(processorName) as? ResourceAssignmentProcessor
+                                                ?: throw BluePrintProcessorException("failed to get resource processor ($processorName) " +
+                                                        "for resource assignment(${resourceAssignment.name})")
+                                try {
+                                    // Set BluePrint Runtime Service
+                                    resourceAssignmentProcessor.raRuntimeService = resourceAssignmentRuntimeService
+                                    // Set Resource Dictionaries
+                                    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)
                                 }
-
-                                // Set errors from RA
-                                blueprintRuntimeService.setBluePrintError(resourceAssignmentRuntimeService.getBluePrintError())
-                            } catch (e: RuntimeException) {
-                                log.error("Fail in processing ${resourceAssignment.name}", e)
-                                throw BluePrintProcessorException(e)
                             }
                         }
-                    }
                 log.debug("Resolving (${deferred.size})resources parallel.")
                 deferred.awaitAll()
             }
@@ -229,10 +260,10 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
             }
             else -> {
                 val resourceDefinition = resourceDefinitions[dictionaryName]
-                    ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
+                        ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dictionaryName")
 
                 val resourceSource = resourceDefinition.sources[dictionarySource]
-                    ?: throw BluePrintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
+                        ?: throw BluePrintProcessorException("couldn't get resource definition $dictionaryName source($dictionarySource)")
 
                 ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR.plus(resourceSource.type)
             }
@@ -262,25 +293,25 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
 
         if (resolutionKey.isNotEmpty()) {
             val existingResourceAssignments =
-                resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResolutionKeyAndOccurrence(
-                    bluePrintRuntimeService,
-                    resolutionKey,
-                    occurrence,
-                    artifactPrefix)
+                    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)
+                        resolutionKey)
             }
             return existingResourceAssignments
         } else if (resourceId.isNotEmpty() && resourceType.isNotEmpty()) {
             val existingResourceAssignments =
-                resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
-                    bluePrintRuntimeService,
-                    resourceId,
-                    resourceType,
+                    resourceResolutionDBService.findByBlueprintNameAndBlueprintVersionAndArtifactNameAndResourceIdAndResourceTypeAndOccurrence(
+                            bluePrintRuntimeService,
+                            resourceId,
+                            resourceType,
 
-                    occurrence,
-                    artifactPrefix)
+                            occurrence,
+                            artifactPrefix)
             if (existingResourceAssignments.isNotEmpty()) {
                 log.info("Resolution with resourceId=($resourceId) and resourceType=($resourceType) already exist - will resolve " +
                         "all resources not already resolved.")
@@ -291,15 +322,18 @@ open class ResourceResolutionServiceImpl(private var applicationContext: Applica
     }
 
     // Update the resource assignment list with the status of the resource that have already been resolved
-    private fun updateResourceAssignmentWithExisting(resourceResolutionList: List<ResourceResolution>,
+    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)
-                        it.property!!.value = resourceResolution.value!!.asJsonPrimitive()
+                        val value = resourceResolution.value!!.asJsonPrimitive()
+                        it.property!!.value = value
                         it.status = resourceResolution.status
+                        ResourceAssignmentUtils.setResourceDataValue(it, raRuntimeService, value)
                     }
                 }
             }