Spring boot, Kotlin version upgrades
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / utils / JacksonUtils.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2018-2019 IBM.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.onap.ccsdk.cds.controllerblueprints.core.utils
18
19 import com.fasterxml.jackson.annotation.JsonInclude
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.fasterxml.jackson.databind.SerializationFeature
22 import com.fasterxml.jackson.databind.node.ArrayNode
23 import com.fasterxml.jackson.databind.node.BooleanNode
24 import com.fasterxml.jackson.databind.node.DoubleNode
25 import com.fasterxml.jackson.databind.node.FloatNode
26 import com.fasterxml.jackson.databind.node.IntNode
27 import com.fasterxml.jackson.databind.node.MissingNode
28 import com.fasterxml.jackson.databind.node.NullNode
29 import com.fasterxml.jackson.databind.node.ObjectNode
30 import com.fasterxml.jackson.databind.node.TextNode
31 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
32 import kotlinx.coroutines.Dispatchers
33 import kotlinx.coroutines.runBlocking
34 import kotlinx.coroutines.withContext
35 import org.apache.commons.io.IOUtils
36 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants
37 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
38 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
39 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintTypes
40 import org.onap.ccsdk.cds.controllerblueprints.core.normalizedFile
41 import org.onap.ccsdk.cds.controllerblueprints.core.readNBText
42 import java.io.File
43 import java.io.InputStream
44 import java.nio.charset.Charset
45
46 /**
47  *
48  *
49  * @author Brinda Santh
50  */
51 class JacksonUtils {
52
53     companion object {
54
55         val objectMapper = jacksonObjectMapper()
56
57         inline fun <reified T : Any> readValue(content: String): T =
58             objectMapper.readValue(content, T::class.java)
59
60         inline fun <reified T : Any> readValue(stream: InputStream): T =
61             objectMapper.readValue(stream, T::class.java)
62
63         fun <T> readValue(content: String, valueType: Class<T>): T? {
64             return objectMapper.readValue(content, valueType)
65         }
66
67         fun <T> readValue(stream: InputStream, valueType: Class<T>): T? {
68             return objectMapper.readValue(stream, valueType)
69         }
70
71         fun <T> readValue(node: JsonNode, valueType: Class<T>): T? {
72             return objectMapper.treeToValue(node, valueType)
73         }
74
75         fun getContent(fileName: String): String = runBlocking {
76             try {
77                 normalizedFile(fileName).readNBText()
78             } catch (e: Exception) {
79                 throw BluePrintException("couldn't get file ($fileName) content : ${e.message}")
80             }
81         }
82
83         fun getClassPathFileContent(fileName: String): String {
84             return runBlocking {
85                 withContext(Dispatchers.Default) {
86                     IOUtils.toString(
87                         JacksonUtils::class.java.classLoader
88                             .getResourceAsStream(fileName), Charset.defaultCharset()
89                     )
90                 }
91             }
92         }
93
94         fun <T> readValueFromFile(fileName: String, valueType: Class<T>): T? {
95             val content: String = getContent(fileName)
96             return readValue(content, valueType)
97         }
98
99         fun <T> readValueFromClassPathFile(fileName: String, valueType: Class<T>): T? {
100             val content: String = getClassPathFileContent(fileName)
101             return readValue(content, valueType)
102         }
103
104         fun objectNodeFromObject(from: kotlin.Any): ObjectNode {
105             return objectMapper.convertValue(from, ObjectNode::class.java)
106         }
107
108         fun jsonNodeFromObject(from: kotlin.Any): JsonNode {
109             return objectMapper.convertValue(from, JsonNode::class.java)
110         }
111
112         fun jsonNodeFromClassPathFile(fileName: String): JsonNode {
113             val content: String = getClassPathFileContent(fileName)
114             return jsonNode(content)
115         }
116
117         fun jsonNodeFromFile(fileName: String): JsonNode {
118             val content: String = getContent(fileName)
119             return jsonNode(content)
120         }
121
122         fun jsonNode(content: String): JsonNode {
123             return jacksonObjectMapper().readTree(content)
124         }
125
126         fun getJson(any: kotlin.Any): String {
127             return getJson(any, false)
128         }
129
130         fun getWrappedJson(wrapper: String, any: kotlin.Any, pretty: Boolean = false): String {
131             val wrapperMap = hashMapOf<String, Any>()
132             wrapperMap[wrapper] = any
133             return getJson(wrapperMap, pretty)
134         }
135
136         fun getJson(any: kotlin.Any, pretty: Boolean = false): String {
137             val objectMapper = jacksonObjectMapper()
138             objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
139             if (pretty) {
140                 objectMapper.enable(SerializationFeature.INDENT_OUTPUT)
141             }
142             return objectMapper.writeValueAsString(any)
143         }
144
145         fun getJsonNode(any: kotlin.Any?, pretty: Boolean = false): JsonNode {
146             val objectMapper = jacksonObjectMapper()
147             objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
148             if (pretty) {
149                 objectMapper.enable(SerializationFeature.INDENT_OUTPUT)
150             }
151             return objectMapper.valueToTree(any)
152         }
153
154         fun <T> getListFromJsonNode(node: JsonNode, valueType: Class<T>): List<T> {
155             return getListFromJson(node.toString(), valueType)
156         }
157
158         fun <T> getListFromJson(content: String, valueType: Class<T>): List<T> {
159             val objectMapper = jacksonObjectMapper()
160             val javaType = objectMapper.typeFactory.constructCollectionType(List::class.java, valueType)
161             return objectMapper.readValue<List<T>>(content, javaType)
162         }
163
164         fun <T> getListFromFile(fileName: String, valueType: Class<T>): List<T> {
165             val content: String = getContent(fileName)
166             return getListFromJson(content, valueType)
167         }
168
169         fun <T> getListFromClassPathFile(fileName: String, valueType: Class<T>): List<T> {
170             val content: String = getClassPathFileContent(fileName)
171             return getListFromJson(content, valueType)
172         }
173
174         fun <T> getMapFromJson(content: String, valueType: Class<T>): MutableMap<String, T> {
175             val objectMapper = jacksonObjectMapper()
176             val mapType = objectMapper.typeFactory.constructMapType(Map::class.java, String::class.java, valueType)
177             return objectMapper.readValue(content, mapType)
178         }
179
180         fun <T> getMapFromFile(file: File, valueType: Class<T>): MutableMap<String, T> = runBlocking {
181             val content: String = file.readNBText()
182             getMapFromJson(content, valueType)
183         }
184
185         fun <T> getMapFromFile(fileName: String, valueType: Class<T>): MutableMap<String, T> = getMapFromFile(File(fileName), valueType)
186
187         fun <T> getInstanceFromMap(properties: MutableMap<String, JsonNode>, classType: Class<T>): T {
188             return readValue(getJson(properties), classType)
189                 ?: throw BluePrintProcessorException("failed to transform content ($properties) to type ($classType)")
190         }
191
192         fun checkJsonNodeValueOfType(type: String, jsonNode: JsonNode): Boolean {
193             if (BluePrintTypes.validPrimitiveTypes().contains(type.toLowerCase())) {
194                 return checkJsonNodeValueOfPrimitiveType(type, jsonNode)
195             } else if (BluePrintTypes.validCollectionTypes().contains(type)) {
196                 return checkJsonNodeValueOfCollectionType(type, jsonNode)
197             }
198             return false
199         }
200
201         fun checkIfPrimitiveType(primitiveType: String): Boolean {
202             return when (primitiveType.toLowerCase()) {
203                 BluePrintConstants.DATA_TYPE_STRING -> true
204                 BluePrintConstants.DATA_TYPE_BOOLEAN -> true
205                 BluePrintConstants.DATA_TYPE_INTEGER -> true
206                 BluePrintConstants.DATA_TYPE_FLOAT -> true
207                 BluePrintConstants.DATA_TYPE_DOUBLE -> true
208                 BluePrintConstants.DATA_TYPE_TIMESTAMP -> true
209                 else -> false
210             }
211         }
212
213         fun checkJsonNodeValueOfPrimitiveType(primitiveType: String, jsonNode: JsonNode): Boolean {
214             return when (primitiveType.toLowerCase()) {
215                 BluePrintConstants.DATA_TYPE_STRING -> jsonNode.isTextual
216                 BluePrintConstants.DATA_TYPE_BOOLEAN -> jsonNode.isBoolean
217                 BluePrintConstants.DATA_TYPE_INTEGER -> jsonNode.isInt
218                 BluePrintConstants.DATA_TYPE_FLOAT -> jsonNode.isDouble
219                 BluePrintConstants.DATA_TYPE_DOUBLE -> jsonNode.isDouble
220                 BluePrintConstants.DATA_TYPE_TIMESTAMP -> jsonNode.isTextual
221                 else -> false
222             }
223         }
224
225         fun checkJsonNodeValueOfCollectionType(type: String, jsonNode: JsonNode): Boolean {
226             return when (type.toLowerCase()) {
227                 BluePrintConstants.DATA_TYPE_LIST -> jsonNode.isArray
228                 else -> false
229             }
230         }
231
232         fun getValue(value: JsonNode): Any {
233             return when (value) {
234                 is BooleanNode -> value.booleanValue()
235                 is IntNode -> value.intValue()
236                 is FloatNode -> value.floatValue()
237                 is DoubleNode -> value.doubleValue()
238                 is TextNode -> value.textValue()
239                 else -> value
240             }
241         }
242
243         fun getValue(value: Any, type: String): Any {
244             return when (type.toLowerCase()) {
245                 BluePrintConstants.DATA_TYPE_BOOLEAN -> (value as BooleanNode).booleanValue()
246                 BluePrintConstants.DATA_TYPE_INTEGER -> (value as IntNode).intValue()
247                 BluePrintConstants.DATA_TYPE_FLOAT -> (value as FloatNode).floatValue()
248                 BluePrintConstants.DATA_TYPE_DOUBLE -> (value as DoubleNode).doubleValue()
249                 BluePrintConstants.DATA_TYPE_STRING -> (value as TextNode).textValue()
250                 else -> (value as JsonNode)
251             }
252         }
253
254         fun populatePrimitiveValues(key: String, value: JsonNode, primitiveType: String, objectNode: ObjectNode) {
255             when (primitiveType.toLowerCase()) {
256                 BluePrintConstants.DATA_TYPE_BOOLEAN,
257                 BluePrintConstants.DATA_TYPE_INTEGER,
258                 BluePrintConstants.DATA_TYPE_FLOAT,
259                 BluePrintConstants.DATA_TYPE_DOUBLE,
260                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
261                 BluePrintConstants.DATA_TYPE_STRING,
262                 BluePrintConstants.DATA_TYPE_NULL ->
263                     objectNode.set(key, value)
264                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
265             }
266         }
267
268         fun populatePrimitiveValues(value: JsonNode, primitiveType: String, arrayNode: ArrayNode) {
269             when (primitiveType.toLowerCase()) {
270                 BluePrintConstants.DATA_TYPE_BOOLEAN,
271                 BluePrintConstants.DATA_TYPE_INTEGER,
272                 BluePrintConstants.DATA_TYPE_FLOAT,
273                 BluePrintConstants.DATA_TYPE_DOUBLE,
274                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
275                 BluePrintConstants.DATA_TYPE_STRING,
276                 BluePrintConstants.DATA_TYPE_NULL ->
277                     arrayNode.add(value)
278                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
279             }
280         }
281
282         fun populatePrimitiveDefaultValues(key: String, primitiveType: String, objectNode: ObjectNode) {
283             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
284                 ?: throw BluePrintException("populatePrimitiveDefaultValues expected only primitive values! Received type ($primitiveType)")
285             objectNode.set<JsonNode>(key, defaultValue)
286         }
287
288         fun populatePrimitiveDefaultValuesForArrayNode(primitiveType: String, arrayNode: ArrayNode) {
289             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
290                 ?: throw BluePrintException("populatePrimitiveDefaultValuesForArrayNode expected only primitive values! Received type ($primitiveType)")
291             arrayNode.add(defaultValue)
292         }
293
294         private fun getDefaultValueOfPrimitiveAsJsonNode(primitiveType: String): JsonNode? {
295             return when (primitiveType.toLowerCase()) {
296                 BluePrintConstants.DATA_TYPE_BOOLEAN -> BooleanNode.valueOf(false)
297                 BluePrintConstants.DATA_TYPE_INTEGER -> IntNode.valueOf(0)
298                 BluePrintConstants.DATA_TYPE_FLOAT -> FloatNode.valueOf(0.0f)
299                 BluePrintConstants.DATA_TYPE_DOUBLE -> DoubleNode.valueOf(0.0)
300                 BluePrintConstants.DATA_TYPE_STRING -> MissingNode.getInstance()
301                 else -> null
302             }
303         }
304
305         fun populateJsonNodeValues(key: String, nodeValue: JsonNode?, type: String, objectNode: ObjectNode) {
306             if (nodeValue == null || nodeValue is NullNode) {
307                 objectNode.set<JsonNode>(key, nodeValue)
308             } else if (BluePrintTypes.validPrimitiveTypes().contains(type)) {
309                 populatePrimitiveValues(key, nodeValue, type, objectNode)
310             } else {
311                 objectNode.set<JsonNode>(key, nodeValue)
312             }
313         }
314
315         fun convertPrimitiveResourceValue(type: String, value: String): JsonNode {
316             return when (type.toLowerCase()) {
317                 BluePrintConstants.DATA_TYPE_BOOLEAN -> jsonNodeFromObject(value.toBoolean())
318                 BluePrintConstants.DATA_TYPE_INTEGER -> jsonNodeFromObject(value.toInt())
319                 BluePrintConstants.DATA_TYPE_FLOAT -> jsonNodeFromObject(value.toFloat())
320                 BluePrintConstants.DATA_TYPE_DOUBLE -> jsonNodeFromObject(value.toDouble())
321                 BluePrintConstants.DATA_TYPE_STRING -> jsonNodeFromObject(value)
322                 else -> getJsonNode(value)
323             }
324         }
325     }
326 }