/* * Copyright © 2018 IBM. * * Modifications Copyright © 2017-2019 AT&T, Bell Canada * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.TextNode import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BlueprintFunctionNode import org.onap.ccsdk.cds.controllerblueprints.core.isNullOrMissing import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintVelocityTemplateService import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition import org.slf4j.LoggerFactory abstract class ResourceAssignmentProcessor : BlueprintFunctionNode { private val log = LoggerFactory.getLogger(ResourceAssignmentProcessor::class.java) lateinit var raRuntimeService: ResourceAssignmentRuntimeService var resourceDictionaries: MutableMap = hashMapOf() var resourceAssignments: MutableList = arrayListOf() var scriptPropertyInstances: MutableMap = hashMapOf() lateinit var scriptType: String /** * This will be called from the scripts to serve instance from runtime to scripts. */ open fun scriptPropertyInstanceType(name: String): T { return scriptPropertyInstances as? T ?: throw BluePrintProcessorException("couldn't get script property instance ($name)") } open fun setFromInput(resourceAssignment: ResourceAssignment): Boolean { try { val value = raRuntimeService.getInputValue(resourceAssignment.name) if (!value.isNullOrMissing()) { log.debug( "For Resource:(${resourceAssignment.name}) found value:({}) in input-data.", ResourceAssignmentUtils.getValueToLog(resourceAssignment.property?.metadata, value) ) ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value) return true } } catch (e: BluePrintProcessorException) { // NoOp - couldn't find value from input } return false } open fun setFromInputKeyDependencies(keys: MutableList, resourceAssignment: ResourceAssignment): Boolean { try { for (dependencyKey in keys) { var value = raRuntimeService.getInputValue(dependencyKey) if (!value.isNullOrMissing()) { log.debug( "For Resource:(${resourceAssignment.name}) found value:({}) in input-data under: ($dependencyKey).", ResourceAssignmentUtils.getValueToLog(resourceAssignment.property?.metadata, value) ) ResourceAssignmentUtils.setResourceDataValue(resourceAssignment, raRuntimeService, value) return true } } } catch (e: BluePrintProcessorException) { // NoOp - couldn't find value from input } return false } open fun resourceDefinition(name: String): ResourceDefinition? { return if (resourceDictionaries.containsKey(name)) resourceDictionaries[name] else null } open fun resolveInputKeyMappingVariables( inputKeyMapping: Map, templatingConstants: Map? ): Map { val const = templatingConstants?.mapValues { TextNode(it.value) as JsonNode } return inputKeyMapping.mapValues { const?.get(it.value) ?: raRuntimeService.getResolutionStore(it.value) } } open suspend fun resolveFromInputKeyMapping(valueToResolve: String, keyMapping: MutableMap): String { if (valueToResolve.isEmpty() || !valueToResolve.contains("$")) { return valueToResolve } // TODO("Optimize to JSON Node directly without velocity").asJsonNode().toString() return BluePrintVelocityTemplateService.generateContent(valueToResolve, keyMapping.asJsonNode().toString()) } final override suspend fun applyNB(resourceAssignment: ResourceAssignment): Boolean { try { processNB(resourceAssignment) } catch (runtimeException: RuntimeException) { log.error("failed in ${getName()} : ${runtimeException.message}", runtimeException) recoverNB(runtimeException, resourceAssignment) return false } return true } open suspend fun executeScript(resourceAssignment: ResourceAssignment) { return when (scriptType) { BluePrintConstants.SCRIPT_JYTHON -> { executeScriptBlocking(resourceAssignment) } else -> { executeScriptNB(resourceAssignment) } } } private suspend fun executeScriptNB(resourceAssignment: ResourceAssignment) { try { processNB(resourceAssignment) } catch (runtimeException: RuntimeException) { log.error("failed in ${getName()} : ${runtimeException.message}", runtimeException) recoverNB(runtimeException, resourceAssignment) } } private fun executeScriptBlocking(resourceAssignment: ResourceAssignment) { try { process(resourceAssignment) } catch (runtimeException: RuntimeException) { log.error("failed in ResourceAssignmentProcessor : ${runtimeException.message}", runtimeException) recover(runtimeException, resourceAssignment) } } /** * If Jython Script, Override Blocking methods(process() and recover()) * If Kotlin or Internal Scripts, Override non blocking methods ( processNB() and recoverNB()), so default * blocking * methods will have default implementation, * * Always applyNB() method will be invoked, apply() won't be called from parent */ final override fun apply(resourceAssignment: ResourceAssignment): Boolean { throw BluePrintException("Not Implemented, use applyNB method") } final override fun prepareRequest(resourceAssignment: ResourceAssignment): ResourceAssignment { throw BluePrintException("Not Implemented required") } final override fun prepareResponse(): Boolean { throw BluePrintException("Not Implemented required") } final override suspend fun prepareRequestNB(resourceAssignment: ResourceAssignment): ResourceAssignment { throw BluePrintException("Not Implemented required") } final override suspend fun prepareResponseNB(): Boolean { throw BluePrintException("Not Implemented required") } override fun process(resourceAssignment: ResourceAssignment) { throw BluePrintException("Not Implemented, child class will implement this") } override fun recover(runtimeException: RuntimeException, resourceAssignment: ResourceAssignment) { throw BluePrintException("Not Implemented, child class will implement this") } fun addError(type: String, name: String, error: String) { raRuntimeService.getBluePrintError().addError(type, name, error, getName()) } fun addError(error: String) { raRuntimeService.getBluePrintError().addError(error, getName()) } open fun isTemplateKeyValueNull(resourceAssignment: ResourceAssignment): Boolean { val resourceProp = checkNotNull(resourceAssignment.property) { "Failed to populate mandatory resource resource mapping $resourceAssignment" } if (resourceProp.required != null && resourceProp.required!! && resourceProp.value.isNullOrMissing() ) { return true } return false } }