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%2Fprocessor%2FDatabaseResourceAssignmentProcessor.kt;h=98df3f1cfd7a453a1893c22371f502b3845751c2;hb=refs%2Fheads%2Fmaster;hp=d190ee53c6b7ce87feea5c8006ed8728407c08cb;hpb=5453c29bf6f559a9aed18ed72879ff64b34aa0fd;p=ccsdk%2Fcds.git diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt index d190ee53c..6072a9233 100644 --- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt +++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt @@ -1,6 +1,6 @@ /* * Copyright © 2018 IBM. - * Modifications Copyright © 2017-2018 AT&T Intellectual Property. + * Modifications Copyright © 2017-2018 AT&T Intellectual Property, Bell Canada. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,174 +17,180 @@ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor -import com.fasterxml.jackson.databind.node.JsonNodeFactory -import com.fasterxml.jackson.databind.node.MissingNode -import com.fasterxml.jackson.databind.node.NullNode +import com.fasterxml.jackson.databind.JsonNode import org.onap.ccsdk.cds.blueprintsprocessor.db.BluePrintDBLibGenericService -import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.BluePrintDBLibPropertySevice -import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.PrimaryDBLibGenericService +import org.onap.ccsdk.cds.blueprintsprocessor.db.PrimaryDBLibGenericService +import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.BluePrintDBLibPropertyService import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.DatabaseResourceSource import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils -import org.onap.ccsdk.cds.controllerblueprints.core.* +import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ExecutionServiceDomains +import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException +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.updateErrorMessage 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.onap.ccsdk.cds.controllerblueprints.resource.dict.factory.ResourceSourceMappingFactory import org.slf4j.LoggerFactory import org.springframework.beans.factory.config.ConfigurableBeanFactory import org.springframework.context.annotation.Scope import org.springframework.stereotype.Service -import java.util.* +import java.util.HashMap /** * DatabaseResourceAssignmentProcessor * * @author Kapil Singal */ -@Service("${PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-processor-db") +@Service("${PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-db") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) -open class DatabaseResourceAssignmentProcessor(private val bluePrintDBLibPropertySevice: BluePrintDBLibPropertySevice, private val primaryDBLibGenericService: PrimaryDBLibGenericService) - : ResourceAssignmentProcessor() { +open class DatabaseResourceAssignmentProcessor( + private val bluePrintDBLibPropertyService: BluePrintDBLibPropertyService, + private val primaryDBLibGenericService: PrimaryDBLibGenericService +) : ResourceAssignmentProcessor() { private val logger = LoggerFactory.getLogger(DatabaseResourceAssignmentProcessor::class.java) override fun getName(): String { - return "${PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-processor-db" + return "${PREFIX_RESOURCE_RESOLUTION_PROCESSOR}source-db" } - override fun process(resourceAssignment: ResourceAssignment) { + override suspend fun processNB(resourceAssignment: ResourceAssignment) { try { validate(resourceAssignment) - // Check if It has Input - try { - val value = raRuntimeService.getInputValue(resourceAssignment.name) - if (value !is NullNode && value !is MissingNode) { - logger.info("processor-db source template key (${resourceAssignment.name}) found from input and value is ($value)") - ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value) - } else { - setValueFromDB(resourceAssignment) - } - } catch (e: BluePrintProcessorException) { + if (!setFromInput(resourceAssignment)) { setValueFromDB(resourceAssignment) } - // Check the value has populated for mandatory case ResourceAssignmentUtils.assertTemplateKeyValueNotNull(resourceAssignment) + } catch (e: BluePrintProcessorException) { + val errorMsg = "Failed to process Database resource resolution in template key ($resourceAssignment) assignments." + throw e.updateErrorMessage( + ExecutionServiceDomains.RESOURCE_RESOLUTION, errorMsg, + "Wrong resource definition or DB resolution failed." + ) } catch (e: Exception) { ResourceAssignmentUtils.setFailedResourceDataValue(resourceAssignment, e.message) throw BluePrintProcessorException("Failed in template key ($resourceAssignment) assignments with: ${e.message}", e) } } - private fun setValueFromDB(resourceAssignment: ResourceAssignment) { - val dName = resourceAssignment.dictionaryName - val dSource = resourceAssignment.dictionarySource - val resourceDefinition = resourceDictionaries[dName] - ?: throw BluePrintProcessorException("couldn't get resource dictionary definition for $dName") - val resourceSource = resourceDefinition.sources[dSource] - ?: throw BluePrintProcessorException("couldn't get resource definition $dName source($dSource)") - val resourceSourceProperties = checkNotNull(resourceSource.properties) { "failed to get source properties for $dName " } - val sourceProperties = JacksonUtils.getInstanceFromMap(resourceSourceProperties, DatabaseResourceSource::class.java) - - val sql = checkNotNull(sourceProperties.query) { "failed to get request query for $dName under $dSource properties" } - val inputKeyMapping = checkNotNull(sourceProperties.inputKeyMapping) { "failed to get input-key-mappings for $dName under $dSource properties" } - - logger.info("$dSource dictionary information : ($sql), ($inputKeyMapping), (${sourceProperties.outputKeyMapping})") - val jdbcTemplate = blueprintDBLibService(sourceProperties) - - val rows = jdbcTemplate.query(sql, populateNamedParameter(inputKeyMapping)) - if (rows.isNullOrEmpty()) { - logger.warn("Failed to get $dSource result for dictionary name ($dName) the query ($sql)") - } else { - populateResource(resourceAssignment, sourceProperties, rows) + open fun setValueFromDB(resourceAssignment: ResourceAssignment) { + val dName = resourceAssignment.dictionaryName!! + val dSource = resourceAssignment.dictionarySource!! + val resourceDefinition = resourceDefinition(dName) + + /** Check Resource Assignment has the source definitions, If not get from Resource Definition **/ + val resourceSource = resourceAssignment.dictionarySourceDefinition + ?: resourceDefinition?.sources?.get(dSource) + ?: throw BluePrintProcessorException("couldn't get resource definition $dName source($dSource)") + val resourceSourceProperties = checkNotNull(resourceSource.properties) { + "failed to get source properties for $dName " + } + val sourceProperties = + JacksonUtils.getInstanceFromMap(resourceSourceProperties, DatabaseResourceSource::class.java) + + val sql = checkNotNull(sourceProperties.query) { + "failed to get request query for $dName under $dSource properties" + } + val inputKeyMapping = checkNotNull(sourceProperties.inputKeyMapping) { + "failed to get input-key-mappings for $dName under $dSource properties" + } + + val resolvedInputKeyMapping = resolveInputKeyMappingVariables( + inputKeyMapping, + resourceAssignment.templatingConstants + ).toMutableMap() + logger.info("\nResolved Input Key mappings: \n$resolvedInputKeyMapping") + + resolvedInputKeyMapping.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})" + ) + val jdbcTemplate = blueprintDBLibService(sourceProperties, dSource) + + val rows = jdbcTemplate.query(sql, populateNamedParameter(resolvedInputKeyMapping)) + if (rows.isEmpty()) { + logger.warn("Emptyset from dictionary-source($dSource) for dictionary name ($dName) the query ($sql).") } + logger.debug("Query returned ${rows.size} values") + populateResource(resourceAssignment, sourceProperties, rows) } - private fun blueprintDBLibService(sourceProperties: DatabaseResourceSource): BluePrintDBLibGenericService { - return if (checkNotEmpty(sourceProperties.endpointSelector)) { + open fun blueprintDBLibService(sourceProperties: DatabaseResourceSource, selector: String): BluePrintDBLibGenericService { + return if (isNotEmpty(sourceProperties.endpointSelector)) { val dbPropertiesJson = raRuntimeService.resolveDSLExpression(sourceProperties.endpointSelector!!) - bluePrintDBLibPropertySevice.JdbcTemplate(dbPropertiesJson) + bluePrintDBLibPropertyService.JdbcTemplate(dbPropertiesJson) } else { - primaryDBLibGenericService + bluePrintDBLibPropertyService.JdbcTemplate(selector) } - } @Throws(BluePrintProcessorException::class) - private fun validate(resourceAssignment: ResourceAssignment) { - checkNotEmptyOrThrow(resourceAssignment.name, "resource assignment template key is not defined") - checkNotEmptyOrThrow(resourceAssignment.dictionaryName, "resource assignment dictionary name is not defined for template key (${resourceAssignment.name})") - checkEqualsOrThrow(ResourceDictionaryConstants.SOURCE_PROCESSOR_DB, resourceAssignment.dictionarySource) { - "resource assignment source is not ${ResourceDictionaryConstants.SOURCE_PROCESSOR_DB} but it is ${resourceAssignment.dictionarySource}" + open fun validate(resourceAssignment: ResourceAssignment) { + checkNotEmpty(resourceAssignment.name) { "resource assignment template key is not defined" } + checkNotEmpty(resourceAssignment.dictionaryName) { + "resource assignment dictionary name is not defined for template key (${resourceAssignment.name})" } + check(resourceAssignment.dictionarySource in getListOfDBSources()) { + "resource assignment source ${resourceAssignment.dictionarySource} is not registered in \"resourceSourceMappings\"" + } + } + + // placeholder to get the list of DB sources. + open fun getListOfDBSources(): Array { + return ResourceSourceMappingFactory.getRegisterSourceMapping() + .resourceSourceMappings.filterValues { it == "source-db" }.keys.toTypedArray() } - private fun populateNamedParameter(inputKeyMapping: Map): Map { + open fun populateNamedParameter(inputKeyMapping: Map): Map { val namedParameters = HashMap() inputKeyMapping.forEach { - val expressionValue = raRuntimeService.getDictionaryStore(it.value).textValue() + val expressionValue = it.value.textValue() logger.trace("Reference dictionary key (${it.key}) resulted in value ($expressionValue)") namedParameters[it.key] = expressionValue } - logger.info("Parameter information : ({})", namedParameters) + if (namedParameters.isNotEmpty()) { + logger.info("Parameter information : ($namedParameters)") + } return namedParameters } @Throws(BluePrintProcessorException::class) - private fun populateResource(resourceAssignment: ResourceAssignment, sourceProperties: DatabaseResourceSource, rows: List>) { + open fun populateResource( + resourceAssignment: ResourceAssignment, + sourceProperties: DatabaseResourceSource, + rows: List> + ) { val dName = resourceAssignment.dictionaryName val dSource = resourceAssignment.dictionarySource val type = nullToEmpty(resourceAssignment.property?.type) - val outputKeyMapping = checkNotNull(sourceProperties.outputKeyMapping) { "failed to get output-key-mappings for $dName under $dSource properties" } - logger.info("Response processing type($type)") + val outputKeyMapping = checkNotNull(sourceProperties.outputKeyMapping) { + "failed to get output-key-mappings for $dName under $dSource properties" + } + logger.info("Response processing type ($type)") - // Primitive Types - when (type) { - in BluePrintTypes.validPrimitiveTypes() -> { - val dbColumnValue = rows[0][outputKeyMapping[dName]] - logger.info("For template key (${resourceAssignment.name}) setting value as ($dbColumnValue)") - ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, dbColumnValue) - } - in BluePrintTypes.validCollectionTypes() -> { - val entrySchemaType = returnNotEmptyOrThrow(resourceAssignment.property?.entrySchema?.type) { "Entry schema is not defined for dictionary ($dName) info" } - val arrayNode = JsonNodeFactory.instance.arrayNode() - rows.forEach { - if (entrySchemaType in BluePrintTypes.validPrimitiveTypes()) { - val dbColumnValue = it[outputKeyMapping[dName]] - // Add Array JSON - JacksonUtils.populatePrimitiveValues(dbColumnValue!!, entrySchemaType, arrayNode) - } else { - val arrayChildNode = JsonNodeFactory.instance.objectNode() - for (mapping in outputKeyMapping.entries) { - val dbColumnValue = checkNotNull(it[mapping.key]) - val propertyTypeForDataType = ResourceAssignmentUtils.getPropertyType(raRuntimeService, entrySchemaType, mapping.key) - JacksonUtils.populatePrimitiveValues(mapping.key, dbColumnValue, propertyTypeForDataType, arrayChildNode) - } - arrayNode.add(arrayChildNode) - } - } - logger.info("For template key (${resourceAssignment.name}) setting value as ($arrayNode)") - // Set the List of Complex Values - ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, arrayNode) - } - else -> { - // Complex Types - val row = rows[0] - val objectNode = JsonNodeFactory.instance.objectNode() - for (mapping in outputKeyMapping.entries) { - val dbColumnValue = checkNotNull(row[mapping.key]) - val propertyTypeForDataType = ResourceAssignmentUtils.getPropertyType(raRuntimeService, type, mapping.key) - JacksonUtils.populatePrimitiveValues(mapping.key, dbColumnValue, propertyTypeForDataType, objectNode) - } - logger.info("For template key (${resourceAssignment.name}) setting value as ($objectNode)") - ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, objectNode) - } + val responseNode = checkNotNull(JacksonUtils.getJsonNode(rows)) { + "Failed to get database query result into Json node." } + + val parsedResponseNode = ResourceAssignmentUtils.parseResponseNode( + responseNode, resourceAssignment, + raRuntimeService, outputKeyMapping + ) + ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, parsedResponseNode) } - override fun recover(runtimeException: RuntimeException, resourceAssignment: ResourceAssignment) { - raRuntimeService.getBluePrintError().addError(runtimeException.message!!) + override suspend fun recoverNB(runtimeException: RuntimeException, resourceAssignment: ResourceAssignment) { + addError(runtimeException.message!!) } -} \ No newline at end of file +}