Enhancing BluePrintJinjaTemplateService
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / service / BluePrintJinjaTemplateService.kt
1 /*
2  * Copyright © 2019 IBM, Bell Canada.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.ccsdk.cds.controllerblueprints.core.service
18
19 import com.fasterxml.jackson.core.type.TypeReference
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.fasterxml.jackson.databind.ObjectMapper
22 import com.hubspot.jinjava.Jinjava
23 import com.hubspot.jinjava.JinjavaConfig
24 import com.hubspot.jinjava.interpret.Context
25 import com.hubspot.jinjava.interpret.InterpreterFactory
26 import com.hubspot.jinjava.interpret.JinjavaInterpreter
27 import com.hubspot.jinjava.loader.ResourceLocator
28 import com.hubspot.jinjava.loader.ResourceNotFoundException
29 import com.hubspot.jinjava.objects.serialization.PyishObjectMapper
30 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
31 import org.onap.ccsdk.cds.controllerblueprints.core.config.BluePrintLoadConfiguration
32 import org.onap.ccsdk.cds.controllerblueprints.core.interfaces.BluePrintJsonNodeFactory
33 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedPathName
34 import org.onap.ccsdk.cds.controllerblueprints.core.removeNullNode
35 import java.io.IOException
36 import java.nio.charset.Charset
37 import java.nio.file.Files.readAllBytes
38 import java.nio.file.Paths
39 import java.util.Objects
40
41 object BluePrintJinjaTemplateService {
42
43     /**
44      * To enable inheritance within CBA, we need Jinja runtime to know where to load the templates.
45      */
46     class BlueprintRelatedTemplateLocator(
47         private val bluePrintLoadConfiguration: BluePrintLoadConfiguration,
48         private val artifactName: String,
49         private val artifactVersion: String
50     ) : ResourceLocator {
51
52         @Throws(IOException::class)
53         override fun getString(fullName: String, encoding: Charset, interpreter: JinjavaInterpreter): String {
54             try {
55                 val deployFile =
56                     normalizedPathName(
57                         bluePrintLoadConfiguration.blueprintDeployPath,
58                         artifactName,
59                         artifactVersion,
60                         fullName
61                     )
62
63                 return String(readAllBytes(Paths.get(deployFile)))
64             } catch (var5: IllegalArgumentException) {
65                 throw ResourceNotFoundException("Couldn't find resource: $fullName")
66             }
67         }
68     }
69
70     fun generateContent(
71         template: String,
72         json: String,
73         ignoreJsonNull: Boolean,
74         additionalContext: MutableMap<String, Any>,
75         bluePrintLoadConfiguration: BluePrintLoadConfiguration,
76         artifactName: String,
77         artifactVersion: String
78     ): String {
79
80         return generateContent(
81             template,
82             json,
83             ignoreJsonNull,
84             additionalContext,
85             BlueprintRelatedTemplateLocator(bluePrintLoadConfiguration, artifactName, artifactVersion)
86         )
87     }
88
89     fun generateContent(
90         template: String,
91         json: String,
92         ignoreJsonNull: Boolean,
93         additionalContext: MutableMap<String, Any>,
94         resourceLocator: ResourceLocator? = null
95     ): String {
96         // Add the JSON Data to the context
97         if (json.isNotEmpty()) {
98             val mapper = ObjectMapper().setNodeFactory(BluePrintJsonNodeFactory())
99             val jsonNode = mapper.readValue(json, JsonNode::class.java)
100                 ?: throw BluePrintProcessorException("couldn't get json node from json")
101             if (ignoreJsonNull) {
102                 jsonNode.removeNullNode()
103             }
104             additionalContext.putAll(mapper.readValue(json, object : TypeReference<Map<String, Any>>() {}))
105         }
106
107         val jinjava = Jinjava(
108             JinjavaConfig(object : InterpreterFactory {
109                 override fun newInstance(interpreter: JinjavaInterpreter): JinjavaInterpreter {
110                     return CustomJinjavaInterpreter(interpreter)
111                 }
112
113                 override fun newInstance(jinjava: Jinjava, context: Context, config: JinjavaConfig): JinjavaInterpreter {
114                     return CustomJinjavaInterpreter(jinjava, context, config)
115                 }
116             })
117         )
118
119         if (resourceLocator != null) {
120             jinjava.resourceLocator = resourceLocator
121         }
122
123         return jinjava.render(template, additionalContext)
124     }
125
126     class CustomJinjavaInterpreter : JinjavaInterpreter {
127         constructor(interpreter: JinjavaInterpreter) : super(interpreter)
128         constructor(jinjava: Jinjava, context: Context, config: JinjavaConfig) : super(jinjava, context, config)
129
130         // Overriding actual getAsString method to return `context.currentNode.master.image` instead of empty string
131         override fun getAsString(`object`: Any?): String {
132             return if (config.legacyOverrides.isUsePyishObjectMapper)
133                 PyishObjectMapper.getAsUnquotedPyishString(`object`)
134             else
135                 Objects.toString(`object`, context.currentNode.master.image)
136         }
137     }
138 }