Mesh input-key-mapping using velocity

Change-Id: Ic7190c86fc4e3f66fe7223c1c3575279c2c1d105
Issue-ID: CCSDK-1131
Signed-off-by: Alexis de Talhouët <adetalhouet89@gmail.com>
diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt
index ca4d631..bac76e7 100644
--- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt
+++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/DatabaseResourceAssignmentProcessor.kt
@@ -37,7 +37,6 @@
 import org.springframework.context.annotation.Scope
 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate
 import org.springframework.stereotype.Service
-import java.util.*
 
 /**
  * DatabaseResourceAssignmentProcessor
@@ -77,12 +76,16 @@
                 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 resolvedInputKeyMapping = resolveInputKeyMappingVariables(inputKeyMapping)
+
+                val resolvedSql = resolveFromInputKeyMapping(sql, resolvedInputKeyMapping)
+
+                logger.info("$dSource dictionary information : ($resolvedSql), ($inputKeyMapping), (${sourceProperties.outputKeyMapping})")
                 val jdbcTemplate = blueprintDBLibService(sourceProperties)
 
-                val rows = jdbcTemplate.queryForList(sql, populateNamedParameter(inputKeyMapping))
+                val rows = jdbcTemplate.queryForList(resolvedSql, resolvedInputKeyMapping)
                 if (rows.isNullOrEmpty()) {
-                    logger.warn("Failed to get $dSource result for dictionary name ($dName) the query ($sql)")
+                    logger.warn("Failed to get $dSource result for dictionary name ($dName) the query ($resolvedSql)")
                 } else {
                     populateResource(resourceAssignment, sourceProperties, rows)
                 }
@@ -115,17 +118,6 @@
         }
     }
 
-    private fun populateNamedParameter(inputKeyMapping: Map<String, String>): Map<String, Any> {
-        val namedParameters = HashMap<String, Any>()
-        inputKeyMapping.forEach {
-            val expressionValue = raRuntimeService.getDictionaryStore(it.value).textValue()
-            logger.trace("Reference dictionary key (${it.key}) resulted in value ($expressionValue)")
-            namedParameters[it.key] = expressionValue
-        }
-        logger.info("Parameter information : ({})", namedParameters)
-        return namedParameters
-    }
-
     @Throws(BluePrintProcessorException::class)
     private fun populateResource(resourceAssignment: ResourceAssignment, sourceProperties: DatabaseResourceSource, rows: List<Map<String, Any>>) {
         val dName = resourceAssignment.dictionaryName
diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/ResourceAssignmentProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/ResourceAssignmentProcessor.kt
index 9b7c70a..3022ca5 100644
--- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/ResourceAssignmentProcessor.kt
+++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/ResourceAssignmentProcessor.kt
@@ -17,12 +17,16 @@
 
 package org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.processor
 
+import org.apache.commons.collections.MapUtils
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService
 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException
 import org.onap.ccsdk.apps.controllerblueprints.core.interfaces.BlueprintFunctionNode
+import org.onap.ccsdk.apps.controllerblueprints.core.service.BluePrintTemplateService
+import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceAssignment
 import org.onap.ccsdk.apps.controllerblueprints.resource.dict.ResourceDefinition
 import org.slf4j.LoggerFactory
+import java.util.*
 
 abstract class ResourceAssignmentProcessor : BlueprintFunctionNode<ResourceAssignment, ResourceAssignment> {
 
@@ -38,12 +42,32 @@
      */
     open fun <T> scriptPropertyInstanceType(name: String): T {
         return scriptPropertyInstances as? T
-                ?: throw BluePrintProcessorException("couldn't get script property instance ($name)")
+            ?: throw BluePrintProcessorException("couldn't get script property instance ($name)")
     }
 
     open fun resourceDefinition(name: String): ResourceDefinition {
         return resourceDictionaries[name]
-                ?: throw BluePrintProcessorException("couldn't get resource definition for ($name)")
+            ?: throw BluePrintProcessorException("couldn't get resource definition for ($name)")
+    }
+
+    open fun resolveInputKeyMappingVariables(inputKeyMapping: Map<String, String>): Map<String, Any> {
+        val resolvedInputKeyMapping = HashMap<String, Any>()
+        if (MapUtils.isNotEmpty(inputKeyMapping)) {
+            for ((key, value) in inputKeyMapping) {
+                val resultValue = raRuntimeService.getResolutionStore(value)
+                val expressionValue = JacksonUtils.getValue(resultValue)
+                log.trace("Reference dictionary key ({}), value ({})", key, expressionValue)
+                resolvedInputKeyMapping[key] = expressionValue
+            }
+        }
+        return resolvedInputKeyMapping
+    }
+
+    open fun resolveFromInputKeyMapping(valueToResolve: String, keyMapping: Map<String, Any>): String {
+        if (valueToResolve.isEmpty() || !valueToResolve.contains("$")) {
+            return valueToResolve
+        }
+        return BluePrintTemplateService.generateContent(valueToResolve, additionalContext = keyMapping)
     }
 
     override fun prepareRequest(resourceAssignment: ResourceAssignment): ResourceAssignment {
diff --git a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt
index 9bb1ea2..73ccfb2 100644
--- a/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt
+++ b/ms/blueprintsprocessor/functions/resource-resolution/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/functions/resource/resolution/processor/RestResourceResolutionProcessor.kt
@@ -19,8 +19,6 @@
 
 import com.fasterxml.jackson.databind.node.ArrayNode
 import com.fasterxml.jackson.databind.node.JsonNodeFactory
-import com.fasterxml.jackson.databind.node.ObjectNode
-import org.apache.commons.collections.MapUtils
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants.PREFIX_RESOURCE_RESOLUTION_PROCESSOR
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.RestResourceSource
 import org.onap.ccsdk.apps.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
@@ -40,7 +38,6 @@
 import org.springframework.beans.factory.config.ConfigurableBeanFactory
 import org.springframework.context.annotation.Scope
 import org.springframework.stereotype.Service
-import java.util.*
 
 /**
  * RestResourceResolutionProcessor
@@ -81,7 +78,7 @@
                 val path = nullToEmpty(sourceProperties.path)
                 val inputKeyMapping =
                     checkNotNull(sourceProperties.inputKeyMapping) { "failed to get input-key-mappings for $dName under $dSource properties" }
-                val resolvedInputKeyMapping = populateInputKeyMappingVariables(inputKeyMapping)
+                val resolvedInputKeyMapping = resolveInputKeyMappingVariables(inputKeyMapping)
 
                 // Resolving content Variables
                 val payload = resolveFromInputKeyMapping(nullToEmpty(sourceProperties.payload), resolvedInputKeyMapping)
@@ -170,7 +167,9 @@
             }
             else -> {
                 // Complex Types
-                val objectNode = responseNode as ObjectNode
+                entrySchemaType =
+                    returnNotEmptyOrThrow(resourceAssignment.property?.entrySchema?.type) { "Entry schema is not defined for dictionary ($dName) info" }
+                val objectNode = JsonNodeFactory.instance.objectNode()
                 outputKeyMapping.map {
                     val responseKeyValue = responseNode.get(it.key)
                     val propertyTypeForDataType =
@@ -186,29 +185,6 @@
         }
     }
 
-    private fun populateInputKeyMappingVariables(inputKeyMapping: Map<String, String>): Map<String, Any> {
-        val resolvedInputKeyMapping = HashMap<String, Any>()
-        if (MapUtils.isNotEmpty(inputKeyMapping)) {
-            for ((key, value) in inputKeyMapping) {
-                val expressionValue = raRuntimeService.getResolutionStore(value).asText()
-                logger.trace("Reference dictionary key ({}), value ({})", key, expressionValue)
-                resolvedInputKeyMapping[key] = expressionValue
-            }
-        }
-        return resolvedInputKeyMapping
-    }
-
-    private fun resolveFromInputKeyMapping(valueToResolve: String, keyMapping: Map<String, Any>): String {
-        if (valueToResolve.isEmpty() || !valueToResolve.contains("$")) {
-            return valueToResolve
-        }
-        var res = valueToResolve
-        for (entry in keyMapping.entries) {
-            res = res.replace(("\\$" + entry.key).toRegex(), entry.value.toString())
-        }
-        return res
-    }
-
     @Throws(BluePrintProcessorException::class)
     private fun validate(resourceAssignment: ResourceAssignment) {
         checkNotEmptyOrThrow(resourceAssignment.name, "resource assignment template key is not defined")