Bug-fix - CDS Processor-DB & Default Dictionary not working 87/95687/13
authorSteve Siani <alphonse.steve.siani.djissitchi@ibm.com>
Fri, 13 Sep 2019 22:09:43 +0000 (18:09 -0400)
committerSteve Siani <alphonse.steve.siani.djissitchi@ibm.com>
Thu, 19 Sep 2019 16:22:02 +0000 (12:22 -0400)
Issue-ID: CCSDK-1718
Signed-off-by: Steve Siani <alphonse.steve.siani.djissitchi@ibm.com>
Change-Id: Ia15f36d7732058161aa2addc9268dd647330f069

Issue-ID: CCSDK-1717
Signed-off-by: Steve Siani <alphonse.steve.siani.djissitchi@ibm.com>
Change-Id: Ia15f36d7732058161aa2addc9268dd647330f069

ms/blueprintsprocessor/application/src/main/resources/application.properties
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/processor/DatabaseResourceAssignmentProcessor.kt
ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/InputResourceResolutionProcessor.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/utils/ResourceAssignmentUtilsTest.kt

index 66c7b35..6d8a4fa 100755 (executable)
@@ -113,4 +113,4 @@ blueprintsprocessor.messageconsumer.self-service-api.pollMillSec=1000
 blueprintsprocessor.messageproducer.self-service-api.type=kafka-basic-auth
 blueprintsprocessor.messageproducer.self-service-api.bootstrapServers=127.0.0.1:9092
 blueprintsprocessor.messageproducer.self-service-api.clientId=default-client-id
-blueprintsprocessor.messageproducer.self-service-api.topic=producer.t
+blueprintsprocessor.messageproducer.self-service-api.topic=producer.t
\ No newline at end of file
index 2a9218d..5370743 100644 (file)
@@ -29,5 +29,5 @@ object ResourceResolutionConstants {
         const val RESOURCE_RESOLUTION_INPUT_OCCURRENCE = "occurrence"
         const val RESOURCE_RESOLUTION_INPUT_RESOURCE_ID = "resource-id"
         const val RESOURCE_RESOLUTION_INPUT_RESOURCE_TYPE = "resource-type"
-        val DATA_DICTIONARY_SECRET_SOURCE_TYPES = arrayOf("vault-data") //Add more secret data dictionary source type here
+        const val RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA = "log-protect"
 }
\ No newline at end of file
index 6645a63..5043c9a 100644 (file)
@@ -57,9 +57,8 @@ open class DatabaseResourceAssignmentProcessor(private val bluePrintDBLibPropert
             // Check if It has Input
             try {
                 val value = raRuntimeService.getInputValue(resourceAssignment.name)
-                if (value.returnNullIfMissing() != null) {
-                    logger.info("processor-db source template key (${resourceAssignment.name}) found from input and value is ($value)")
-                    ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value)
+                if (ResourceAssignmentUtils.checkIfInputWasProvided(resourceAssignment, value)) {
+                    ResourceAssignmentUtils.setInputValueIfProvided(resourceAssignment, raRuntimeService, value)
                 } else {
                     setValueFromDB(resourceAssignment)
                 }
index db51453..f26da14 100644 (file)
@@ -38,8 +38,6 @@ import org.springframework.stereotype.Service
 @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
 open class InputResourceResolutionProcessor : ResourceAssignmentProcessor() {
 
-    private val logger = LoggerFactory.getLogger(InputResourceResolutionProcessor::class.java)
-
     override fun getName(): String {
         return "${PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-input"
     }
@@ -49,9 +47,8 @@ open class InputResourceResolutionProcessor : ResourceAssignmentProcessor() {
             if (isNotEmpty(resourceAssignment.name)) {
                 val value = raRuntimeService.getInputValue(resourceAssignment.name)
                 // if value is null don't call setResourceDataValue to populate the value
-                if (value !is MissingNode && value !is NullNode) {
-                    logger.info("input source template key (${resourceAssignment.name}) found from input and value is ($value)")
-                    ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value)
+                if (ResourceAssignmentUtils.checkIfInputWasProvided(resourceAssignment, value)) {
+                    ResourceAssignmentUtils.setInputValueIfProvided(resourceAssignment, raRuntimeService, value)
                 }
             }
             // Check the value has populated for mandatory case
index 6515b11..ecc2c2b 100644 (file)
@@ -17,9 +17,6 @@
 
 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor
 
-import com.fasterxml.jackson.databind.node.MissingNode
-import com.fasterxml.jackson.databind.node.NullNode
-import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.RestResourceSource
 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
@@ -54,8 +51,11 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS
             validate(resourceAssignment)
 
             // Check if It has Input
-            val value = getFromInput(resourceAssignment)
-            if (value == null || value is MissingNode || value is NullNode) {
+            val value = raRuntimeService.getInputValue(resourceAssignment.name)
+            if (ResourceAssignmentUtils.checkIfInputWasProvided(resourceAssignment, value)) {
+                ResourceAssignmentUtils.setInputValueIfProvided(resourceAssignment, raRuntimeService, value)
+            }
+            else {
                 val dName = resourceAssignment.dictionaryName!!
                 val dSource = resourceAssignment.dictionarySource!!
                 val resourceDefinition = resourceDefinition(dName)
@@ -126,7 +126,7 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS
         val dName = resourceAssignment.dictionaryName
         val dSource = resourceAssignment.dictionarySource
         val type = nullToEmpty(resourceAssignment.property?.type)
-        lateinit var entrySchemaType: String
+        val metadata = resourceAssignment.property!!.metadata
 
         val outputKeyMapping = checkNotNull(sourceProperties.outputKeyMapping) {
             "failed to get output-key-mappings for $dName under $dSource properties"
@@ -136,12 +136,10 @@ open class RestResourceResolutionProcessor(private val blueprintRestLibPropertyS
         val responseNode = checkNotNull(JacksonUtils.jsonNode(restResponse).at(path)) {
             "Failed to find path ($path) in response ($restResponse)"
         }
-        if (resourceAssignment.dictionarySource in DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-            logger.info("populating value for output mapping ($outputKeyMapping), from json (*************)")
-        }
-        else {
-            logger.info("populating value for output mapping ($outputKeyMapping), from json ($responseNode)")
-        }
+
+        val valueToPrint = ResourceAssignmentUtils.getValueToLog(metadata, responseNode)
+        logger.info("populating value for output mapping ($outputKeyMapping), from json ($valueToPrint)")
+
         val parsedResponseNode = ResourceAssignmentUtils.parseResponseNode(responseNode, resourceAssignment,
                 raRuntimeService, outputKeyMapping)
 
index 819246b..7854aa4 100644 (file)
@@ -71,15 +71,11 @@ class ResourceAssignmentUtils {
 
             try {
                 if (resourceProp.type.isNotEmpty()) {
-                    if (resourceAssignment.dictionarySource in ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-                        logger.info("Setting Resource Value (*********) for Resource Name " +
-                                "(${resourceAssignment.name}) of type (${resourceProp.type})")
-                    }
-                    else {
-                        logger.info("Setting Resource Value ($value) for Resource Name " +
-                                "(${resourceAssignment.name}), definition(${resourceAssignment.dictionaryName}) " +
-                                "of type (${resourceProp.type})")
-                    }
+                    val metadata = resourceAssignment.property!!.metadata
+                    val valueToPrint = getValueToLog(metadata, value)
+                    logger.info("Setting Resource Value ($valueToPrint) for Resource Name " +
+                            "(${resourceAssignment.name}), definition(${resourceAssignment.dictionaryName}) " +
+                            "of type (${resourceProp.type})")
                     setResourceValue(resourceAssignment, raRuntimeService, value)
                     resourceAssignment.updatedDate = Date()
                     resourceAssignment.updatedBy = BluePrintConstants.USER_SYSTEM
@@ -109,6 +105,22 @@ class ResourceAssignmentUtils {
             }
         }
 
+        @Throws(BluePrintProcessorException::class)
+        fun setInputValueIfProvided(resourceAssignment: ResourceAssignment,
+                                     raRuntimeService: ResourceAssignmentRuntimeService, value: JsonNode) {
+            logger.info("${resourceAssignment.dictionarySource} source template key (${resourceAssignment.name}) " +
+                    "found from input and value is ($value)")
+            try {
+                ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value)
+            }
+            catch (e: Exception) {
+                throw BluePrintProcessorException("Failed to set input value in resource name " +
+                        "(${resourceAssignment.name}) and dictionary key (${resourceAssignment.dictionaryName}) of " +
+                        "type (${resourceAssignment.property!!.type}) with error message (${e.message})", e)
+            }
+
+        }
+
         @Throws(BluePrintProcessorException::class)
         fun assertTemplateKeyValueNotNull(resourceAssignment: ResourceAssignment) {
             val resourceProp = checkNotNull(resourceAssignment.property) {
@@ -128,27 +140,24 @@ class ResourceAssignmentUtils {
                 val mapper = ObjectMapper()
                 val root: ObjectNode = mapper.createObjectNode()
 
-                var containsSecret = false
+                var containsLogProtected = false
                 assignments.forEach {
                     if (isNotEmpty(it.name) && it.property != null) {
                         val rName = it.name
+                        val metadata = it.property!!.metadata
                         val type = nullToEmpty(it.property?.type).toLowerCase()
                         val value = useDefaultValueIfNull(it, rName)
-                        if (it.dictionarySource in ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-                            logger.info("Generating Resource name ($rName), type ($type), value (************)")
-                            containsSecret = true
-                        }
-                        else {
-                            logger.info("Generating Resource name ($rName), type ($type), value ($value)")
+                        val valueToPrint = getValueToLog(metadata, value)
+                        if (checkIfLogIsProtected(metadata)) {
+                            containsLogProtected = true
                         }
+                        logger.trace("Generating Resource name ($rName), type ($type), value ($valueToPrint)")
                         root.set(rName, value)
                     }
                 }
                 result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root)
-                if (containsSecret) {
-                    logger.info("Generated Resource Param Data (***********)")
-                }
-                else{
+
+                if (!containsLogProtected) {
                     logger.info("Generated Resource Param Data ($result)")
                 }
             } catch (e: Exception) {
@@ -164,14 +173,12 @@ class ResourceAssignmentUtils {
             assignments.forEach {
                 if (isNotEmpty(it.name) && it.property != null) {
                     val rName = it.name
+                    val metadata = it.property!!.metadata
                     val type = nullToEmpty(it.property?.type).toLowerCase()
                     val value = useDefaultValueIfNull(it, rName)
-                    if (it.dictionarySource in ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-                        logger.trace("Generating Resource name ($rName), type ($type), value (************)")
-                    }
-                    else {
-                        logger.trace("Generating Resource name ($rName), type ($type), value ($value)")
-                    }
+                    val valueToPrint = getValueToLog(metadata, value)
+
+                    logger.trace("Generating Resource name ($rName), type ($type), value ($valueToPrint)")
                     data[rName] = value
                 }
             }
@@ -218,19 +225,17 @@ class ResourceAssignmentUtils {
         @Throws(BluePrintProcessorException::class)
         fun parseResponseNode(responseNode: JsonNode, resourceAssignment: ResourceAssignment,
                               raRuntimeService: ResourceAssignmentRuntimeService, outputKeyMapping: MutableMap<String, String>): JsonNode {
+            val metadata = resourceAssignment.property!!.metadata
             try {
                 if ((resourceAssignment.property?.type).isNullOrEmpty()) {
                     throw BluePrintProcessorException("Couldn't get data dictionary type for dictionary name (${resourceAssignment.name})")
                 }
                 val type = resourceAssignment.property!!.type
 
-                if (resourceAssignment.dictionarySource in ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-                    logger.info("For template key (${resourceAssignment.name}) setting value as (***************)")
-                }
-                else {
-                    logger.info("For template key (${resourceAssignment.name}) setting value as ($responseNode)")
-                }
-                
+                val valueToPrint = getValueToLog(metadata, responseNode)
+
+                logger.info("For template key (${resourceAssignment.name}) setting value as ($valueToPrint)")
+
                 return when (type) {
                     in BluePrintTypes.validPrimitiveTypes() -> {
                         parseResponseNodeForPrimitiveTypes(responseNode, outputKeyMapping)
@@ -255,7 +260,7 @@ class ResourceAssignmentUtils {
             var result: JsonNode? = responseNode
             if (responseNode.isComplexType()) {
                 val key = outputKeyMapping.keys.firstOrNull()
-                var returnNode: JsonNode? = responseNode
+                var returnNode: JsonNode?
                 if (responseNode is ArrayNode) {
                     val arrayNode = responseNode.toList()
                     val firstElement = if (key.isNullOrEmpty()) {
@@ -267,22 +272,30 @@ class ResourceAssignmentUtils {
                         }
                     }
 
-                    if (firstElement.isNull() || (firstElement!!.isComplexType() && !firstElement!!.has(outputKeyMapping[key]))
-                            || (!result!!.isComplexType() && result is NullNode)) {
-                        if (key.isNullOrEmpty()) {
-                            throw BluePrintProcessorException("Fail to find mapping in the responseNode.")
-                        }
-                        else {
-                            throw BluePrintProcessorException("Fail to find response with output key mapping ($key) in result.")
-                        }
-                    }
                     returnNode = firstElement
                 }
-                result = if (returnNode!!.isComplexType()) {
+                else{
+                    returnNode = responseNode
+                }
+
+                if (returnNode.isNull() || (returnNode!!.isComplexType() && !returnNode.has(outputKeyMapping[key]))) {
+                    if (key.isNullOrEmpty()) {
+                        throw BluePrintProcessorException("Fail to find mapping in the responseNode.")
+                    }
+                    else {
+                        throw BluePrintProcessorException("Fail to find response with output key mapping ($key) in result.")
+                    }
+                }
+                result = if (returnNode.isComplexType()) {
                     returnNode[outputKeyMapping[key]]
                 }
                 else {
-                    returnNode
+                    responseNode
+                }
+            }
+            else {
+                if (outputKeyMapping.isNotEmpty()) {
+                    throw BluePrintProcessorException("Fail to find key-value in response node to map output-key-mapping.")
                 }
             }
             return result!!
@@ -292,7 +305,8 @@ class ResourceAssignmentUtils {
                                                    raRuntimeService: ResourceAssignmentRuntimeService,
                                                    outputKeyMapping: MutableMap<String, String>): JsonNode {
             val dName = resourceAssignment.dictionaryName
-            val dSource = resourceAssignment.dictionarySource
+            val metadata = resourceAssignment.property!!.metadata
+            var resultNode: JsonNode
             if ((resourceAssignment.property?.entrySchema?.type).isNullOrEmpty()) {
                 throw BluePrintProcessorException("Couldn't get data type for dictionary type " +
                         "(${resourceAssignment.property!!.type}) and dictionary name ($dName)")
@@ -300,22 +314,20 @@ class ResourceAssignmentUtils {
             val entrySchemaType = resourceAssignment.property!!.entrySchema!!.type
 
             var arrayNode = JacksonUtils.objectMapper.createArrayNode()
-
             if (outputKeyMapping.isNotEmpty()) {
                 when (responseNode) {
                     is ArrayNode -> {
                         val responseArrayNode = responseNode.toList()
                         for (responseSingleJsonNode in responseArrayNode) {
-                            val arrayChildNode = parseArrayNodeElementWithOutputKeyMapping(raRuntimeService, responseSingleJsonNode,
-                                    outputKeyMapping, entrySchemaType, dSource!!)
+                            val arrayChildNode = parseSingleElementOfArrayResponseNode(entrySchemaType,
+                                    outputKeyMapping, raRuntimeService, responseSingleJsonNode, metadata)
                             arrayNode.add(arrayChildNode)
                         }
+                        resultNode = arrayNode
                     }
                     is ObjectNode -> {
                         val responseArrayNode = responseNode.rootFieldsToMap()
-                        val arrayNodeResult = parseObjectNodeWithOutputKeyMapping(responseArrayNode,
-                                outputKeyMapping, entrySchemaType, dSource!!)
-                        arrayNode.addAll(arrayNodeResult)
+                        resultNode = parseObjectResponseNode(entrySchemaType, outputKeyMapping, responseArrayNode, metadata)
                     }
                     else -> {
                         throw BluePrintProcessorException("Key-value response expected to match the responseNode.")
@@ -328,121 +340,196 @@ class ResourceAssignmentUtils {
                         responseNode.forEach { elementNode ->
                             arrayNode.add(elementNode)
                         }
+                        resultNode = arrayNode
                     }
                     is ObjectNode -> {
                         val responseArrayNode = responseNode.rootFieldsToMap()
                         for ((key, responseSingleJsonNode) in responseArrayNode) {
                             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
+                            logKeyValueResolvedResource(metadata, key, responseSingleJsonNode, entrySchemaType)
                             JacksonUtils.populateJsonNodeValues(key, responseSingleJsonNode, entrySchemaType, arrayChildNode)
                             arrayNode.add(arrayChildNode)
                         }
+                        resultNode = arrayNode
                     }
                     else -> {
-                        arrayNode.add(responseNode)
+                        resultNode = responseNode
                     }
                 }
             }
-            return arrayNode
-        }
 
-        private fun parseResponseNodeForComplexType(responseNode: JsonNode, resourceAssignment: ResourceAssignment,
-                                                    raRuntimeService: ResourceAssignmentRuntimeService,
-                                                    outputKeyMapping: MutableMap<String, String>): JsonNode {
-            val entrySchemaType = resourceAssignment.property!!.type
-            val dictionarySource = resourceAssignment.dictionarySource!!
-            val dictionaryName = resourceAssignment.dictionaryName!!
+            return resultNode
+        }
 
-            var result: ObjectNode
-            if (checkOutputKeyMappingInDataTypeProperties(entrySchemaType, outputKeyMapping, raRuntimeService))
-            {
-                result = parseArrayNodeElementWithOutputKeyMapping(raRuntimeService, responseNode, outputKeyMapping, entrySchemaType, dictionarySource!!)
-            }
-            else {
-                val childNode = JacksonUtils.objectMapper.createObjectNode()
-                if (outputKeyMapping.isNotEmpty()) {
-                    outputKeyMapping.map {
-                        val responseKeyValue = if (responseNode.has(it.key)) {
-                            responseNode.get(it.key)
+        private fun parseSingleElementOfArrayResponseNode(entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
+                                                          raRuntimeService: ResourceAssignmentRuntimeService,
+                                                          responseNode: JsonNode, metadata: MutableMap<String, String>?): ObjectNode {
+            val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
+            when (entrySchemaType) {
+                in BluePrintTypes.validPrimitiveTypes() -> {
+                    if (outputKeyMappingHasOnlyOneElement) {
+                        val outputKeyMap = outputKeyMapping.entries.first()
+                        return parseSingleElementNodeWithOneOutputKeyMapping(responseNode, outputKeyMap.key, outputKeyMap.value, entrySchemaType, metadata)
+                    }
+                    else {
+                        throw BluePrintProcessorException("Expect one entry in output-key-mapping")
+                    }
+                }
+                else -> {
+                    return when {
+                        checkOutputKeyMappingAllElementsInDataTypeProperties(entrySchemaType, outputKeyMapping, raRuntimeService) -> {
+                            parseSingleElementNodeWithAllOutputKeyMapping(responseNode, outputKeyMapping, entrySchemaType, metadata)
                         }
-                        else {
-                            NullNode.getInstance()
+                        outputKeyMappingHasOnlyOneElement -> {
+                            val outputKeyMap = outputKeyMapping.entries.first()
+                            parseSingleElementNodeWithOneOutputKeyMapping(responseNode, outputKeyMap.key, outputKeyMap.value, entrySchemaType, metadata)
+                        }
+                        else -> {
+                            throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
                         }
-
-                        logKeyValueResolvedResource(it.key, responseKeyValue, entrySchemaType, dictionarySource)
-
-                        JacksonUtils.populateJsonNodeValues(it.value,
-                                responseKeyValue, entrySchemaType, childNode)
                     }
                 }
-                else {
-                    JacksonUtils.populateJsonNodeValues(dictionaryName, responseNode, entrySchemaType, childNode)
-                }
-                result = childNode
             }
-            return result
         }
 
-        private fun parseArrayNodeElementWithOutputKeyMapping(raRuntimeService: ResourceAssignmentRuntimeService,
-                                                              responseSingleJsonNode: JsonNode, outputKeyMapping:
-                                                              MutableMap<String, String>, entrySchemaType: String,
-                                                              dictionarySource: String): ObjectNode {
+        private fun parseObjectResponseNode(entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
+                                            responseArrayNode: MutableMap<String, JsonNode>, metadata: MutableMap<String, String>?): ObjectNode {
+            val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
+            if (outputKeyMappingHasOnlyOneElement) {
+                val outputKeyMap = outputKeyMapping.entries.first()
+                return parseObjectResponseNodeWithOneOutputKeyMapping(responseArrayNode, outputKeyMap.key, outputKeyMap.value,
+                        entrySchemaType, metadata)
+            }
+            else {
+                throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
+            }
+        }
+
+        private fun parseSingleElementNodeWithOneOutputKeyMapping(responseSingleJsonNode: JsonNode, outputKeyMappingKey:
+        String, outputKeyMappingValue: String, type: String, metadata: MutableMap<String, String>?): ObjectNode {
             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
 
+            val responseKeyValue = if (responseSingleJsonNode.has(outputKeyMappingValue)) {
+                responseSingleJsonNode.get(outputKeyMappingValue)
+            }
+            else {
+                NullNode.getInstance()
+            }
+
+            logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseKeyValue, type)
+            JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseKeyValue, type, arrayChildNode)
+
+            return arrayChildNode
+        }
+
+        private fun parseSingleElementNodeWithAllOutputKeyMapping(responseSingleJsonNode: JsonNode,
+                                                                  outputKeyMapping: MutableMap<String, String>,
+                                                                  type: String, metadata: MutableMap<String, String>?): ObjectNode {
+            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
             outputKeyMapping.map {
-                val responseKeyValue = if (responseSingleJsonNode.has(it.key)) {
-                    responseSingleJsonNode.get(it.key)
-                }
-                else {
+                val responseKeyValue = if (responseSingleJsonNode.has(it.value)) {
+                    responseSingleJsonNode.get(it.value)
+                } else {
                     NullNode.getInstance()
                 }
-                val propertyTypeForDataType = ResourceAssignmentUtils
-                        .getPropertyType(raRuntimeService, entrySchemaType, it.key)
-
-                logKeyValueResolvedResource(it.key, responseKeyValue, propertyTypeForDataType, dictionarySource)
 
-                JacksonUtils.populateJsonNodeValues(it.value,
-                        responseKeyValue, propertyTypeForDataType, arrayChildNode)
+                logKeyValueResolvedResource(metadata, it.key, responseKeyValue, type)
+                JacksonUtils.populateJsonNodeValues(it.key, responseKeyValue, type, arrayChildNode)
             }
             return arrayChildNode
         }
 
-        private fun parseObjectNodeWithOutputKeyMapping(responseArrayNode: MutableMap<String, JsonNode>,
-                                                        outputKeyMapping: MutableMap<String, String>,
-                                                        entrySchemaType: String,
-                                                        dictionarySource: String): ArrayNode {
-            val arrayNode = JacksonUtils.objectMapper.createArrayNode()
-            outputKeyMapping.map {
-                val objectNode = JacksonUtils.objectMapper.createObjectNode()
-                val responseSingleJsonNode = responseArrayNode.filterKeys { key -> key == it.key }.entries.firstOrNull()
-
-                val responseNode = responseSingleJsonNode?.value ?: NullNode.getInstance()
+        private fun parseObjectResponseNodeWithOneOutputKeyMapping(responseArrayNode: MutableMap<String, JsonNode>,
+                                                                   outputKeyMappingKey: String, outputKeyMappingValue: String,
+                                                                   type: String, metadata: MutableMap<String, String>?): ObjectNode {
+            val objectNode = JacksonUtils.objectMapper.createObjectNode()
+            val responseSingleJsonNode = responseArrayNode.filterKeys { key ->
+                key == outputKeyMappingValue }.entries.firstOrNull()
 
-                logKeyValueResolvedResource(it.key, responseNode, entrySchemaType, dictionarySource)
+            if (responseSingleJsonNode == null) {
+                logKeyValueResolvedResource(metadata, outputKeyMappingKey, NullNode.getInstance(), type)
+                JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, NullNode.getInstance(), type, objectNode)
+            }
+            else
+            {
+                logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseSingleJsonNode.value, type)
+                JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseSingleJsonNode.value, type, objectNode)
+            }
+            return objectNode
+        }
 
-                JacksonUtils.populateJsonNodeValues(it.value, responseNode, entrySchemaType, objectNode)
+        private fun parseResponseNodeForComplexType(responseNode: JsonNode, resourceAssignment: ResourceAssignment,
+                                                    raRuntimeService: ResourceAssignmentRuntimeService,
+                                                    outputKeyMapping: MutableMap<String, String>): JsonNode {
+            val entrySchemaType = resourceAssignment.property!!.type
+            val dictionaryName = resourceAssignment.dictionaryName!!
+            val metadata = resourceAssignment.property!!.metadata
+            val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
 
-                arrayNode.add(objectNode)
+            if (outputKeyMapping.isNotEmpty()) {
+                return when {
+                    checkOutputKeyMappingAllElementsInDataTypeProperties(entrySchemaType, outputKeyMapping, raRuntimeService) -> {
+                        parseSingleElementNodeWithAllOutputKeyMapping(responseNode, outputKeyMapping, entrySchemaType, metadata)
+                    }
+                    outputKeyMappingHasOnlyOneElement -> {
+                        val outputKeyMap = outputKeyMapping.entries.first()
+                        parseSingleElementNodeWithOneOutputKeyMapping(responseNode, outputKeyMap.key, outputKeyMap.value,
+                                entrySchemaType, metadata)
+                    }
+                    else -> {
+                        throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
+                    }
+                }
+            }
+            else {
+                val childNode = JacksonUtils.objectMapper.createObjectNode()
+                JacksonUtils.populateJsonNodeValues(dictionaryName, responseNode, entrySchemaType, childNode)
+                return childNode
             }
-
-            return arrayNode
         }
 
-        private fun checkOutputKeyMappingInDataTypeProperties(dataTypeName: String, outputKeyMapping: MutableMap<String, String>,
-                                                              raRuntimeService: ResourceAssignmentRuntimeService): Boolean {
+        private fun checkOutputKeyMappingAllElementsInDataTypeProperties(dataTypeName: String, outputKeyMapping: MutableMap<String, String>,
+                                                                         raRuntimeService: ResourceAssignmentRuntimeService): Boolean {
             val dataTypeProps = raRuntimeService.bluePrintContext().dataTypeByName(dataTypeName)?.properties
             val result = outputKeyMapping.filterKeys { !dataTypeProps!!.containsKey(it) }.keys.firstOrNull()
             return result == null
         }
 
-        private fun logKeyValueResolvedResource(key: String, value: JsonNode, type: String, dictionarySource: String) {
-            if (dictionarySource in ResourceResolutionConstants.DATA_DICTIONARY_SECRET_SOURCE_TYPES) {
-                logger.info("For List Type Resource: key ($key), value (****************), " +
-                        "type  ({$type})")
+        private fun logKeyValueResolvedResource(metadata: MutableMap<String, String>?, key: String, value: JsonNode, type: String) {
+            val valueToPrint = getValueToLog(metadata, value)
+
+            logger.info("For List Type Resource: key ($key), value ($valueToPrint), " +
+                    "type  ({$type})")
+        }
+
+        private fun checkIfOutputKeyMappingProvideOneElement(outputKeyMapping: MutableMap<String, String>): Boolean {
+            return (outputKeyMapping.size == 1)
+        }
+
+        fun getValueToLog(metadata: MutableMap<String, String>?, value: Any): Any {
+            return if (checkIfLogIsProtected(metadata)) {
+                "*************"
             }
-            else {
-                logger.info("For List Type Resource: key ($key), value ($value), " +
-                        "type  ({$type})")
+            else{
+                value
+            }
+        }
+
+        fun checkIfInputWasProvided(resourceAssignment: ResourceAssignment, value: JsonNode) : Boolean{
+            val defaultValueNode = resourceAssignment.property!!.defaultValue.asJsonType()
+            return (value.returnNullIfMissing() != null && value != defaultValueNode)
+        }
+
+        private fun checkIfLogIsProtected(metadata: MutableMap<String, String>?) : Boolean {
+            var checkProtected = false
+            if (metadata != null &&
+                    metadata.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA)) {
+                val protectedMetadata = metadata[ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA]
+                if (protectedMetadata == "yes" || protectedMetadata == "y") {
+                    checkProtected = true
+                }
             }
+            return checkProtected
         }
     }
 }
\ No newline at end of file
index 9365c3e..728e116 100644 (file)
@@ -22,7 +22,6 @@
 package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils
 
 import com.fasterxml.jackson.databind.JsonNode
-import com.fasterxml.jackson.databind.node.NullNode
 import com.fasterxml.jackson.databind.node.TextNode
 import io.mockk.every
 import io.mockk.spyk
@@ -42,11 +41,25 @@ import kotlin.test.assertEquals
 data class IpAddress(val port: String, val ip: String)
 data class Host(val name: String, val ipAddress: IpAddress)
 data class ExpectedResponseIp(val ip: String)
-data class ExpectedResponsePort(val port: String)
+data class ExpectedResponseIpAddress(val ipAddress: IpAddress)
 
 class ResourceAssignmentUtilsTest {
     private lateinit var resourceAssignmentRuntimeService: ResourceAssignmentRuntimeService
 
+    private lateinit var inputMapToTestPrimitiveTypeWithValue: JsonNode
+    private lateinit var inputMapToTestPrimitiveTypeWithKeyValue: JsonNode
+    private lateinit var inputMapToTestCollectionOfPrimitiveType: JsonNode
+    private lateinit var inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode
+    private lateinit var inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode
+    private lateinit var inputMapToTestComplexTypeWithOneOutputKeyMapping: JsonNode
+    private lateinit var inputMapToTestComplexTypeWithAllOutputKeyMapping: JsonNode
+    private lateinit var expectedValueToTestPrimitiveType: JsonNode
+    private lateinit var expectedValueToTesCollectionOfPrimitiveType: JsonNode
+    private lateinit var expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping: JsonNode
+    private lateinit var expectedValueToTestComplexTypeWithOneOutputKeyMapping: JsonNode
+    private lateinit var expectedValueToTestComplexTypeWithAllOutputKeyMapping: JsonNode
+    private lateinit var expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping: JsonNode
+
     @Before
     fun setup() {
 
@@ -55,6 +68,11 @@ class ResourceAssignmentUtilsTest {
 
         resourceAssignmentRuntimeService = spyk(ResourceAssignmentRuntimeService("1234", bluePrintContext))
 
+        //Init input map and expected values for tests
+        initInputMapAndExpectedValuesForPrimitiveType()
+        initInputMapAndExpectedValuesForCollection()
+        initInputMapAndExpectedValuesForComplexType()
+
         val propertiesDefinition1 = PropertyDefinition().apply {
             type = "string"
             id = "port"
@@ -149,146 +167,127 @@ class ResourceAssignmentUtilsTest {
 
     @Test
     fun parseResponseNodeTestForPrimitivesTypes(){
-        // Input values for primitive type
-        val keyValue = mutableMapOf<String, String>()
-        keyValue["value"]= "1.2.3.1"
-        val expectedPrimitiveType = TextNode("1.2.3.1")
+        var outcome = prepareResponseNodeForTest("sample-value", "string", "",
+                inputMapToTestPrimitiveTypeWithValue)
+        assertEquals(expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of simple String")
 
-        var outcome = prepareResponseNodeForTest("sample-value", "string",
-                "", "1.2.3.1".asJsonPrimitive())
-        assertEquals(expectedPrimitiveType, outcome, "Unexpected outcome returned for primitive type of simple String")
-        outcome = prepareResponseNodeForTest("sample-key-value", "string", "", keyValue)
-        assertEquals(expectedPrimitiveType, outcome, "Unexpected outcome returned for primitive type of key-value String")
+        outcome = prepareResponseNodeForTest("sample-key-value", "string", "",
+                inputMapToTestPrimitiveTypeWithKeyValue)
+        assertEquals(expectedValueToTestPrimitiveType, outcome, "Unexpected outcome returned for primitive type of key-value String")
     }
 
     @Test
     fun parseResponseNodeTestForCollectionsOfString(){
-        // Input values for collection type
-        val mapOfString = mutableMapOf<String, String>()
-        mapOfString["value1"] = "1.2.3.1"
-        mapOfString["port"] = "8888"
-        mapOfString["value2"] = "1.2.3.2"
-        val arrayOfKeyValue = arrayListOf(ExpectedResponseIp("1.2.3.1"),
-                ExpectedResponsePort( "8888"), ExpectedResponseIp("1.2.3.2"))
-
-        val mutableMapKeyValue = mutableMapOf<String, String>()
-        mutableMapKeyValue["value1"] = "1.2.3.1"
-        mutableMapKeyValue["port"] = "8888"
-
-        //List
-        val expectedListOfString = arrayOfKeyValue.asJsonType()
         var outcome = prepareResponseNodeForTest("listOfString", "list",
-                "string", mapOfString.asJsonType())
-        assertEquals(expectedListOfString, outcome, "unexpected outcome returned for list of String")
+                "string", inputMapToTestCollectionOfPrimitiveType)
+        assertEquals(expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for list of String")
 
-        //Map
-        val expectedMapOfString = mutableMapOf<String, JsonNode>()
-        expectedMapOfString["ip"] = "1.2.3.1".asJsonPrimitive()
-        expectedMapOfString["port"] = "8888".asJsonPrimitive()
-
-        val arrayNode = JacksonUtils.objectMapper.createArrayNode()
-        expectedMapOfString.map {
-            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
-            arrayChildNode.set(it.key, it.value)
-            arrayNode.add(arrayChildNode)
-        }
-        val arrayChildNode1 = JacksonUtils.objectMapper.createObjectNode()
-        arrayChildNode1.set("ip", NullNode.getInstance())
-        arrayNode.add(arrayChildNode1)
         outcome = prepareResponseNodeForTest("mapOfString", "map", "string",
-                mutableMapKeyValue.asJsonType())
-        assertEquals(arrayNode, outcome, "unexpected outcome returned for map of String")
-    }
-
-    @Test
-    fun parseResponseNodeTestForCollectionsOfJsonNode(){
-        // Input values for collection type
-        val mapOfString = mutableMapOf<String, JsonNode>()
-        mapOfString["value1"] = "1.2.3.1".asJsonPrimitive()
-        mapOfString["port"] = "8888".asJsonPrimitive()
-        mapOfString["value2"] = "1.2.3.2".asJsonPrimitive()
-        val arrayOfKeyValue = arrayListOf(ExpectedResponseIp("1.2.3.1"),
-                ExpectedResponsePort( "8888"), ExpectedResponseIp("1.2.3.2"))
-
-        val mutableMapKeyValue = mutableMapOf<String, JsonNode>()
-        mutableMapKeyValue["value1"] = "1.2.3.1".asJsonPrimitive()
-        mutableMapKeyValue["port"] = "8888".asJsonPrimitive()
-
-        //List
-        val expectedListOfString = arrayOfKeyValue.asJsonType()
-        var outcome = prepareResponseNodeForTest("listOfString", "list",
-                "string", mapOfString.asJsonType())
-        assertEquals(expectedListOfString, outcome, "unexpected outcome returned for list of String")
-
-        //Map
-        val expectedMapOfString = mutableMapOf<String, JsonNode>()
-        expectedMapOfString["ip"] = "1.2.3.1".asJsonPrimitive()
-        expectedMapOfString["port"] = "8888".asJsonPrimitive()
-        val arrayNode = JacksonUtils.objectMapper.createArrayNode()
-        expectedMapOfString.map {
-            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
-            arrayChildNode.set(it.key, it.value)
-            arrayNode.add(arrayChildNode)
-        }
-        val arrayChildNode1 = JacksonUtils.objectMapper.createObjectNode()
-        arrayChildNode1.set("ip", NullNode.getInstance())
-        arrayNode.add(arrayChildNode1)
-        outcome = prepareResponseNodeForTest("mapOfString", "map",
-                "string", mutableMapKeyValue.asJsonType())
-        assertEquals(arrayNode, outcome, "unexpected outcome returned for map of String")
+                inputMapToTestCollectionOfPrimitiveType)
+        assertEquals(expectedValueToTesCollectionOfPrimitiveType, outcome, "unexpected outcome returned for map of String")
     }
 
     @Test
     fun parseResponseNodeTestForCollectionsOfComplexType(){
-        // Input values for collection type
-        val mapOfComplexType = mutableMapOf<String, JsonNode>()
-        mapOfComplexType["value1"] = IpAddress("1111", "1.2.3.1").asJsonType()
-        mapOfComplexType["value2"] = IpAddress("2222", "1.2.3.2").asJsonType()
-        mapOfComplexType["value3"] = IpAddress("3333", "1.2.3.3").asJsonType()
+        var outcome = prepareResponseNodeForTest("listOfMyDataTypeWithOneOutputKeyMapping", "list",
+                "ip-address", inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping)
+        assertEquals(expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping, outcome, "unexpected outcome returned for list of String")
 
-        //List
-        val arrayNode = JacksonUtils.objectMapper.createArrayNode()
-        mapOfComplexType.map {
-            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
-            arrayChildNode.set("ipAddress", it.value)
-            arrayNode.add(arrayChildNode)
-        }
-        var outcome = prepareResponseNodeForTest("listOfMyDataType", "list",
-                "ip-address", mapOfComplexType.asJsonType())
-        assertEquals(arrayNode, outcome, "unexpected outcome returned for list of String")
+        outcome = prepareResponseNodeForTest("listOfMyDataTypeWithAllOutputKeyMapping", "list",
+                "ip-address", inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping)
+        assertEquals(expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping, outcome, "unexpected outcome returned for list of String")
     }
 
     @Test
     fun `parseResponseNodeTestForComplexType find one output key mapping`(){
-        // Input values for complex type
-        val objectNode = JacksonUtils.objectMapper.createObjectNode()
-
-        // Input values for collection type
-        val mapOfComplexType = mutableMapOf<String, JsonNode>()
-        mapOfComplexType["value"] = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
-        mapOfComplexType["port"] = "8888".asJsonType()
-        mapOfComplexType["something"] = "1.2.3.2".asJsonType()
-
-        val expectedComplexType = objectNode.set("ipAddress", Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType())
         val outcome = prepareResponseNodeForTest("complexTypeOneKeys", "host",
-                "", mapOfComplexType.asJsonType())
-        assertEquals(expectedComplexType, outcome, "Unexpected outcome returned for complex type")
+                "", inputMapToTestComplexTypeWithOneOutputKeyMapping)
+        assertEquals(expectedValueToTestComplexTypeWithOneOutputKeyMapping, outcome, "Unexpected outcome returned for complex type")
     }
 
     @Test
     fun `parseResponseNodeTestForComplexType find all output key mapping`(){
-        // Input values for complex type
-        val objectNode = JacksonUtils.objectMapper.createObjectNode()
+        val outcome = prepareResponseNodeForTest("complexTypeAllKeys", "host",
+                "", inputMapToTestComplexTypeWithAllOutputKeyMapping)
+        assertEquals(expectedValueToTestComplexTypeWithAllOutputKeyMapping, outcome, "Unexpected outcome returned for complex type")
+    }
+
+    private fun initInputMapAndExpectedValuesForPrimitiveType() {
+        inputMapToTestPrimitiveTypeWithValue = "1.2.3.1".asJsonType()
+        val keyValue = mutableMapOf<String, String>()
+        keyValue["value"]= "1.2.3.1"
+        inputMapToTestPrimitiveTypeWithKeyValue = keyValue.asJsonType()
+        expectedValueToTestPrimitiveType = TextNode("1.2.3.1")
+    }
+
+    private fun initInputMapAndExpectedValuesForCollection(){
+        val listOfIps = arrayListOf("1.2.3.1", "1.2.3.2", "1.2.3.3")
+        val arrayNodeForList1 = JacksonUtils.objectMapper.createArrayNode()
+        listOfIps.forEach {
+            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
+            arrayChildNode.set("value", it.asJsonPrimitive())
+            arrayNodeForList1.add(arrayChildNode)
+        }
+        inputMapToTestCollectionOfPrimitiveType = arrayNodeForList1
+
+        expectedValueToTesCollectionOfPrimitiveType = arrayListOf(ExpectedResponseIp("1.2.3.1"),
+                ExpectedResponseIp( "1.2.3.2"), ExpectedResponseIp("1.2.3.3")).asJsonType()
+
 
-        // Input values for collection type
+        val listOfIpAddresses = arrayListOf(IpAddress("1111", "1.2.3.1").asJsonType(),
+                IpAddress("2222", "1.2.3.2").asJsonType(), IpAddress("3333", "1.2.3.3").asJsonType())
+        val arrayNodeForList2 = JacksonUtils.objectMapper.createArrayNode()
+        listOfIpAddresses.forEach {
+            val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
+            arrayChildNode.set("value", it.asJsonType())
+            arrayNodeForList2.add(arrayChildNode)
+        }
+        inputMapToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayNodeForList2
+
+        val arrayNodeForList3 = JacksonUtils.objectMapper.createArrayNode()
+        var childNode = JacksonUtils.objectMapper.createObjectNode()
+        childNode.set("port", "1111".asJsonPrimitive())
+        childNode.set("ip", "1.2.3.1".asJsonPrimitive())
+        arrayNodeForList3.add(childNode)
+        childNode = JacksonUtils.objectMapper.createObjectNode()
+        childNode.set("port", "2222".asJsonPrimitive())
+        childNode.set("ip", "1.2.3.2".asJsonPrimitive())
+        arrayNodeForList3.add(childNode)
+        childNode = JacksonUtils.objectMapper.createObjectNode()
+        childNode.set("port", "3333".asJsonPrimitive())
+        childNode.set("ip", "1.2.3.3".asJsonPrimitive())
+        arrayNodeForList3.add(childNode)
+        inputMapToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayNodeForList3
+
+        expectedValueToTestCollectionOfComplexTypeWithOneOutputKeyMapping = arrayListOf(ExpectedResponseIpAddress(IpAddress("1111", "1.2.3.1")),
+                ExpectedResponseIpAddress(IpAddress("2222", "1.2.3.2")), ExpectedResponseIpAddress(
+                IpAddress("3333", "1.2.3.3"))).asJsonType()
+        expectedValueToTestCollectionOfComplexTypeWithAllOutputKeyMapping = arrayListOf(IpAddress("1111", "1.2.3.1"),
+                IpAddress("2222", "1.2.3.2"),
+                IpAddress("3333", "1.2.3.3")).asJsonType()
+    }
+
+    private fun initInputMapAndExpectedValuesForComplexType(){
         val mapOfComplexType = mutableMapOf<String, JsonNode>()
-        mapOfComplexType["name"] = "my-ipAddress".asJsonType()
-        mapOfComplexType["ipAddress"] = IpAddress("1111", "1.2.3.1").asJsonType()
+        mapOfComplexType["value"] = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
+        mapOfComplexType["port"] = "8888".asJsonType()
+        mapOfComplexType["something"] = "1.2.3.2".asJsonType()
+        inputMapToTestComplexTypeWithOneOutputKeyMapping = mapOfComplexType.asJsonType()
 
-        val expectedComplexType = Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType()
-        val outcome = prepareResponseNodeForTest("complexTypeAllKeys", "host",
-                "", mapOfComplexType.asJsonType())
-        assertEquals(expectedComplexType, outcome, "Unexpected outcome returned for complex type")
+        val objectNode = JacksonUtils.objectMapper.createObjectNode()
+        expectedValueToTestComplexTypeWithOneOutputKeyMapping = objectNode.set("host", Host("my-ipAddress", IpAddress("1111", "1.2.3.1")).asJsonType())
+
+        val childNode1 = JacksonUtils.objectMapper.createObjectNode()
+        childNode1.set("name", "my-ipAddress".asJsonPrimitive())
+        childNode1.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType())
+        childNode1.set("port", "8888".asJsonType())
+        childNode1.set("something", IpAddress("2222", "1.2.3.1").asJsonType())
+        inputMapToTestComplexTypeWithAllOutputKeyMapping = childNode1
+
+        val childNode2 = JacksonUtils.objectMapper.createObjectNode()
+        childNode2.set("name", "my-ipAddress".asJsonPrimitive())
+        childNode2.set("ipAddress", IpAddress("1111", "1.2.3.1").asJsonType())
+        expectedValueToTestComplexTypeWithAllOutputKeyMapping = childNode2
     }
 
     private fun prepareResponseNodeForTest(dictionary_source: String, sourceType: String, entrySchema: String,
@@ -355,27 +354,28 @@ class ResourceAssignmentUtilsTest {
         val outputMapping = mutableMapOf<String, String>()
 
         when (dictionary_source) {
-            "listOfString", "mapOfString" -> {
-                //List of string
-                outputMapping["value1"] = "ip"
-                outputMapping["port"] = "port"
-                outputMapping["value2"] = "ip"
-            }
-            "listOfMyDataType", "mapOfMyDataType" -> {
-                //List or map of complex Type
-                outputMapping["value1"] = "ipAddress"
-                outputMapping["value2"] = "ipAddress"
-                outputMapping["value3"] = "ipAddress"
-            }
             "sample-key-value", "sample-value" -> {
                 //Primary Type
                 if (dictionary_source=="sample-key-value")
                     outputMapping["sample-ip"] = "value"
             }
+            "listOfString", "mapOfString" -> {
+                //List of string
+                outputMapping["ip"] = "value"
+            }
+            "listOfMyDataTypeWithOneOutputKeyMapping", "listOfMyDataTypeWithAllOutputKeyMapping" -> {
+                //List or map of complex Type
+                if (dictionary_source == "listOfMyDataTypeWithOneOutputKeyMapping")
+                    outputMapping["ipAddress"] = "value"
+                else {
+                    outputMapping["port"] = "port"
+                    outputMapping["ip"] = "ip"
+                }
+            }
             else -> {
                 //Complex Type
                 if (dictionary_source == "complexTypeOneKeys")
-                    outputMapping["value"] = "ipAddress"
+                    outputMapping["host"] = "value"
                 else {
                     outputMapping["name"] = "name"
                     outputMapping["ipAddress"] = "ipAddress"