945f300afa48b3df57e566527373d0e6cd8da58f
[ccsdk/cds.git] / ms / controllerblueprints / modules / 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                 BluePrintConstants.DATA_TYPE_MAP -> jsonNode.isContainerNode
229                 else -> false
230             }
231         }
232
233         fun getValue(value: JsonNode): Any {
234             return when (value) {
235                 is BooleanNode -> value.booleanValue()
236                 is IntNode -> value.intValue()
237                 is FloatNode -> value.floatValue()
238                 is DoubleNode -> value.doubleValue()
239                 is TextNode -> value.textValue()
240                 else -> value
241             }
242         }
243
244         fun getValue(value: Any, type: String): Any {
245             return when (type.toLowerCase()) {
246                 BluePrintConstants.DATA_TYPE_BOOLEAN -> (value as BooleanNode).booleanValue()
247                 BluePrintConstants.DATA_TYPE_INTEGER -> (value as IntNode).intValue()
248                 BluePrintConstants.DATA_TYPE_FLOAT -> (value as FloatNode).floatValue()
249                 BluePrintConstants.DATA_TYPE_DOUBLE -> (value as DoubleNode).doubleValue()
250                 BluePrintConstants.DATA_TYPE_STRING -> (value as TextNode).textValue()
251                 else -> (value as JsonNode)
252             }
253         }
254
255         fun populatePrimitiveValues(key: String, value: JsonNode, primitiveType: String, objectNode: ObjectNode) {
256             when (primitiveType.toLowerCase()) {
257                 BluePrintConstants.DATA_TYPE_BOOLEAN,
258                 BluePrintConstants.DATA_TYPE_INTEGER,
259                 BluePrintConstants.DATA_TYPE_FLOAT,
260                 BluePrintConstants.DATA_TYPE_DOUBLE,
261                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
262                 BluePrintConstants.DATA_TYPE_STRING,
263                 BluePrintConstants.DATA_TYPE_NULL ->
264                     objectNode.set(key, value)
265                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
266             }
267         }
268
269         fun populatePrimitiveValues(value: JsonNode, primitiveType: String, arrayNode: ArrayNode) {
270             when (primitiveType.toLowerCase()) {
271                 BluePrintConstants.DATA_TYPE_BOOLEAN,
272                 BluePrintConstants.DATA_TYPE_INTEGER,
273                 BluePrintConstants.DATA_TYPE_FLOAT,
274                 BluePrintConstants.DATA_TYPE_DOUBLE,
275                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
276                 BluePrintConstants.DATA_TYPE_STRING,
277                 BluePrintConstants.DATA_TYPE_NULL ->
278                     arrayNode.add(value)
279                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
280             }
281         }
282
283         fun populatePrimitiveDefaultValues(key: String, primitiveType: String, objectNode: ObjectNode) {
284             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
285                 ?: throw BluePrintException("populatePrimitiveDefaultValues expected only primitive values! Received type ($primitiveType)")
286             objectNode.set(key, defaultValue)
287         }
288
289         fun populatePrimitiveDefaultValuesForArrayNode(primitiveType: String, arrayNode: ArrayNode) {
290             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
291                 ?: throw BluePrintException("populatePrimitiveDefaultValuesForArrayNode expected only primitive values! Received type ($primitiveType)")
292             arrayNode.add(defaultValue)
293         }
294
295         private fun getDefaultValueOfPrimitiveAsJsonNode(primitiveType: String): JsonNode? {
296             return when (primitiveType.toLowerCase()) {
297                 BluePrintConstants.DATA_TYPE_BOOLEAN -> BooleanNode.valueOf(false)
298                 BluePrintConstants.DATA_TYPE_INTEGER -> IntNode.valueOf(0)
299                 BluePrintConstants.DATA_TYPE_FLOAT -> FloatNode.valueOf(0.0f)
300                 BluePrintConstants.DATA_TYPE_DOUBLE -> DoubleNode.valueOf(0.0)
301                 BluePrintConstants.DATA_TYPE_STRING -> MissingNode.getInstance()
302                 else -> null
303             }
304         }
305
306         fun populateJsonNodeValues(key: String, nodeValue: JsonNode?, type: String, objectNode: ObjectNode) {
307             if (nodeValue == null || nodeValue is NullNode) {
308                 objectNode.set(key, nodeValue)
309             } else if (BluePrintTypes.validPrimitiveTypes().contains(type)) {
310                 populatePrimitiveValues(key, nodeValue, type, objectNode)
311             } else {
312                 objectNode.set(key, nodeValue)
313             }
314         }
315
316         fun convertPrimitiveResourceValue(type: String, value: String): JsonNode {
317             return when (type.toLowerCase()) {
318                 BluePrintConstants.DATA_TYPE_BOOLEAN -> jsonNodeFromObject(value.toBoolean())
319                 BluePrintConstants.DATA_TYPE_INTEGER -> jsonNodeFromObject(value.toInt())
320                 BluePrintConstants.DATA_TYPE_FLOAT -> jsonNodeFromObject(value.toFloat())
321                 BluePrintConstants.DATA_TYPE_DOUBLE -> jsonNodeFromObject(value.toDouble())
322                 BluePrintConstants.DATA_TYPE_STRING -> jsonNodeFromObject(value)
323                 else -> getJsonNode(value)
324             }
325         }
326     }
327 }