Refractor controller blueprint modules
[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.isJson(): Boolean {
60     return ((this.trim().startsWith("{") && this.trim().endsWith("}")) ||
61             (this.trim().startsWith("[") && this.trim().endsWith("]")))
62 }
63
64 fun Any.asJsonString(intend: Boolean? = false): String {
65     return JacksonUtils.getJson(this, intend!!)
66 }
67
68 fun String.asJsonPrimitive(): TextNode {
69     return TextNode(this)
70 }
71
72 inline fun <reified T : Any> String.jsonAsType(): T {
73     return JacksonUtils.readValue<T>(this.trim())
74 }
75
76 // If you know the string is json content, then use the function directly
77 fun String.jsonAsJsonType(): JsonNode {
78     return JacksonUtils.jsonNode(this.trim())
79 }
80
81 fun Boolean.asJsonPrimitive(): BooleanNode {
82     return BooleanNode.valueOf(this)
83 }
84
85 fun Int.asJsonPrimitive(): IntNode {
86     return IntNode.valueOf(this)
87 }
88
89 fun Double.asJsonPrimitive(): DoubleNode {
90     return DoubleNode.valueOf(this)
91 }
92
93 /**
94  * Utility to convert Primitive object to Json Type Primitive.
95  */
96 fun <T : Any?> T.asJsonPrimitive(): JsonNode {
97     return if (this == null || this is MissingNode || this is NullNode) {
98         NullNode.instance
99     } else {
100         when (this) {
101             is String ->
102                 this.asJsonPrimitive()
103             is Boolean ->
104                 this.asJsonPrimitive()
105             is Int ->
106                 this.asJsonPrimitive()
107             is Double ->
108                 this.asJsonPrimitive()
109             else ->
110                 throw BluePrintException("$this type is not supported")
111         }
112     }
113 }
114
115 /** Based on Blueprint DataType Convert string value to JsonNode Type **/
116 fun String.asJsonType(bpDataType: String): JsonNode {
117     return when (bpDataType.toLowerCase()) {
118         BluePrintConstants.DATA_TYPE_STRING -> this.asJsonPrimitive()
119         BluePrintConstants.DATA_TYPE_BOOLEAN -> this.toBoolean().asJsonPrimitive()
120         BluePrintConstants.DATA_TYPE_INTEGER -> this.toInt().asJsonPrimitive()
121         BluePrintConstants.DATA_TYPE_FLOAT -> this.toFloat().asJsonPrimitive()
122         BluePrintConstants.DATA_TYPE_DOUBLE -> this.toDouble().asJsonPrimitive()
123         // For List, Map and Complex Types.
124         else -> this.jsonAsJsonType()
125     }
126 }
127
128 /**
129  * Utility to convert Complex or Primitive object to Json Type.
130  */
131 fun <T : Any?> T.asJsonType(): JsonNode {
132     return if (this == null || this is MissingNode || this is NullNode) {
133         NullNode.instance
134     } else {
135         when (this) {
136             is JsonNode ->
137                 this
138             is String -> {
139                 if (this.isJson())
140                     this.jsonAsJsonType()
141                 else
142                     TextNode(this)
143             }
144             is Boolean ->
145                 BooleanNode.valueOf(this)
146             is Int ->
147                 IntNode.valueOf(this.toInt())
148             is Double ->
149                 DoubleNode.valueOf(this.toDouble())
150             else ->
151                 JacksonUtils.jsonNodeFromObject(this)
152         }
153     }
154 }
155
156 fun Map<String, *>.asJsonNode(): JsonNode {
157     return JacksonUtils.jsonNodeFromObject(this)
158 }
159
160 fun Map<String, *>.asObjectNode(): ObjectNode {
161     return JacksonUtils.objectNodeFromObject(this)
162 }
163
164 fun format(message: String, vararg args: Any?): String {
165     if (args != null && args.isNotEmpty()) {
166         return MessageFormatter.arrayFormat(message, args).message
167     }
168     return message
169 }
170
171 fun <T : Any> Map<String, *>.castOptionalValue(key: String, valueType: KClass<T>): T? {
172     return if (containsKey(key)) {
173         get(key) as? T
174     } else {
175         null
176     }
177 }
178
179 fun <T : Any> Map<String, *>.castValue(key: String, valueType: KClass<T>): T {
180     if (containsKey(key)) {
181         return get(key) as T
182     } else {
183         throw BluePrintException("couldn't find the key $key")
184     }
185 }
186
187 fun ArrayNode.asListOfString(): List<String> {
188     return JacksonUtils.getListFromJsonNode(this, String::class.java)
189 }
190
191 fun <T> JsonNode.asType(clazzType: Class<T>): T {
192     return JacksonUtils.readValue(this, clazzType)
193         ?: throw BluePrintException("couldn't convert JsonNode of type $clazzType")
194 }
195
196 fun JsonNode.asListOfString(): List<String> {
197     check(this is ArrayNode) { "JsonNode is not of type ArrayNode" }
198     return this.asListOfString()
199 }
200
201 fun <T : JsonNode> T?.returnNullIfMissing(): JsonNode? {
202     return if (this == null || this is NullNode || this is MissingNode) {
203         null
204     } else this
205 }
206
207 fun <T : JsonNode> T?.isNullOrMissing(): Boolean {
208     return this == null || this is NullNode || this is MissingNode
209 }
210
211 /**
212  * Convert Json to map of json node, the root fields will be map keys
213  */
214 fun JsonNode.rootFieldsToMap(): MutableMap<String, JsonNode> {
215     if (this is ObjectNode) {
216         val propertyMap: MutableMap<String, JsonNode> = linkedMapOf()
217         this.fields().forEach {
218             propertyMap[it.key] = it.value
219         }
220         return propertyMap
221     } else {
222         throw BluePrintException("json node should be Object Node Type")
223     }
224 }
225
226 fun JsonNode.removeNullNode() {
227     val it = this.iterator()
228     while (it.hasNext()) {
229         val child = it.next()
230         if (child.isNull) {
231             it.remove()
232         } else {
233             child.removeNullNode()
234         }
235     }
236 }
237
238 fun MutableMap<String, JsonNode>.putJsonElement(key: String, value: Any) {
239     val convertedValue = value.asJsonType()
240     this[key] = convertedValue
241 }
242
243 fun Map<String, JsonNode>.getAsString(key: String): String {
244     return this[key]?.asText() ?: throw BluePrintException("couldn't find value for key($key)")
245 }
246
247 fun Map<String, JsonNode>.getAsBoolean(key: String): Boolean {
248     return this[key]?.asBoolean() ?: throw BluePrintException("couldn't find value for key($key)")
249 }
250
251 fun Map<String, JsonNode>.getAsInt(key: String): Int {
252     return this[key]?.asInt() ?: throw BluePrintException("couldn't find value for key($key)")
253 }
254
255 fun Map<String, JsonNode>.getAsDouble(key: String): Double {
256     return this[key]?.asDouble() ?: throw BluePrintException("couldn't find value for key($key)")
257 }
258
259 fun Map<String, JsonNode>.getOptionalAsString(key: String): String? {
260     return if (this.containsKey(key)) this[key]!!.asText() else null
261 }
262
263 fun Map<String, JsonNode>.getOptionalAsBoolean(key: String): Boolean? {
264     return if (this.containsKey(key)) this[key]!!.asBoolean() else null
265 }
266
267 fun Map<String, JsonNode>.getOptionalAsInt(key: String): Int? {
268     return if (this.containsKey(key)) this[key]!!.asInt() else null
269 }
270
271 fun Map<String, JsonNode>.getOptionalAsDouble(key: String): Double? {
272     return if (this.containsKey(key)) this[key]!!.asDouble() else null
273 }
274
275 // Checks
276
277 inline fun checkEquals(value1: String?, value2: String?, lazyMessage: () -> Any): Boolean {
278     if (value1.equals(value2, ignoreCase = true)) {
279         return true
280     } else {
281         throw BluePrintException(lazyMessage().toString())
282     }
283 }
284
285 inline fun checkNotEmpty(value: String?, lazyMessage: () -> Any): String {
286     if (value == null || value.isEmpty()) {
287         val message = lazyMessage()
288         throw IllegalStateException(message.toString())
289     } else {
290         return value
291     }
292 }
293
294 inline fun checkNotBlank(value: String?, lazyMessage: () -> Any): String {
295     if (value == null || value.isBlank()) {
296         val message = lazyMessage()
297         throw IllegalStateException(message.toString())
298     } else {
299         return value
300     }
301 }
302
303 fun isNotEmpty(value: String?): Boolean {
304     return value != null && value.isNotEmpty()
305 }
306
307 fun isNotBlank(value: String?): Boolean {
308     return value != null && value.isNotBlank()
309 }
310
311 fun <T : String> T?.emptyTONull(): String? {
312     return if (this == null || this.isEmpty()) null else this
313 }
314
315 fun nullToEmpty(value: String?): String {
316     return if (isNotEmpty(value)) value!! else ""
317 }
318
319 inline fun <reified T : JsonNode> T.isComplexType(): Boolean {
320     return this is ObjectNode || this is ArrayNode
321 }
322
323 // Json Parsing Extensions
324 fun JsonNode.jsonPathParse(expression: String): JsonNode {
325     check(this.isComplexType()) { "$this is not complex or array node to apply expression" }
326     return JsonParserUtils.parse(this, expression)
327 }
328
329 // Json Path Extensions
330 fun JsonNode.jsonPaths(expression: String): List<String> {
331     check(this.isComplexType()) { "$this is not complex or array node to apply expression" }
332     return JsonParserUtils.paths(this, expression)
333 }