573fc17d265c913cad5e3752fdfd5599c187e22a
[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, includeNull: Boolean = false): String {
137             val objectMapper = jacksonObjectMapper()
138             if (includeNull) {
139                 objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS)
140             } else {
141                 objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
142             }
143             if (pretty) {
144                 objectMapper.enable(SerializationFeature.INDENT_OUTPUT)
145             }
146             return objectMapper.writeValueAsString(any)
147         }
148
149         fun getJsonNode(any: kotlin.Any?, pretty: Boolean = false): JsonNode {
150             val objectMapper = jacksonObjectMapper()
151             objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL)
152             if (pretty) {
153                 objectMapper.enable(SerializationFeature.INDENT_OUTPUT)
154             }
155             return objectMapper.valueToTree(any)
156         }
157
158         fun <T> getListFromJsonNode(node: JsonNode, valueType: Class<T>): List<T> {
159             return getListFromJson(node.toString(), valueType)
160         }
161
162         fun <T> getListFromJson(content: String, valueType: Class<T>): List<T> {
163             val objectMapper = jacksonObjectMapper()
164             val javaType = objectMapper.typeFactory.constructCollectionType(List::class.java, valueType)
165             return objectMapper.readValue<List<T>>(content, javaType)
166         }
167
168         fun <T> getListFromFile(fileName: String, valueType: Class<T>): List<T> {
169             val content: String = getContent(fileName)
170             return getListFromJson(content, valueType)
171         }
172
173         fun <T> getListFromClassPathFile(fileName: String, valueType: Class<T>): List<T> {
174             val content: String = getClassPathFileContent(fileName)
175             return getListFromJson(content, valueType)
176         }
177
178         fun <T> getMapFromJson(content: String, valueType: Class<T>): MutableMap<String, T> {
179             val objectMapper = jacksonObjectMapper()
180             val mapType = objectMapper.typeFactory.constructMapType(Map::class.java, String::class.java, valueType)
181             return objectMapper.readValue(content, mapType)
182         }
183
184         fun <T> getMapFromFile(file: File, valueType: Class<T>): MutableMap<String, T> = runBlocking {
185             val content: String = file.readNBText()
186             getMapFromJson(content, valueType)
187         }
188
189         fun <T> getMapFromFile(fileName: String, valueType: Class<T>): MutableMap<String, T> = getMapFromFile(File(fileName), valueType)
190
191         fun <T> getInstanceFromMap(properties: MutableMap<String, JsonNode>, classType: Class<T>): T {
192             return readValue(getJson(properties), classType)
193                 ?: throw BluePrintProcessorException("failed to transform content ($properties) to type ($classType)")
194         }
195
196         fun checkJsonNodeValueOfType(type: String, jsonNode: JsonNode): Boolean {
197             if (BluePrintTypes.validPrimitiveTypes().contains(type.toLowerCase())) {
198                 return checkJsonNodeValueOfPrimitiveType(type, jsonNode)
199             } else if (BluePrintTypes.validCollectionTypes().contains(type)) {
200                 return checkJsonNodeValueOfCollectionType(type, jsonNode)
201             }
202             return false
203         }
204
205         fun checkIfPrimitiveType(primitiveType: String): Boolean {
206             return when (primitiveType.toLowerCase()) {
207                 BluePrintConstants.DATA_TYPE_STRING -> true
208                 BluePrintConstants.DATA_TYPE_BOOLEAN -> true
209                 BluePrintConstants.DATA_TYPE_INTEGER -> true
210                 BluePrintConstants.DATA_TYPE_FLOAT -> true
211                 BluePrintConstants.DATA_TYPE_DOUBLE -> true
212                 BluePrintConstants.DATA_TYPE_TIMESTAMP -> true
213                 else -> false
214             }
215         }
216
217         fun checkJsonNodeValueOfPrimitiveType(primitiveType: String, jsonNode: JsonNode): Boolean {
218             return when (primitiveType.toLowerCase()) {
219                 BluePrintConstants.DATA_TYPE_STRING -> jsonNode.isTextual
220                 BluePrintConstants.DATA_TYPE_BOOLEAN -> jsonNode.isBoolean
221                 BluePrintConstants.DATA_TYPE_INTEGER -> jsonNode.isInt
222                 BluePrintConstants.DATA_TYPE_FLOAT -> jsonNode.isDouble
223                 BluePrintConstants.DATA_TYPE_DOUBLE -> jsonNode.isDouble
224                 BluePrintConstants.DATA_TYPE_TIMESTAMP -> jsonNode.isTextual
225                 else -> false
226             }
227         }
228
229         fun checkJsonNodeValueOfCollectionType(type: String, jsonNode: JsonNode): Boolean {
230             return when (type.toLowerCase()) {
231                 BluePrintConstants.DATA_TYPE_LIST -> jsonNode.isArray
232                 else -> false
233             }
234         }
235
236         fun getValue(value: JsonNode): Any {
237             return when (value) {
238                 is BooleanNode -> value.booleanValue()
239                 is IntNode -> value.intValue()
240                 is FloatNode -> value.floatValue()
241                 is DoubleNode -> value.doubleValue()
242                 is TextNode -> value.textValue()
243                 else -> value
244             }
245         }
246
247         fun getValue(value: Any, type: String): Any {
248             return when (type.toLowerCase()) {
249                 BluePrintConstants.DATA_TYPE_BOOLEAN -> (value as BooleanNode).booleanValue()
250                 BluePrintConstants.DATA_TYPE_INTEGER -> (value as IntNode).intValue()
251                 BluePrintConstants.DATA_TYPE_FLOAT -> (value as FloatNode).floatValue()
252                 BluePrintConstants.DATA_TYPE_DOUBLE -> (value as DoubleNode).doubleValue()
253                 BluePrintConstants.DATA_TYPE_STRING -> (value as TextNode).textValue()
254                 else -> (value as JsonNode)
255             }
256         }
257
258         fun populatePrimitiveValues(key: String, value: JsonNode, primitiveType: String, objectNode: ObjectNode) {
259             when (primitiveType.toLowerCase()) {
260                 BluePrintConstants.DATA_TYPE_BOOLEAN,
261                 BluePrintConstants.DATA_TYPE_INTEGER,
262                 BluePrintConstants.DATA_TYPE_FLOAT,
263                 BluePrintConstants.DATA_TYPE_DOUBLE,
264                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
265                 BluePrintConstants.DATA_TYPE_STRING,
266                 BluePrintConstants.DATA_TYPE_NULL ->
267                     objectNode.set(key, value)
268                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
269             }
270         }
271
272         fun populatePrimitiveValues(value: JsonNode, primitiveType: String, arrayNode: ArrayNode) {
273             when (primitiveType.toLowerCase()) {
274                 BluePrintConstants.DATA_TYPE_BOOLEAN,
275                 BluePrintConstants.DATA_TYPE_INTEGER,
276                 BluePrintConstants.DATA_TYPE_FLOAT,
277                 BluePrintConstants.DATA_TYPE_DOUBLE,
278                 BluePrintConstants.DATA_TYPE_TIMESTAMP,
279                 BluePrintConstants.DATA_TYPE_STRING,
280                 BluePrintConstants.DATA_TYPE_NULL ->
281                     arrayNode.add(value)
282                 else -> throw BluePrintException("populatePrimitiveValues expected only primitive values! Received: ($value)")
283             }
284         }
285
286         fun populatePrimitiveDefaultValues(key: String, primitiveType: String, objectNode: ObjectNode) {
287             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
288                 ?: throw BluePrintException("populatePrimitiveDefaultValues expected only primitive values! Received type ($primitiveType)")
289             objectNode.set<JsonNode>(key, defaultValue)
290         }
291
292         fun populatePrimitiveDefaultValuesForArrayNode(primitiveType: String, arrayNode: ArrayNode) {
293             val defaultValue = getDefaultValueOfPrimitiveAsJsonNode(primitiveType)
294                 ?: throw BluePrintException("populatePrimitiveDefaultValuesForArrayNode expected only primitive values! Received type ($primitiveType)")
295             arrayNode.add(defaultValue)
296         }
297
298         private fun getDefaultValueOfPrimitiveAsJsonNode(primitiveType: String): JsonNode? {
299             return when (primitiveType.toLowerCase()) {
300                 BluePrintConstants.DATA_TYPE_BOOLEAN -> BooleanNode.valueOf(false)
301                 BluePrintConstants.DATA_TYPE_INTEGER -> IntNode.valueOf(0)
302                 BluePrintConstants.DATA_TYPE_FLOAT -> FloatNode.valueOf(0.0f)
303                 BluePrintConstants.DATA_TYPE_DOUBLE -> DoubleNode.valueOf(0.0)
304                 BluePrintConstants.DATA_TYPE_STRING -> MissingNode.getInstance()
305                 else -> null
306             }
307         }
308
309         fun populateJsonNodeValues(key: String, nodeValue: JsonNode?, type: String, objectNode: ObjectNode) {
310             if (nodeValue == null || nodeValue is NullNode) {
311                 objectNode.set<JsonNode>(key, nodeValue)
312             } else if (BluePrintTypes.validPrimitiveTypes().contains(type)) {
313                 populatePrimitiveValues(key, nodeValue, type, objectNode)
314             } else {
315                 objectNode.set<JsonNode>(key, nodeValue)
316             }
317         }
318
319         fun convertPrimitiveResourceValue(type: String, value: String): JsonNode {
320             return when (type.toLowerCase()) {
321                 BluePrintConstants.DATA_TYPE_BOOLEAN -> jsonNodeFromObject(value.toBoolean())
322                 BluePrintConstants.DATA_TYPE_INTEGER -> jsonNodeFromObject(value.toInt())
323                 BluePrintConstants.DATA_TYPE_FLOAT -> jsonNodeFromObject(value.toFloat())
324                 BluePrintConstants.DATA_TYPE_DOUBLE -> jsonNodeFromObject(value.toDouble())
325                 BluePrintConstants.DATA_TYPE_STRING -> jsonNodeFromObject(value)
326                 else -> getJsonNode(value)
327             }
328         }
329     }
330 }