X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=ms%2Fblueprintsprocessor%2Ffunctions%2Fresource-resolution%2Fsrc%2Fmain%2Fkotlin%2Forg%2Fonap%2Fccsdk%2Fcds%2Fblueprintsprocessor%2Ffunctions%2Fresource%2Fresolution%2Futils%2FResourceAssignmentUtils.kt;h=54231da613de4e9d99fa54b29b51a183caf9a8cb;hb=1072867dfac0df993cbd3e44bcc11a5cac7465fd;hp=b818cc2b100a8bdfcf455d8210341d2e7534b59a;hpb=341db21b2ac0a14a1ed2b8bf7930914dda054bfe;p=ccsdk%2Fcds.git diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtils.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtils.kt index b818cc2b1..54231da61 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtils.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/utils/ResourceAssignmentUtils.kt @@ -19,6 +19,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.uti import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.databind.node.NullNode import com.fasterxml.jackson.databind.node.ObjectNode @@ -31,6 +32,7 @@ import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes import org.onap.ccsdk.cds.controllerblueprints.core.asJsonType import org.onap.ccsdk.cds.controllerblueprints.core.checkFileExists import org.onap.ccsdk.cds.controllerblueprints.core.checkNotEmpty +import org.onap.ccsdk.cds.controllerblueprints.core.common.ApplicationConstants.LOG_REDACTED import org.onap.ccsdk.cds.controllerblueprints.core.isComplexType import org.onap.ccsdk.cds.controllerblueprints.core.isNotEmpty import org.onap.ccsdk.cds.controllerblueprints.core.isNullOrMissing @@ -38,8 +40,13 @@ import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile import org.onap.ccsdk.cds.controllerblueprints.core.nullToEmpty import org.onap.ccsdk.cds.controllerblueprints.core.rootFieldsToMap import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintVelocityTemplateService 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.DictionaryMetadataEntry +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 @@ -86,7 +93,7 @@ class ResourceAssignmentUtils { resourceAssignment.dictionaryName = resourceAssignment.name logger.warn( "Missing dictionary key, setting with template key (${resourceAssignment.name}) " + - "as dictionary key (${resourceAssignment.dictionaryName})" + "as dictionary key (${resourceAssignment.dictionaryName})" ) } @@ -96,8 +103,8 @@ class ResourceAssignmentUtils { val valueToPrint = getValueToLog(metadata, value) logger.info( "Setting Resource Value ($valueToPrint) for Resource Name " + - "(${resourceAssignment.name}), definition(${resourceAssignment.dictionaryName}) " + - "of type (${resourceProp.type})" + "(${resourceAssignment.name}), definition(${resourceAssignment.dictionaryName}) " + + "of type (${resourceProp.type})" ) setResourceValue(resourceAssignment, raRuntimeService, value) resourceAssignment.updatedDate = Date() @@ -107,8 +114,9 @@ class ResourceAssignmentUtils { } catch (e: Exception) { throw BluePrintProcessorException( "Failed in setting value for template key " + - "(${resourceAssignment.name}) and dictionary key (${resourceAssignment.dictionaryName}) of " + - "type (${resourceProp.type}) with error message (${e.message})", e + "(${resourceAssignment.name}) and dictionary key (${resourceAssignment.dictionaryName}) of " + + "type (${resourceProp.type}) with error message (${e.message})", + e ) } } @@ -122,6 +130,35 @@ class ResourceAssignmentUtils { raRuntimeService.putResolutionStore(resourceAssignment.name, value) raRuntimeService.putDictionaryStore(resourceAssignment.dictionaryName!!, value) resourceAssignment.property!!.value = value + + val metadata = resourceAssignment.property?.metadata + metadata?.get(ResourceResolutionConstants.METADATA_TRANSFORM_TEMPLATE) + ?.let { if (it.contains("$")) it else null } + ?.let { template -> + val resolutionStore = raRuntimeService.getResolutionStore() + .mapValues { e -> e.value.asText() } as MutableMap + val newValue: JsonNode + try { + newValue = BluePrintVelocityTemplateService + .generateContent(template, null, true, resolutionStore) + .also { + if (hasLogProtect(metadata)) + logger.info("Transformed value: $resourceAssignment.name") + else + logger.info("Transformed value: $value -> $it") + } + .let { v -> v.asJsonType() } + } catch (e: Exception) { + throw BluePrintProcessorException( + "transform-template failed: $template", e + ) + } + with(resourceAssignment) { + raRuntimeService.putResolutionStore(this.name, newValue) + raRuntimeService.putDictionaryStore(this.dictionaryName!!, newValue) + this.property!!.value = newValue + } + } } fun setFailedResourceDataValue(resourceAssignment: ResourceAssignment, message: String?) { @@ -149,6 +186,7 @@ class ResourceAssignmentUtils { val result: String try { val mapper = ObjectMapper() + mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true) val root: ObjectNode = mapper.createObjectNode() var containsLogProtected = false @@ -159,14 +197,13 @@ class ResourceAssignmentUtils { val type = nullToEmpty(it.property?.type).toLowerCase() val value = useDefaultValueIfNull(it, rName) val valueToPrint = getValueToLog(metadata, value) - if (checkIfLogIsProtected(metadata)) { - containsLogProtected = true - } + containsLogProtected = hasLogProtect(metadata) logger.trace("Generating Resource name ($rName), type ($type), value ($valueToPrint)") - root.set(rName, value) + root.set(rName, value) } } - result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root) + result = mapper.writerWithDefaultPrettyPrinter() + .writeValueAsString(mapper.treeToValue(root, Object::class.java)) if (!containsLogProtected) { logger.info("Generated Resource Param Data ($result)") @@ -196,6 +233,51 @@ class ResourceAssignmentUtils { return data } + fun generateResolutionSummaryData( + resourceAssignments: List, + resourceDefinitions: Map + ): String { + val emptyTextNode = TextNode.valueOf("") + val resolutionSummaryList = resourceAssignments.map { + val definition = resourceDefinitions[it.name] + val description = definition?.property?.description ?: "" + val value = it.property?.value + ?.let { v -> if (v.isNullOrMissing()) emptyTextNode else v } + ?: emptyTextNode + + var payload: JsonNode = definition?.sources?.get(it.dictionarySource) + ?.properties?.get("resolved-payload") + ?.let { p -> if (p.isNullOrMissing()) emptyTextNode else p } + ?: emptyTextNode + + val metadata = definition?.property?.metadata + ?.map { e -> DictionaryMetadataEntry(e.key, e.value) } + ?.toMutableList() ?: mutableListOf() + + val keyIdentifiers: MutableList = it.keyIdentifiers.map { k -> + if (k.value.isNullOrMissing()) KeyIdentifier(k.name, emptyTextNode) else k + }.toMutableList() + + ResolutionSummary( + it.name, + value, + it.property?.required ?: false, + it.property?.type ?: "", + keyIdentifiers, + description, + metadata, + it.dictionaryName ?: "", + it.dictionarySource ?: "", + payload, + it.status ?: "", + it.message ?: "" + ) + } + // Wrapper needed for integration with SDNC + val data = mapOf("resolution-summary" to resolutionSummaryList) + return JacksonUtils.getJson(data, includeNull = true) + } + private fun useDefaultValueIfNull( resourceAssignment: ResourceAssignment, resourceAssignmentName: String @@ -263,7 +345,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 +364,7 @@ class ResourceAssignmentUtils { private fun parseResponseNodeForPrimitiveTypes( responseNode: JsonNode, + resourceAssignment: ResourceAssignment, outputKeyMapping: MutableMap ): JsonNode { // Return responseNode if is not a Complex Type @@ -306,11 +389,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( @@ -325,7 +413,7 @@ class ResourceAssignmentUtils { if ((resourceAssignment.property?.entrySchema?.type).isNullOrEmpty()) { throw BluePrintProcessorException( "Couldn't get data type for dictionary type " + - "(${resourceAssignment.property!!.type}) and dictionary name ($dName)" + "(${resourceAssignment.property!!.type}) and dictionary name ($dName)" ) } val entrySchemaType = resourceAssignment.property!!.entrySchema!!.type @@ -337,7 +425,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 +435,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 +478,7 @@ class ResourceAssignmentUtils { private fun parseSingleElementOfArrayResponseNode( entrySchemaType: String, + resourceAssignment: ResourceAssignment, outputKeyMapping: MutableMap, raRuntimeService: ResourceAssignmentRuntimeService, responseNode: JsonNode, @@ -397,7 +489,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 +514,7 @@ class ResourceAssignmentUtils { raRuntimeService ) -> { parseSingleElementNodeWithAllOutputKeyMapping( + resourceAssignment, responseNode, outputKeyMapping, entrySchemaType, @@ -425,6 +524,7 @@ class ResourceAssignmentUtils { outputKeyMappingHasOnlyOneElement -> { val outputKeyMap = outputKeyMapping.entries.first() parseSingleElementNodeWithOneOutputKeyMapping( + resourceAssignment, responseNode, outputKeyMap.key, outputKeyMap.value, @@ -441,6 +541,7 @@ class ResourceAssignmentUtils { } private fun parseObjectResponseNode( + resourceAssignment: ResourceAssignment, entrySchemaType: String, outputKeyMapping: MutableMap, responseArrayNode: MutableMap, @@ -449,19 +550,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? @@ -476,11 +579,20 @@ 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, type: String, @@ -496,6 +608,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 +654,7 @@ class ResourceAssignmentUtils { raRuntimeService ) -> { parseSingleElementNodeWithAllOutputKeyMapping( + resourceAssignment, responseNode, outputKeyMapping, entrySchemaType, @@ -550,8 +664,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 -> { @@ -585,7 +699,7 @@ class ResourceAssignmentUtils { logger.info( "For List Type Resource: key ($key), value ($valueToPrint), " + - "type ({$type})" + "type ({$type})" ) } @@ -593,25 +707,7 @@ class ResourceAssignmentUtils { return (outputKeyMapping.size == 1) } - fun getValueToLog(metadata: MutableMap?, value: Any): Any { - return if (checkIfLogIsProtected(metadata)) { - "******REDACTED******" - } else { - value - } - } - - private fun checkIfLogIsProtected(metadata: MutableMap?): 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 - } + fun getValueToLog(metadata: MutableMap?, value: Any): Any = + if (hasLogProtect(metadata)) LOG_REDACTED else value } }