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
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
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
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})"
)
}
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()
} 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
)
}
}
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<String, Any>
+ 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?) {
val result: String
try {
val mapper = ObjectMapper()
+ mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true)
val root: ObjectNode = mapper.createObjectNode()
var containsLogProtected = false
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<JsonNode>(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)")
return data
}
+ fun generateResolutionSummaryData(
+ resourceAssignments: List<ResourceAssignment>,
+ resourceDefinitions: Map<String, ResourceDefinition>
+ ): 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<KeyIdentifier> = 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
return when (type) {
in BluePrintTypes.validPrimitiveTypes() -> {
// Primitive Types
- parseResponseNodeForPrimitiveTypes(responseNode, outputKeyMapping)
+ parseResponseNodeForPrimitiveTypes(responseNode, resourceAssignment, outputKeyMapping)
}
in BluePrintTypes.validCollectionTypes() -> {
// Array Types
private fun parseResponseNodeForPrimitiveTypes(
responseNode: JsonNode,
+ resourceAssignment: ResourceAssignment,
outputKeyMapping: MutableMap<String, String>
): JsonNode {
// Return responseNode if is not a Complex Type
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(
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
val responseArrayNode = responseNode.toList()
for (responseSingleJsonNode in responseArrayNode) {
val arrayChildNode = parseSingleElementOfArrayResponseNode(
- entrySchemaType,
+ entrySchemaType, resourceAssignment,
outputKeyMapping, raRuntimeService, responseSingleJsonNode, metadata
)
arrayNode.add(arrayChildNode)
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.")
private fun parseSingleElementOfArrayResponseNode(
entrySchemaType: String,
+ resourceAssignment: ResourceAssignment,
outputKeyMapping: MutableMap<String, String>,
raRuntimeService: ResourceAssignmentRuntimeService,
responseNode: JsonNode,
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,
raRuntimeService
) -> {
parseSingleElementNodeWithAllOutputKeyMapping(
+ resourceAssignment,
responseNode,
outputKeyMapping,
entrySchemaType,
outputKeyMappingHasOnlyOneElement -> {
val outputKeyMap = outputKeyMapping.entries.first()
parseSingleElementNodeWithOneOutputKeyMapping(
+ resourceAssignment,
responseNode,
outputKeyMap.key,
outputKeyMap.value,
}
private fun parseObjectResponseNode(
+ resourceAssignment: ResourceAssignment,
entrySchemaType: String,
outputKeyMapping: MutableMap<String, String>,
responseArrayNode: MutableMap<String, JsonNode>,
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>?
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,
logKeyValueResolvedResource(metadata, it.key, responseKeyValue, type)
JacksonUtils.populateJsonNodeValues(it.key, responseKeyValue, type, arrayChildNode)
+ resourceAssignment.keyIdentifiers.add(KeyIdentifier(it.key, responseKeyValue))
}
return arrayChildNode
}
raRuntimeService
) -> {
parseSingleElementNodeWithAllOutputKeyMapping(
+ resourceAssignment,
responseNode,
outputKeyMapping,
entrySchemaType,
outputKeyMappingHasOnlyOneElement -> {
val outputKeyMap = outputKeyMapping.entries.first()
parseSingleElementNodeWithOneOutputKeyMapping(
- responseNode, outputKeyMap.key, outputKeyMap.value,
- entrySchemaType, metadata
+ resourceAssignment, responseNode, outputKeyMap.key,
+ outputKeyMap.value, entrySchemaType, metadata
)
}
else -> {
logger.info(
"For List Type Resource: key ($key), value ($valueToPrint), " +
- "type ({$type})"
+ "type ({$type})"
)
}
return (outputKeyMapping.size == 1)
}
- fun getValueToLog(metadata: MutableMap<String, String>?, value: Any): Any {
- return if (checkIfLogIsProtected(metadata)) {
- "******REDACTED******"
- } else {
- value
- }
- }
-
- 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
- }
+ fun getValueToLog(metadata: MutableMap<String, String>?, value: Any): Any =
+ if (hasLogProtect(metadata)) LOG_REDACTED else value
}
}