Eliminate Template Requirement 18/100818/8
authorJozsef Csongvai <jozsef.csongvai@bell.ca>
Tue, 21 Jan 2020 16:27:14 +0000 (11:27 -0500)
committerJozsef Csongvai <jozsef.csongvai@bell.ca>
Fri, 21 Feb 2020 15:42:19 +0000 (10:42 -0500)
Enables resource assignment without the use of a template.
If no template is defined by the CBA, the default output is
a kev-value map. If operation input: resolution-summary is set
to true, output will be a list of ResolutionSummary.

Issue-ID: CCSDK-2038
Change-Id: I5f6bcefcacec6e83cffac1134b13690b500a7563
Signed-off-by: Jozsef Csongvai <jozsef.csongvai@bell.ca>
17 files changed:
components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/activation-blueprint.json
components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/notemplate-mapping.json [new file with mode: 0644]
components/model-catalog/definition-type/starter-type/node_type/component-resource-resolution.json
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponent.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponentDSL.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionConstants.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionService.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtils.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionComponentDSLTest.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/ResourceResolutionServiceTest.kt
ms/blueprintsprocessor/functions/resource-resolution/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtilsTest.kt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintConstants.kt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintTemplateService.kt
ms/blueprintsprocessor/modules/blueprints/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/utils/JacksonUtils.kt
ms/blueprintsprocessor/modules/blueprints/resource-dict/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/resource/dict/ResourceDefinition.kt

index 639c214..85a056c 100644 (file)
           "another-mapping": {
             "type": "artifact-mapping-resource",
             "file": "Definitions/another-mapping.json"
+          },
+          "notemplate-mapping": {
+            "type": "artifact-mapping-resource",
+            "file": "Definitions/notemplate-mapping.json"
           }
         }
       },
diff --git a/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/notemplate-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/baseconfiguration/Definitions/notemplate-mapping.json
new file mode 100644 (file)
index 0000000..5aa3b3d
--- /dev/null
@@ -0,0 +1,36 @@
+[
+  {
+    "name": "service-instance-id",
+    "input-param": true,
+    "property": {
+      "type": "string"
+    },
+    "dictionary-name": "service-instance-id",
+    "dictionary-source": "input",
+    "dependencies": [
+    ]
+  },
+  {
+    "name": "vnf-id",
+    "input-param": true,
+    "property": {
+      "type": "string"
+    },
+    "dictionary-name": "vnf-id",
+    "dictionary-source": "input",
+    "dependencies": []
+  },
+  {
+    "name": "vnf_name",
+    "input-param": false,
+    "property": {
+      "type": "string"
+    },
+    "dictionary-name": "vnf_name",
+    "dictionary-source": "sdnc",
+    "dependencies": [
+      "service-instance-id",
+      "vnf-id"
+    ]
+  }
+]
\ No newline at end of file
index 1c81b7f..ff1b526 100644 (file)
               "required": false,
               "type": "string"
             },
+            "resolution-summary": {
+              "description": "Enable resolution-summary output",
+              "required": false,
+              "type": "boolean"
+            },
             "artifact-prefix-names": {
               "required": true,
               "description": "Template , Resource Assignment Artifact Prefix names",
index db0a6f0..3c95ea7 100644 (file)
@@ -43,6 +43,7 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re
         const val INPUT_RESOURCE_TYPE = "resource-type"
         const val INPUT_ARTIFACT_PREFIX_NAMES = "artifact-prefix-names"
         const val INPUT_RESOLUTION_KEY = "resolution-key"
+        const val INPUT_RESOLUTION_SUMMARY = "resolution-summary"
         const val INPUT_STORE_RESULT = "store-result"
         const val INPUT_OCCURRENCE = "occurrence"
 
@@ -64,6 +65,8 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re
 
         val resourceType =
             getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE)?.returnNullIfMissing()?.textValue() ?: ""
+        val resolutionSummary =
+                getOptionalOperationInput(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY)?.asBoolean() ?: false
 
         val properties: MutableMap<String, Any> = mutableMapOf()
         properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_STORE_RESULT] = storeResult
@@ -71,6 +74,7 @@ open class ResourceResolutionComponent(private val resourceResolutionService: Re
         properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId
         properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType
         properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = resolutionSummary
 
         val jsonResponse = JsonNodeFactory.instance.objectNode()
         // Initialize Output Attribute to empty JSON
index 6573d0e..fd104d3 100644 (file)
@@ -81,6 +81,11 @@ fun BluePrintTypes.nodeTypeComponentResourceResolution(): NodeType {
                     false, "Key for service instance related correlation."
                 )
 
+                property(
+                    ResourceResolutionComponent.INPUT_RESOLUTION_SUMMARY, BluePrintConstants.DATA_TYPE_BOOLEAN,
+                        false, "Enables ResolutionSummary output"
+                )
+
                 property(
                     ResourceResolutionComponent.INPUT_OCCURRENCE, BluePrintConstants.DATA_TYPE_INTEGER,
                     false, "Number of time to perform the resolution."
@@ -176,6 +181,12 @@ class ComponentResourceResolutionNodeTemplateBuilder(id: String, description: St
             property(ResourceResolutionComponent.INPUT_RESOLUTION_KEY, resolutionKey)
         }
 
+        fun resolutionSummary(resolutionSummary: Boolean) = resolutionSummary(resolutionSummary.asJsonPrimitive())
+
+        fun resolutionSummary(resolutionSummary: JsonNode) {
+            property(ResourceResolutionComponent.INPUT_RESOLUTION_SUMMARY, resolutionSummary)
+        }
+
         fun dynamicProperties(dynamicProperties: String) = dynamicProperties(dynamicProperties.asJsonType())
 
         fun dynamicProperties(dynamicProperties: JsonNode) {
index 7272a3d..dff00c7 100644 (file)
@@ -147,7 +147,7 @@ open class ResourceResolutionServiceImpl(
         properties: Map<String, Any>
     ): String {
 
-        // Velocity Artifact Definition Name
+        // Template Artifact Definition Name
         val artifactTemplate = "$artifactPrefix-template"
         // Resource Assignment Artifact Definition Name
         val artifactMapping = "$artifactPrefix-mapping"
@@ -185,22 +185,28 @@ open class ResourceResolutionServiceImpl(
             properties
         )
 
+        val resolutionSummary = properties.getOrDefault(ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY, false) as Boolean
         val resolvedParamJsonContent =
             ResourceAssignmentUtils.generateResourceDataForAssignments(resourceAssignments.toList())
-
         val artifactTemplateDefinition = bluePrintRuntimeService.bluePrintContext().checkNodeTemplateArtifact(nodeTemplateName, artifactTemplate)
 
-        val resolvedContent = if (artifactTemplateDefinition != null) {
-            blueprintTemplateService.generateContent(
-                bluePrintRuntimeService, nodeTemplateName,
-                artifactTemplate, resolvedParamJsonContent, false,
-                mutableMapOf(
-                    ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE to
-                            properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE].asJsonPrimitive()
+        val resolvedContent = when {
+            artifactTemplateDefinition != null -> {
+                blueprintTemplateService.generateContent(
+                        bluePrintRuntimeService, nodeTemplateName,
+                        artifactTemplate, resolvedParamJsonContent, false,
+                        mutableMapOf(
+                                ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE to
+                                        properties[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE].asJsonPrimitive()
+                        )
                 )
-            )
-        } else {
-            resolvedParamJsonContent
+            }
+            resolutionSummary -> {
+                ResourceAssignmentUtils.generateResolutionSummaryData(resourceAssignments, resourceDefinitions)
+            }
+            else -> {
+                resolvedParamJsonContent
+            }
         }
 
         if (isToStore(properties)) {
index e43b45e..0bfd7e4 100644 (file)
@@ -28,6 +28,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.isNotEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.nullToEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.KeyIdentifier
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDictionaryConstants
 import org.slf4j.LoggerFactory
@@ -91,6 +92,11 @@ open class DatabaseResourceAssignmentProcessor(
             "failed to get input-key-mappings for $dName under $dSource properties"
         }
 
+        sourceProperties.inputKeyMapping
+                ?.mapValues { raRuntimeService.getDictionaryStore(it.value) }
+                ?.map { KeyIdentifier(it.key, it.value) }
+                ?.let { resourceAssignment.keyIdentifiers.addAll(it) }
+
         logger.info(
             "DatabaseResource ($dSource) dictionary information: " +
                     "Query:($sql), input-key-mapping:($inputKeyMapping), output-key-mapping:(${sourceProperties.outputKeyMapping})"
index 2ff5c44..1023340 100644 (file)
@@ -27,6 +27,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.isNotEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.nullToEmpty
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.KeyIdentifier
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.config.ConfigurableBeanFactory
@@ -75,6 +76,11 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS
                     checkNotNull(sourceProperties.inputKeyMapping) { "failed to get input-key-mappings for $dName under $dSource properties" }
                 val resolvedInputKeyMapping = resolveInputKeyMappingVariables(inputKeyMapping).toMutableMap()
 
+                sourceProperties.inputKeyMapping
+                        ?.mapValues { raRuntimeService.getDictionaryStore(it.value) }
+                        ?.map { KeyIdentifier(it.key, it.value) }
+                        ?.let { resourceAssignment.keyIdentifiers.addAll(it) }
+
                 // Resolving content Variables
                 val payload = resolveFromInputKeyMapping(nullToEmpty(sourceProperties.payload), resolvedInputKeyMapping)
                 val urlPath =
index 7ffc6db..7101735 100644 (file)
@@ -42,6 +42,8 @@ import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeServ
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.PropertyDefinitionUtils.Companion.hasLogProtect
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.KeyIdentifier
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResolutionSummary
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition
 import org.slf4j.LoggerFactory
@@ -196,6 +198,22 @@ class ResourceAssignmentUtils {
             return data
         }
 
+        fun generateResolutionSummaryData(
+            resourceAssignments: List<ResourceAssignment>,
+            resourceDefinitions: Map<String, ResourceDefinition>
+        ): String {
+            val resolutionSummaryList = resourceAssignments.map {
+                val payload = resourceDefinitions[it.name]
+                        ?.sources?.get(it.dictionarySource)?.properties?.get("payload")
+                ResolutionSummary(
+                        it.name, it.property?.value, it.property?.required,
+                        it.property?.type, it.keyIdentifiers, it.dictionaryName,
+                        payload, it.dictionarySource, it.status, it.message
+                )
+            }
+            return JacksonUtils.getJson(resolutionSummaryList, includeNull = true)
+        }
+
         private fun useDefaultValueIfNull(
             resourceAssignment: ResourceAssignment,
             resourceAssignmentName: String
@@ -263,7 +281,7 @@ class ResourceAssignmentUtils {
                 return when (type) {
                     in BluePrintTypes.validPrimitiveTypes() -> {
                         // Primitive Types
-                        parseResponseNodeForPrimitiveTypes(responseNode, outputKeyMapping)
+                        parseResponseNodeForPrimitiveTypes(responseNode, resourceAssignment, outputKeyMapping)
                     }
                     in BluePrintTypes.validCollectionTypes() -> {
                         // Array Types
@@ -282,6 +300,7 @@ class ResourceAssignmentUtils {
 
         private fun parseResponseNodeForPrimitiveTypes(
             responseNode: JsonNode,
+            resourceAssignment: ResourceAssignment,
             outputKeyMapping: MutableMap<String, String>
         ): JsonNode {
             // Return responseNode if is not a Complex Type
@@ -306,11 +325,16 @@ class ResourceAssignmentUtils {
             if (returnNode.isNullOrMissing() || returnNode!!.isComplexType() && !returnNode.has(outputKeyMapping[outputKey])) {
                 throw BluePrintProcessorException("Fail to find output key mapping ($outputKey) in the responseNode.")
             }
-            return if (returnNode.isComplexType()) {
+
+            val returnValue = if (returnNode.isComplexType()) {
                 returnNode[outputKeyMapping[outputKey]]
             } else {
                 returnNode
             }
+
+            outputKey?.let { KeyIdentifier(it, returnValue) }
+                ?.let { resourceAssignment.keyIdentifiers.add(it) }
+            return returnValue
         }
 
         private fun parseResponseNodeForCollection(
@@ -337,7 +361,7 @@ class ResourceAssignmentUtils {
                         val responseArrayNode = responseNode.toList()
                         for (responseSingleJsonNode in responseArrayNode) {
                             val arrayChildNode = parseSingleElementOfArrayResponseNode(
-                                entrySchemaType,
+                                entrySchemaType, resourceAssignment,
                                 outputKeyMapping, raRuntimeService, responseSingleJsonNode, metadata
                             )
                             arrayNode.add(arrayChildNode)
@@ -347,7 +371,10 @@ class ResourceAssignmentUtils {
                     is ObjectNode -> {
                         val responseArrayNode = responseNode.rootFieldsToMap()
                         resultNode =
-                            parseObjectResponseNode(entrySchemaType, outputKeyMapping, responseArrayNode, metadata)
+                            parseObjectResponseNode(
+                                resourceAssignment, entrySchemaType, outputKeyMapping,
+                                responseArrayNode, metadata
+                            )
                     }
                     else -> {
                         throw BluePrintProcessorException("Key-value response expected to match the responseNode.")
@@ -387,6 +414,7 @@ class ResourceAssignmentUtils {
 
         private fun parseSingleElementOfArrayResponseNode(
             entrySchemaType: String,
+            resourceAssignment: ResourceAssignment,
             outputKeyMapping: MutableMap<String, String>,
             raRuntimeService: ResourceAssignmentRuntimeService,
             responseNode: JsonNode,
@@ -397,7 +425,13 @@ class ResourceAssignmentUtils {
                 in BluePrintTypes.validPrimitiveTypes() -> {
                     if (outputKeyMappingHasOnlyOneElement) {
                         val outputKeyMap = outputKeyMapping.entries.first()
+                        if (resourceAssignment.keyIdentifiers.none { it.name == outputKeyMap.key }) {
+                            resourceAssignment.keyIdentifiers.add(
+                                    KeyIdentifier(outputKeyMap.key, JacksonUtils.objectMapper.createArrayNode())
+                            )
+                        }
                         return parseSingleElementNodeWithOneOutputKeyMapping(
+                            resourceAssignment,
                             responseNode,
                             outputKeyMap.key,
                             outputKeyMap.value,
@@ -416,6 +450,7 @@ class ResourceAssignmentUtils {
                             raRuntimeService
                         ) -> {
                             parseSingleElementNodeWithAllOutputKeyMapping(
+                                resourceAssignment,
                                 responseNode,
                                 outputKeyMapping,
                                 entrySchemaType,
@@ -425,6 +460,7 @@ class ResourceAssignmentUtils {
                         outputKeyMappingHasOnlyOneElement -> {
                             val outputKeyMap = outputKeyMapping.entries.first()
                             parseSingleElementNodeWithOneOutputKeyMapping(
+                                resourceAssignment,
                                 responseNode,
                                 outputKeyMap.key,
                                 outputKeyMap.value,
@@ -441,6 +477,7 @@ class ResourceAssignmentUtils {
         }
 
         private fun parseObjectResponseNode(
+            resourceAssignment: ResourceAssignment,
             entrySchemaType: String,
             outputKeyMapping: MutableMap<String, String>,
             responseArrayNode: MutableMap<String, JsonNode>,
@@ -449,19 +486,21 @@ class ResourceAssignmentUtils {
             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
             if (outputKeyMappingHasOnlyOneElement) {
                 val outputKeyMap = outputKeyMapping.entries.first()
-                return parseObjectResponseNodeWithOneOutputKeyMapping(
+                val returnValue = parseObjectResponseNodeWithOneOutputKeyMapping(
                     responseArrayNode, outputKeyMap.key, outputKeyMap.value,
                     entrySchemaType, metadata
                 )
+                resourceAssignment.keyIdentifiers.add(KeyIdentifier(outputKeyMap.key, returnValue))
+                return returnValue
             } else {
                 throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
             }
         }
 
         private fun parseSingleElementNodeWithOneOutputKeyMapping(
+            resourceAssignment: ResourceAssignment,
             responseSingleJsonNode: JsonNode,
-            outputKeyMappingKey:
-            String,
+            outputKeyMappingKey: String,
             outputKeyMappingValue: String,
             type: String,
             metadata: MutableMap<String, String>?
@@ -476,11 +515,19 @@ class ResourceAssignmentUtils {
 
             logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseKeyValue, type)
             JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseKeyValue, type, arrayChildNode)
-
+            resourceAssignment.keyIdentifiers.find { it.name == outputKeyMappingKey && it.value.isArray }
+                    .let {
+                        if (it != null)
+                            (it.value as ArrayNode).add(responseKeyValue)
+                        else
+                            resourceAssignment.keyIdentifiers.add(
+                                    KeyIdentifier(outputKeyMappingKey, responseKeyValue))
+                    }
             return arrayChildNode
         }
 
         private fun parseSingleElementNodeWithAllOutputKeyMapping(
+            resourceAssignment: ResourceAssignment,
             responseSingleJsonNode: JsonNode,
             outputKeyMapping: MutableMap<String, String>,
             type: String,
@@ -496,6 +543,7 @@ class ResourceAssignmentUtils {
 
                 logKeyValueResolvedResource(metadata, it.key, responseKeyValue, type)
                 JacksonUtils.populateJsonNodeValues(it.key, responseKeyValue, type, arrayChildNode)
+                resourceAssignment.keyIdentifiers.add(KeyIdentifier(it.key, responseKeyValue))
             }
             return arrayChildNode
         }
@@ -541,6 +589,7 @@ class ResourceAssignmentUtils {
                         raRuntimeService
                     ) -> {
                         parseSingleElementNodeWithAllOutputKeyMapping(
+                            resourceAssignment,
                             responseNode,
                             outputKeyMapping,
                             entrySchemaType,
@@ -550,8 +599,8 @@ class ResourceAssignmentUtils {
                     outputKeyMappingHasOnlyOneElement -> {
                         val outputKeyMap = outputKeyMapping.entries.first()
                         parseSingleElementNodeWithOneOutputKeyMapping(
-                            responseNode, outputKeyMap.key, outputKeyMap.value,
-                            entrySchemaType, metadata
+                            resourceAssignment, responseNode, outputKeyMap.key,
+                            outputKeyMap.value, entrySchemaType, metadata
                         )
                     }
                     else -> {
index ae9b420..d134711 100644 (file)
@@ -41,6 +41,7 @@ class ResourceResolutionComponentDSLTest {
                     occurrence(2)
                     resourceType("vnf")
                     storeResult(false)
+                    resolutionSummary(true)
                     artifactPrefixNames(arrayListOf("template1", "template2"))
                     dynamicProperties(
                         """{
index 2f338a3..0a12540 100644 (file)
@@ -36,6 +36,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintContext
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResolutionSummary
 import org.slf4j.LoggerFactory
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration
@@ -44,6 +45,7 @@ import org.springframework.context.annotation.ComponentScan
 import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.TestPropertySource
 import org.springframework.test.context.junit4.SpringRunner
+import kotlin.test.assertEquals
 import kotlin.test.assertNotNull
 import kotlin.test.assertTrue
 
@@ -79,6 +81,7 @@ class ResourceResolutionServiceTest {
         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_ID] = resourceId
         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE] = resourceType
         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_OCCURRENCE] = occurrence
+        props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = false
     }
 
     @Test
@@ -213,6 +216,100 @@ class ResourceResolutionServiceTest {
         }
     }
 
+    @Test
+    @Throws(Exception::class)
+    fun testResolveResourcesResolutionSummary() {
+        runBlocking {
+            props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_SUMMARY] = true
+            Assert.assertNotNull("failed to create ResourceResolutionService", resourceResolutionService)
+
+            val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(
+                    "1234",
+                    "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration"
+            )
+
+            val executionServiceInput =
+                    JacksonUtils.readValueFromClassPathFile(
+                            "payload/requests/sample-resourceresolution-request.json",
+                            ExecutionServiceInput::class.java
+                    )!!
+
+            val resourceAssignmentRuntimeService =
+                    ResourceAssignmentUtils.transformToRARuntimeService(
+                            bluePrintRuntimeService,
+                            "testResolveResourcesWithMappingAndTemplate"
+                    )
+
+            val artifactPrefix = "notemplate"
+
+            // Prepare Inputs
+            PayloadUtils.prepareInputsFromWorkflowPayload(
+                    bluePrintRuntimeService,
+                    executionServiceInput.payload,
+                    "resource-assignment"
+            )
+
+            resourceResolutionService.resolveResources(
+                    resourceAssignmentRuntimeService,
+                    "resource-assignment",
+                    artifactPrefix,
+                    props
+            )
+        }.let {
+            val list = JacksonUtils.getListFromJson(it, ResolutionSummary::class.java)
+            assertEquals(list.size, 3)
+        }
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun testResolveResourcesWithoutTemplate() {
+        runBlocking {
+            Assert.assertNotNull("failed to create ResourceResolutionService", resourceResolutionService)
+
+            val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime(
+                    "1234",
+                    "./../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration"
+            )
+
+            val executionServiceInput =
+                    JacksonUtils.readValueFromClassPathFile(
+                            "payload/requests/sample-resourceresolution-request.json",
+                            ExecutionServiceInput::class.java
+                    )!!
+
+            val resourceAssignmentRuntimeService =
+                    ResourceAssignmentUtils.transformToRARuntimeService(
+                            bluePrintRuntimeService,
+                            "testResolveResourcesWithMappingAndTemplate"
+                    )
+
+            val artifactPrefix = "notemplate"
+
+            // Prepare Inputs
+            PayloadUtils.prepareInputsFromWorkflowPayload(
+                    bluePrintRuntimeService,
+                    executionServiceInput.payload,
+                    "resource-assignment"
+            )
+
+            resourceResolutionService.resolveResources(
+                    resourceAssignmentRuntimeService,
+                    "resource-assignment",
+                    artifactPrefix,
+                    props
+            )
+        }.let {
+            assertEquals("""
+                {
+                  "service-instance-id" : "siid_1234",
+                  "vnf-id" : "vnf_1234",
+                  "vnf_name" : "temp_vnf"
+                }
+            """.trimIndent(), it)
+        }
+    }
+
     @Test
     fun testResolveResourcesWithResourceIdAndResourceType() {
         props[ResourceResolutionConstants.RESOURCE_RESOLUTION_INPUT_RESOLUTION_KEY] = ""
index 3251dca..8ca4016 100644 (file)
@@ -33,10 +33,12 @@ import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType
 import org.onap.ccsdk.cds.controllerblueprints.core.data.DataType
 import org.onap.ccsdk.cds.controllerblueprints.core.data.EntrySchema
+import org.onap.ccsdk.cds.controllerblueprints.core.data.NodeTemplate
 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils
 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition
 import kotlin.test.assertEquals
 
 data class IpAddress(val port: String, val ip: String)
@@ -46,6 +48,7 @@ data class ExpectedResponseIpAddress(val ipAddress: IpAddress)
 
 class ResourceAssignmentUtilsTest {
     private lateinit var resourceAssignmentRuntimeService: ResourceAssignmentRuntimeService
+    private lateinit var resourceAssignment: ResourceAssignment
 
     private lateinit var inputMapToTestPrimitiveTypeWithValue: JsonNode
     private lateinit var inputMapToTestPrimitiveTypeWithKeyValue: JsonNode
@@ -156,6 +159,34 @@ class ResourceAssignmentUtilsTest {
         assertEquals(expected, outcome.replace("\r\n", "\n"), "unexpected outcome generated")
     }
 
+    @Test
+    fun generate() {
+        val resourceAssignment = createResourceAssignmentForTest(null)
+        val resourceDefinition = ResourceDefinition()
+        val nodeTemplate = NodeTemplate().apply {
+            properties = mutableMapOf("payload" to JacksonUtils.jsonNode("{\"mock\": true}"))
+        }
+        resourceDefinition.sources = mutableMapOf("input" to nodeTemplate)
+
+        val result = ResourceAssignmentUtils.generateResolutionSummaryData(
+                listOf(resourceAssignment), mapOf("pnf-id" to resourceDefinition))
+
+        assertEquals("""
+            [{
+                "name":"pnf-id",
+                "value":null,
+                "required":null,
+                "type":"string",
+                "key-identifiers":[],
+                "dictionary-name":"pnf-id",
+                "request-payload":{"mock":true},
+                "dictionary-source":"input",
+                "status":null,
+                "message":null
+            }]
+        """.replace("\n|\\s".toRegex(), ""), result)
+    }
+
     private fun createResourceAssignmentForTest(resourceValue: String?): ResourceAssignment {
         val valueForTest = if (resourceValue == null) null else TextNode(resourceValue)
         val resourceAssignmentForTest = ResourceAssignment().apply {
@@ -181,6 +212,7 @@ class ResourceAssignmentUtilsTest {
             outcome,
             "Unexpected outcome returned for primitive type of simple String"
         )
+        assertEquals(0, resourceAssignment.keyIdentifiers.size)
 
         outcome = prepareResponseNodeForTest(
             "sample-key-value", "string", "",
@@ -191,6 +223,10 @@ class ResourceAssignmentUtilsTest {
             outcome,
             "Unexpected outcome returned for primitive type of key-value String"
         )
+        assertEquals(
+                expectedValueToTestPrimitiveType,
+                resourceAssignment.keyIdentifiers[0].value
+        )
     }
 
     @Test
@@ -204,6 +240,13 @@ class ResourceAssignmentUtilsTest {
             outcome,
             "unexpected outcome returned for list of String"
         )
+
+        val expectedKeyIdentifierValue = JacksonUtils.getJsonNode(outcome.map { it["ip"] })
+        assertEquals(
+                expectedKeyIdentifierValue,
+                resourceAssignment.keyIdentifiers[0].value
+        )
+
         // FIXME("Map is not collection type, It is known complex type")
         // outcome = prepareResponseNodeForTest(
         //     "mapOfString", "map", "string",
@@ -250,6 +293,9 @@ class ResourceAssignmentUtilsTest {
             outcome,
             "Unexpected outcome returned for complex type"
         )
+        assertEquals(
+                expectedValueToTestComplexTypeWithOneOutputKeyMapping["host"],
+                resourceAssignment.keyIdentifiers[0].value)
     }
 
     @Test
@@ -263,6 +309,16 @@ class ResourceAssignmentUtilsTest {
             outcome,
             "Unexpected outcome returned for complex type"
         )
+        assertEquals(2, resourceAssignment.keyIdentifiers.size)
+        assertEquals(
+                expectedValueToTestComplexTypeWithAllOutputKeyMapping["name"],
+                resourceAssignment.keyIdentifiers[0].value
+        )
+
+        assertEquals(
+                expectedValueToTestComplexTypeWithAllOutputKeyMapping["ipAddress"],
+                resourceAssignment.keyIdentifiers[1].value
+        )
     }
 
     private fun initInputMapAndExpectedValuesForPrimitiveType() {
@@ -359,7 +415,7 @@ class ResourceAssignmentUtilsTest {
         response: Any
     ): JsonNode {
 
-        val resourceAssignment = when (sourceType) {
+        resourceAssignment = when (sourceType) {
             "list" -> {
                 prepareRADataDictionaryCollection(dictionary_source, sourceType, entrySchema)
             }
index 20aef34..5002810 100644 (file)
@@ -218,9 +218,6 @@ object BluePrintConstants {
     const val DEFAULT_STEP_OPERATION = "process"
     const val DEFAULT_STEP_INTERFACE = "ComponentInterface"
 
-    const val ARTIFACT_VELOCITY_TYPE_NAME = "artifact-template-velocity"
-    const val ARTIFACT_JINJA_TYPE_NAME = "artifact-template-jinja"
-
     const val MODEL_TYPE_ARTIFACT_TEMPLATE_VELOCITY = "artifact-template-velocity"
     const val MODEL_TYPE_ARTIFACT_TEMPLATE_JINJA = "artifact-template-jinja"
     const val MODEL_TYPE_ARTIFACT_MAPPING_RESOURCE = "artifact-mapping-resource"
index db733bd..51a6e10 100644 (file)
@@ -40,7 +40,7 @@ class BluePrintTemplateService(private val bluePrintLoadConfiguration: BluePrint
         val template = bluePrintRuntimeService.resolveNodeTemplateArtifact(nodeTemplateName, artifactName)
 
         return when (templateType) {
-            BluePrintConstants.ARTIFACT_JINJA_TYPE_NAME -> {
+            BluePrintConstants.MODEL_TYPE_ARTIFACT_TEMPLATE_JINJA -> {
                 BluePrintJinjaTemplateService.generateContent(
                     template,
                     jsonData,
@@ -51,13 +51,13 @@ class BluePrintTemplateService(private val bluePrintLoadConfiguration: BluePrint
                     bluePrintRuntimeService.bluePrintContext().version()
                 )
             }
-            BluePrintConstants.ARTIFACT_VELOCITY_TYPE_NAME -> {
+            BluePrintConstants.MODEL_TYPE_ARTIFACT_TEMPLATE_VELOCITY -> {
                 BluePrintVelocityTemplateService.generateContent(template, jsonData, ignoreJsonNull, additionalContext)
             }
             else -> {
                 throw BluePrintProcessorException(
-                    "Unknown Artifact type, expecting ${BluePrintConstants.ARTIFACT_JINJA_TYPE_NAME}" +
-                            "or ${BluePrintConstants.ARTIFACT_VELOCITY_TYPE_NAME}"
+                    "Unknown Artifact type, expecting ${BluePrintConstants.MODEL_TYPE_ARTIFACT_TEMPLATE_JINJA}" +
+                            "or ${BluePrintConstants.MODEL_TYPE_ARTIFACT_TEMPLATE_VELOCITY}"
                 )
             }
         }
index 3db1f84..573fc17 100644 (file)
@@ -133,9 +133,13 @@ class JacksonUtils {
             return getJson(wrapperMap, pretty)
         }
 
-        fun getJson(any: kotlin.Any, pretty: Boolean = false): String {
+        fun getJson(any: kotlin.Any, pretty: Boolean = false, includeNull: Boolean = false): String {
             val objectMapper = jacksonObjectMapper()
-            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            if (includeNull) {
+                objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS)
+            } else {
+                objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
+            }
             if (pretty) {
                 objectMapper.enable(SerializationFeature.INDENT_OUTPUT)
             }
index 4ed98dd..f34099e 100644 (file)
@@ -19,6 +19,7 @@ package org.onap.ccsdk.cds.controllerblueprints.resource.dict
 
 import com.fasterxml.jackson.annotation.JsonFormat
 import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.databind.JsonNode
 import org.onap.ccsdk.cds.controllerblueprints.core.data.NodeTemplate
 import org.onap.ccsdk.cds.controllerblueprints.core.data.PropertyDefinition
 import java.io.Serializable
@@ -87,6 +88,9 @@ open class ResourceAssignment {
     @JsonProperty("updated-by")
     var updatedBy: String? = null
 
+    /** input & output key-mapping with their resolved values **/
+    var keyIdentifiers: MutableList<KeyIdentifier> = mutableListOf()
+
     override fun toString(): String {
         return """
             [
@@ -101,6 +105,29 @@ open class ResourceAssignment {
     }
 }
 
+data class KeyIdentifier(val name: String, val value: JsonNode)
+
+/**
+ * Data class for exposing summary of resource resolution
+ */
+data class ResolutionSummary(
+    val name: String,
+    val value: JsonNode?,
+    val required: Boolean?,
+    val type: String?,
+    @JsonProperty("key-identifiers")
+    val keyIdentifiers: MutableList<KeyIdentifier>,
+    @JsonProperty("dictionary-name")
+    val dictionaryName: String?,
+    @JsonProperty("request-payload")
+    val requestPayload: JsonNode?,
+    @JsonProperty("dictionary-source")
+    val dictionarySource: String?,
+    @JsonProperty("status")
+    val status: String?,
+    @JsonProperty("message")
+    val message: String?
+)
 /**
  * Interface for Source Definitions (ex Input Source,
  * Default Source, Database Source, Rest Sources, etc)