Renaming Files having BluePrint to have Blueprint
[ccsdk/cds.git] / ms / blueprintsprocessor / modules / blueprints / blueprint-core / src / main / kotlin / org / onap / ccsdk / cds / controllerblueprints / core / CustomFunctions.kt
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 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
18 package org.onap.ccsdk.cds.controllerblueprints.core
19
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.fasterxml.jackson.databind.node.ArrayNode
22 import com.fasterxml.jackson.databind.node.BooleanNode
23 import com.fasterxml.jackson.databind.node.DoubleNode
24 import com.fasterxml.jackson.databind.node.IntNode
25 import com.fasterxml.jackson.databind.node.MissingNode
26 import com.fasterxml.jackson.databind.node.NullNode
27 import com.fasterxml.jackson.databind.node.ObjectNode
28 import com.fasterxml.jackson.databind.node.TextNode
29 import org.apache.commons.lang3.ObjectUtils
30 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
31 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JsonParserUtils
32 import org.slf4j.LoggerFactory
33 import org.slf4j.helpers.MessageFormatter
34 import java.util.UUID
35 import kotlin.reflect.KClass
36
37 /**
38  *
39  *
40  * @author Brinda Santh
41  */
42
43 fun <T : Any> logger(clazz: T) = LoggerFactory.getLogger(clazz.javaClass)!!
44
45 fun <T : KClass<*>> logger(clazz: T) = LoggerFactory.getLogger(clazz.java)!!
46
47 fun <T : Any> T?.defaultToEmpty(): String {
48     return this?.toString() ?: ""
49 }
50
51 fun <T : Any> T?.defaultToUUID(): String {
52     return this?.toString() ?: UUID.randomUUID().toString()
53 }
54
55 fun <T : Any> T.bpClone(): T {
56     return ObjectUtils.clone(this)
57 }
58
59 fun String.splitCommaAsList(): List<String> {
60     return this.split(",").map { it.trim() }.toList()
61 }
62
63 fun String.isJson(): Boolean {
64     return (
65         (this.trim().startsWith("{") && this.trim().endsWith("}")) ||
66             (this.trim().startsWith("[") && this.trim().endsWith("]"))
67         )
68 }
69
70 fun Any.asJsonString(intend: Boolean? = false): String {
71     return JacksonUtils.getJson(this, intend!!)
72 }
73
74 fun String.asJsonPrimitive(): TextNode {
75     return TextNode(this)
76 }
77
78 inline fun <reified T : Any> String.jsonAsType(): T {
79     return JacksonUtils.readValue<T>(this.trim())
80 }
81
82 // If you know the string is json content, then use the function directly
83 fun String.jsonAsJsonType(): JsonNode {
84     return JacksonUtils.jsonNode(this.trim())
85 }
86
87 fun Boolean.asJsonPrimitive(): BooleanNode {
88     return BooleanNode.valueOf(this)
89 }
90
91 fun Int.asJsonPrimitive(): IntNode {
92     return IntNode.valueOf(this)
93 }
94
95 fun Double.asJsonPrimitive(): DoubleNode {
96     return DoubleNode.valueOf(this)
97 }
98
99 /**
100  * Utility to convert Primitive object to Json Type Primitive.
101  */
102 fun <T : Any?> T.asJsonPrimitive(): JsonNode {
103     return if (this == null || this is MissingNode || this is NullNode) {
104         NullNode.instance
105     } else {
106         when (this) {
107             is String ->
108                 this.asJsonPrimitive()
109             is Boolean ->
110                 this.asJsonPrimitive()
111             is Int ->
112                 this.asJsonPrimitive()
113             is Double ->
114                 this.asJsonPrimitive()
115             else ->
116                 throw BlueprintException("$this type is not supported")
117         }
118     }
119 }
120
121 /** Based on Blueprint DataType Convert string value to JsonNode Type **/
122 fun String.asJsonType(bpDataType: String): JsonNode {
123     return when (bpDataType.toLowerCase()) {
124         BlueprintConstants.DATA_TYPE_STRING -> this.asJsonPrimitive()
125         BlueprintConstants.DATA_TYPE_BOOLEAN -> this.toBoolean().asJsonPrimitive()
126         BlueprintConstants.DATA_TYPE_INTEGER -> this.toInt().asJsonPrimitive()
127         BlueprintConstants.DATA_TYPE_FLOAT -> this.toFloat().asJsonPrimitive()
128         BlueprintConstants.DATA_TYPE_DOUBLE -> this.toDouble().asJsonPrimitive()
129         // For List, Map and Complex Types.
130         else -> this.jsonAsJsonType()
131     }
132 }
133
134 /**
135  * Utility to convert Complex or Primitive object or ByteArray to Json Type.
136  */
137 fun <T : Any?> T.asJsonType(): JsonNode {
138     return if (this == null || this is MissingNode || this is NullNode) {
139         NullNode.instance
140     } else {
141         when (this) {
142             is JsonNode -> this
143             is ByteArray -> JacksonUtils.objectMapper.reader().readTree(this.inputStream())
144             is String -> {
145                 if (this.isJson())
146                     this.jsonAsJsonType()
147                 else
148                     TextNode(this)
149             }
150             is Boolean -> BooleanNode.valueOf(this)
151             is Int -> IntNode.valueOf(this.toInt())
152             is Double -> DoubleNode.valueOf(this.toDouble())
153             else -> JacksonUtils.jsonNodeFromObject(this)
154         }
155     }
156 }
157
158 fun Map<String, *>.asJsonNode(): JsonNode {
159     return JacksonUtils.jsonNodeFromObject(this)
160 }
161
162 fun Map<String, *>.asObjectNode(): ObjectNode {
163     return JacksonUtils.objectNodeFromObject(this)
164 }
165
166 fun format(message: String, vararg args: Any?): String {
167     if (args != null && args.isNotEmpty()) {
168         return MessageFormatter.arrayFormat(message, args).message
169     }
170     return message
171 }
172
173 fun <T : Any> Map<String, *>.castOptionalValue(key: String, valueType: KClass<T>): T? {
174     return if (containsKey(key)) {
175         get(key) as? T
176     } else {
177         null
178     }
179 }
180
181 fun <T : Any> Map<String, *>.castValue(key: String, valueType: KClass<T>): T {
182     if (containsKey(key)) {
183         return get(key) as T
184     } else {
185         throw BlueprintException("couldn't find the key $key")
186     }
187 }
188
189 fun ArrayNode.asListOfString(): List<String> {
190     return JacksonUtils.getListFromJsonNode(this, String::class.java)
191 }
192
193 fun JsonNode.asByteArray(): ByteArray {
194     val writer = JacksonUtils.objectMapper.writer()
195     return writer.writeValueAsBytes(this)
196 }
197
198 fun <T> JsonNode.asType(clazzType: Class<T>): T {
199     return JacksonUtils.readValue(this, clazzType)
200         ?: throw BlueprintException("couldn't convert JsonNode of type $clazzType")
201 }
202
203 fun JsonNode.asListOfString(): List<String> {
204     check(this is ArrayNode) { "JsonNode is not of type ArrayNode" }
205     return this.asListOfString()
206 }
207
208 fun <T : JsonNode> T?.returnNullIfMissing(): JsonNode? {
209     return if (this == null || this is NullNode || this is MissingNode) {
210         null
211     } else this
212 }
213
214 fun <T : JsonNode> T?.isNullOrMissing(): Boolean {
215     return this == null || this is NullNode || this is MissingNode
216 }
217
218 /**
219  * Convert Json to map of json node, the root fields will be map keys
220  */
221 fun JsonNode.rootFieldsToMap(): MutableMap<String, JsonNode> {
222     if (this is ObjectNode) {
223         val propertyMap: MutableMap<String, JsonNode> = linkedMapOf()
224         this.fields().forEach {
225             propertyMap[it.key] = it.value
226         }
227         return propertyMap
228     } else {
229         throw BlueprintException("json node should be Object Node Type")
230     }
231 }
232
233 fun JsonNode.removeNullNode() {
234     val it = this.iterator()
235     while (it.hasNext()) {
236         val child = it.next()
237         if (child.isNull) {
238             it.remove()
239         } else {
240             child.removeNullNode()
241         }
242     }
243 }
244
245 fun MutableMap<String, JsonNode>.putJsonElement(key: String, value: Any) {
246     val convertedValue = value.asJsonType()
247     this[key] = convertedValue
248 }
249
250 fun Map<String, JsonNode>.getAsString(key: String): String {
251     return this[key]?.asText() ?: throw BlueprintException("couldn't find value for key($key)")
252 }
253
254 fun Map<String, JsonNode>.getAsBoolean(key: String): Boolean {
255     return this[key]?.asBoolean() ?: throw BlueprintException("couldn't find value for key($key)")
256 }
257
258 fun Map<String, JsonNode>.getAsInt(key: String): Int {
259     return this[key]?.asInt() ?: throw BlueprintException("couldn't find value for key($key)")
260 }
261
262 fun Map<String, JsonNode>.getAsDouble(key: String): Double {
263     return this[key]?.asDouble() ?: throw BlueprintException("couldn't find value for key($key)")
264 }
265
266 fun Map<String, JsonNode>.getOptionalAsString(key: String): String? {
267     return if (this.containsKey(key)) this[key]!!.asText() else null
268 }
269
270 fun Map<String, JsonNode>.getOptionalAsBoolean(key: String): Boolean? {
271     return if (this.containsKey(key)) this[key]!!.asBoolean() else null
272 }
273
274 fun Map<String, JsonNode>.getOptionalAsInt(key: String): Int? {
275     return if (this.containsKey(key)) this[key]!!.asInt() else null
276 }
277
278 fun Map<String, JsonNode>.getOptionalAsDouble(key: String): Double? {
279     return if (this.containsKey(key)) this[key]!!.asDouble() else null
280 }
281
282 // Checks
283
284 inline fun checkEquals(value1: String?, value2: String?, lazyMessage: () -> Any): Boolean {
285     if (value1.equals(value2, ignoreCase = true)) {
286         return true
287     } else {
288         throw BlueprintException(lazyMessage().toString())
289     }
290 }
291
292 inline fun checkNotEmpty(value: String?, lazyMessage: () -> Any): String {
293     if (value == null || value.isEmpty()) {
294         val message = lazyMessage()
295         throw IllegalStateException(message.toString())
296     } else {
297         return value
298     }
299 }
300
301 inline fun checkNotBlank(value: String?, lazyMessage: () -> Any): String {
302     if (value == null || value.isBlank()) {
303         val message = lazyMessage()
304         throw IllegalStateException(message.toString())
305     } else {
306         return value
307     }
308 }
309
310 fun isNotEmpty(value: String?): Boolean {
311     return value != null && value.isNotEmpty()
312 }
313
314 fun isNotBlank(value: String?): Boolean {
315     return value != null && value.isNotBlank()
316 }
317
318 fun <T : String> T?.emptyTONull(): String? {
319     return if (this == null || this.isEmpty()) null else this
320 }
321
322 fun nullToEmpty(value: String?): String {
323     return if (isNotEmpty(value)) value!! else ""
324 }
325
326 inline fun <reified T : JsonNode> T.isComplexType(): Boolean {
327     return this is ObjectNode || this is ArrayNode
328 }
329
330 // Json Parsing Extensions
331 fun JsonNode.jsonPathParse(expression: String): JsonNode {
332     check(this.isComplexType()) { "$this is not complex or array node to apply expression" }
333     return JsonParserUtils.parse(this, expression)
334 }
335
336 // Json Path Extensions
337 fun JsonNode.jsonPaths(expression: String): List<String> {
338     check(this.isComplexType()) { "$this is not complex or array node to apply expression" }
339     return JsonParserUtils.paths(this, expression)
340 }