5c10f80c9b91acd132da45748aa6b04eb08d872f
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright © 2018 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.apps.controllerblueprints.core.service
19
20
21 import com.att.eelf.configuration.EELFLogger
22 import com.att.eelf.configuration.EELFManager
23 import com.fasterxml.jackson.databind.JsonNode
24 import com.fasterxml.jackson.databind.node.NullNode
25 import com.fasterxml.jackson.databind.node.ObjectNode
26 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
27 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintConstants
28 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintError
29 import org.onap.ccsdk.apps.controllerblueprints.core.BluePrintProcessorException
30 import org.onap.ccsdk.apps.controllerblueprints.core.data.ArtifactDefinition
31 import org.onap.ccsdk.apps.controllerblueprints.core.data.NodeTemplate
32 import org.onap.ccsdk.apps.controllerblueprints.core.data.PropertyDefinition
33 import org.onap.ccsdk.apps.controllerblueprints.core.utils.JacksonUtils
34
35 interface BluePrintRuntimeService<T> {
36
37     fun id(): String
38
39     fun bluePrintContext(): BluePrintContext
40
41     fun getExecutionContext(): T
42
43     fun setExecutionContext(executionContext: T)
44
45     fun put(key: String, value: JsonNode)
46
47     fun get(key: String): JsonNode?
48
49     fun check(key: String): Boolean
50
51     fun cleanRuntime()
52
53     fun getAsString(key: String): String?
54
55     fun getAsBoolean(key: String): Boolean?
56
57     fun getAsInt(key: String): Int?
58
59     fun getAsDouble(key: String): Double?
60
61     fun getBluePrintError(): BluePrintError
62
63     fun setBluePrintError(bluePrintError: BluePrintError)
64
65     fun resolveNodeTemplatePropertyAssignments(nodeTemplateName: String,
66                                                propertyDefinitions: MutableMap<String, PropertyDefinition>,
67                                                propertyAssignments: MutableMap<String, JsonNode>): MutableMap<String, JsonNode>
68
69     fun resolveNodeTemplateProperties(nodeTemplateName: String): MutableMap<String, JsonNode>
70
71     fun resolveNodeTemplateCapabilityProperties(nodeTemplateName: String, capabilityName: String): MutableMap<String,
72             JsonNode>
73
74     fun resolveNodeTemplateInterfaceOperationInputs(nodeTemplateName: String, interfaceName: String,
75                                                     operationName: String): MutableMap<String, JsonNode>
76
77     fun resolveNodeTemplateInterfaceOperationOutputs(nodeTemplateName: String, interfaceName: String,
78                                                      operationName: String): MutableMap<String, JsonNode>
79
80     fun resolveNodeTemplateArtifact(nodeTemplateName: String, artifactName: String): String
81
82     fun resolveNodeTemplateArtifactDefinition(nodeTemplateName: String, artifactName: String): ArtifactDefinition
83
84     fun setInputValue(propertyName: String, propertyDefinition: PropertyDefinition, value: JsonNode)
85
86     fun setWorkflowInputValue(workflowName: String, propertyName: String, propertyDefinition: PropertyDefinition, value: JsonNode)
87
88     fun setNodeTemplatePropertyValue(nodeTemplateName: String, propertyName: String, value: JsonNode)
89
90     fun setNodeTemplateAttributeValue(nodeTemplateName: String, attributeName: String, value: JsonNode)
91
92     fun setNodeTemplateOperationPropertyValue(nodeTemplateName: String, interfaceName: String,
93                                               operationName: String, propertyName: String, value: JsonNode)
94
95     fun setNodeTemplateOperationInputValue(nodeTemplateName: String, interfaceName: String,
96                                            operationName: String, propertyName: String, value: JsonNode)
97
98     fun setNodeTemplateOperationOutputValue(nodeTemplateName: String, interfaceName: String,
99                                             operationName: String, propertyName: String, value: JsonNode)
100
101     fun getInputValue(propertyName: String): JsonNode
102
103     fun getNodeTemplateOperationOutputValue(nodeTemplateName: String, interfaceName: String,
104                                             operationName: String, propertyName: String): JsonNode
105
106     fun getNodeTemplatePropertyValue(nodeTemplateName: String, propertyName: String): JsonNode?
107
108     fun getNodeTemplateAttributeValue(nodeTemplateName: String, attributeName: String): JsonNode?
109
110     fun assignInputs(jsonNode: JsonNode)
111
112     fun assignWorkflowInputs(workflowName: String, jsonNode: JsonNode)
113
114     fun getJsonForNodeTemplateAttributeProperties(nodeTemplateName: String, keys: List<String>): JsonNode
115 }
116
117 /**
118  *
119  *
120  * @author Brinda Santh
121  */
122 open class DefaultBluePrintRuntimeService(private var id: String, private var bluePrintContext: BluePrintContext)
123     : BluePrintRuntimeService<MutableMap<String, JsonNode>> {
124
125     @Transient
126     private val log: EELFLogger = EELFManager.getInstance().getLogger(BluePrintRuntimeService::class.toString())
127
128     private var store: MutableMap<String, JsonNode> = hashMapOf()
129
130     private var bluePrintError = BluePrintError()
131
132     override fun id(): String {
133         return id
134     }
135
136     override fun bluePrintContext(): BluePrintContext {
137         return bluePrintContext
138     }
139
140     override fun getExecutionContext(): MutableMap<String, JsonNode> {
141         return store
142     }
143
144     @Suppress("UNCHECKED_CAST")
145     override fun setExecutionContext(executionContext: MutableMap<String, JsonNode>) {
146         this.store = executionContext
147     }
148
149     override fun put(key: String, value: JsonNode) {
150         store[key] = value
151     }
152
153     override fun get(key: String): JsonNode {
154         return store[key] ?: throw BluePrintProcessorException("failed to get execution property($key)")
155     }
156
157     override fun check(key: String): Boolean {
158         return store.containsKey(key)
159     }
160
161     override fun cleanRuntime() {
162         store.clear()
163     }
164
165     private fun getJsonNode(key: String): JsonNode {
166         return get(key)
167     }
168
169     override fun getAsString(key: String): String? {
170         return get(key).asText()
171     }
172
173     override fun getAsBoolean(key: String): Boolean? {
174         return get(key).asBoolean()
175     }
176
177     override fun getAsInt(key: String): Int? {
178         return get(key).asInt()
179     }
180
181     override fun getAsDouble(key: String): Double? {
182         return get(key).asDouble()
183     }
184
185     override fun getBluePrintError(): BluePrintError {
186         return this.bluePrintError
187     }
188
189     override fun setBluePrintError(bluePrintError: BluePrintError) {
190         this.bluePrintError = bluePrintError
191     }
192
193     /**
194      * Resolve any property assignments for the node
195      */
196     override fun resolveNodeTemplatePropertyAssignments(nodeTemplateName: String,
197                                                         propertyDefinitions: MutableMap<String, PropertyDefinition>,
198                                                         propertyAssignments: MutableMap<String, JsonNode>)
199             : MutableMap<String, JsonNode> {
200
201         val propertyAssignmentValue: MutableMap<String, JsonNode> = hashMapOf()
202
203         propertyDefinitions.forEach { nodeTypePropertyName, nodeTypeProperty ->
204             // Get the Express or Value for the Node Template
205             val propertyAssignment: JsonNode? = propertyAssignments[nodeTypePropertyName]
206
207             var resolvedValue: JsonNode = NullNode.getInstance()
208             if (propertyAssignment != null) {
209                 // Resolve the Expressing
210                 val propertyAssignmentExpression = PropertyAssignmentService(this)
211                 resolvedValue = propertyAssignmentExpression.resolveAssignmentExpression(nodeTemplateName,
212                         nodeTypePropertyName, propertyAssignment)
213             } else {
214                 // Assign default value to the Operation
215                 nodeTypeProperty.defaultValue?.let {
216                     resolvedValue = JacksonUtils.jsonNodeFromObject(nodeTypeProperty.defaultValue!!)
217                 }
218             }
219             // Set for Return of method
220             propertyAssignmentValue[nodeTypePropertyName] = resolvedValue
221         }
222         return propertyAssignmentValue
223     }
224
225     override fun resolveNodeTemplateProperties(nodeTemplateName: String): MutableMap<String, JsonNode> {
226         log.info("resolveNodeTemplatePropertyValues for node template ({})", nodeTemplateName)
227
228         val nodeTemplate: NodeTemplate = bluePrintContext.nodeTemplateByName(nodeTemplateName)
229
230         val propertyAssignments: MutableMap<String, JsonNode> = nodeTemplate.properties!!
231
232         // Get the Node Type Definitions
233         val nodeTypePropertieDefinitions: MutableMap<String, PropertyDefinition> = bluePrintContext
234                 .nodeTypeChainedProperties(nodeTemplate.type)!!
235
236         /**
237          * Resolve the NodeTemplate Property Assignment Values.
238          */
239         return resolveNodeTemplatePropertyAssignments(nodeTemplateName, nodeTypePropertieDefinitions,
240                 propertyAssignments)
241     }
242
243     override fun resolveNodeTemplateCapabilityProperties(nodeTemplateName: String, capabilityName: String):
244             MutableMap<String, JsonNode> {
245         log.info("resolveNodeTemplateCapabilityProperties for node template($nodeTemplateName) capability " +
246                 "($capabilityName)")
247         val nodeTemplate: NodeTemplate = bluePrintContext.nodeTemplateByName(nodeTemplateName)
248
249         val propertyAssignments = nodeTemplate.capabilities?.get(capabilityName)?.properties ?: hashMapOf()
250
251         val propertyDefinitions = bluePrintContext.nodeTemplateNodeType(nodeTemplateName)
252                 .capabilities?.get(capabilityName)?.properties ?: hashMapOf()
253
254         /**
255          * Resolve the Capability Property Assignment Values.
256          */
257         return resolveNodeTemplatePropertyAssignments(nodeTemplateName, propertyDefinitions,
258                 propertyAssignments)
259     }
260
261     override fun resolveNodeTemplateInterfaceOperationInputs(nodeTemplateName: String,
262                                                              interfaceName: String,
263                                                              operationName: String): MutableMap<String, JsonNode> {
264         log.info("resolveNodeTemplateInterfaceOperationInputs for node template ($nodeTemplateName),interface name " +
265                 "($interfaceName), operationName($operationName)")
266
267         val propertyAssignments: MutableMap<String, JsonNode> =
268                 bluePrintContext.nodeTemplateInterfaceOperationInputs(nodeTemplateName, interfaceName, operationName)
269                         ?: hashMapOf()
270
271         val nodeTypeName = bluePrintContext.nodeTemplateByName(nodeTemplateName).type
272
273         val nodeTypeInterfaceOperationInputs: MutableMap<String, PropertyDefinition> =
274                 bluePrintContext.nodeTypeInterfaceOperationInputs(nodeTypeName, interfaceName, operationName)
275                         ?: hashMapOf()
276
277         log.info("input definition for node template ($nodeTemplateName), values ($propertyAssignments)")
278
279         /**
280          * Resolve the Property Input Assignment Values.
281          */
282         return resolveNodeTemplatePropertyAssignments(nodeTemplateName, nodeTypeInterfaceOperationInputs,
283                 propertyAssignments)
284
285     }
286
287
288     override fun resolveNodeTemplateInterfaceOperationOutputs(nodeTemplateName: String,
289                                                               interfaceName: String,
290                                                               operationName: String): MutableMap<String, JsonNode> {
291         log.info("resolveNodeTemplateInterfaceOperationOutputs for node template ($nodeTemplateName),interface name " +
292                 "($interfaceName), operationName($operationName)")
293
294         val propertyAssignments: MutableMap<String, JsonNode> =
295                 bluePrintContext.nodeTemplateInterfaceOperationOutputs(nodeTemplateName, interfaceName, operationName)
296                         ?: hashMapOf()
297
298         val nodeTypeName = bluePrintContext.nodeTemplateByName(nodeTemplateName).type
299
300         val nodeTypeInterfaceOperationOutputs: MutableMap<String, PropertyDefinition> =
301                 bluePrintContext.nodeTypeInterfaceOperationOutputs(nodeTypeName, interfaceName, operationName)
302                         ?: hashMapOf()
303         /**
304          * Resolve the Property Output Assignment Values.
305          */
306         val propertyAssignmentValue = resolveNodeTemplatePropertyAssignments(nodeTemplateName,
307                 nodeTypeInterfaceOperationOutputs, propertyAssignments)
308
309         // Store  operation output values into context
310         propertyAssignmentValue.forEach { key, value ->
311             setNodeTemplateOperationOutputValue(nodeTemplateName, interfaceName, operationName, key, value)
312         }
313         return propertyAssignmentValue
314     }
315
316     override fun resolveNodeTemplateArtifact(nodeTemplateName: String, artifactName: String): String {
317         val artifactDefinition: ArtifactDefinition = resolveNodeTemplateArtifactDefinition(nodeTemplateName, artifactName)
318         val propertyAssignmentExpression = PropertyAssignmentService(this)
319         return propertyAssignmentExpression.artifactContent(artifactDefinition)
320     }
321
322     override fun resolveNodeTemplateArtifactDefinition(nodeTemplateName: String, artifactName: String): ArtifactDefinition {
323         val nodeTemplate = bluePrintContext.nodeTemplateByName(nodeTemplateName)
324
325         return nodeTemplate.artifacts?.get(artifactName)
326                 ?: throw BluePrintProcessorException("failed to get artifat definition($artifactName) from the node " +
327                         "template")
328
329     }
330
331     override fun setInputValue(propertyName: String, propertyDefinition: PropertyDefinition, value: JsonNode) {
332         val path = StringBuilder(BluePrintConstants.PATH_INPUTS)
333                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
334         log.trace("setting input path ({}), values ({})", path, value)
335         put(path, value)
336     }
337
338     override fun setWorkflowInputValue(workflowName: String, propertyName: String,
339                                        propertyDefinition: PropertyDefinition, value: JsonNode) {
340         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_WORKFLOWS)
341                 .append(BluePrintConstants.PATH_DIVIDER).append(workflowName)
342                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INPUTS)
343                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
344                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
345         put(path, value)
346     }
347
348     override fun setNodeTemplatePropertyValue(nodeTemplateName: String, propertyName: String, value: JsonNode) {
349
350         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
351                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
352                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
353                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
354         put(path, value)
355     }
356
357     override fun setNodeTemplateAttributeValue(nodeTemplateName: String, attributeName: String, value: JsonNode) {
358
359         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
360                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
361                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_ATTRIBUTES)
362                 .append(BluePrintConstants.PATH_DIVIDER).append(attributeName).toString()
363         put(path, value)
364     }
365
366     override fun setNodeTemplateOperationPropertyValue(nodeTemplateName: String, interfaceName: String, operationName: String, propertyName: String,
367                                                        value: JsonNode) {
368         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
369                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
370                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INTERFACES)
371                 .append(BluePrintConstants.PATH_DIVIDER).append(interfaceName)
372                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OPERATIONS)
373                 .append(BluePrintConstants.PATH_DIVIDER).append(operationName)
374                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
375                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
376         log.trace("setting operation property path ({}), values ({})", path, value)
377         put(path, value)
378     }
379
380     override fun setNodeTemplateOperationInputValue(nodeTemplateName: String, interfaceName: String,
381                                                     operationName: String, propertyName: String,
382                                                     value: JsonNode) {
383         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
384                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
385                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INTERFACES)
386                 .append(BluePrintConstants.PATH_DIVIDER).append(interfaceName)
387                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OPERATIONS)
388                 .append(BluePrintConstants.PATH_DIVIDER).append(operationName)
389                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INPUTS)
390                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
391                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
392         put(path, value)
393     }
394
395     override fun setNodeTemplateOperationOutputValue(nodeTemplateName: String, interfaceName: String,
396                                                      operationName: String, propertyName: String,
397                                                      value: JsonNode) {
398         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
399                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
400                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INTERFACES)
401                 .append(BluePrintConstants.PATH_DIVIDER).append(interfaceName)
402                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OPERATIONS)
403                 .append(BluePrintConstants.PATH_DIVIDER).append(operationName)
404                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OUTPUTS)
405                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
406                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
407         put(path, value)
408     }
409
410
411     override fun getInputValue(propertyName: String): JsonNode {
412         val path = StringBuilder(BluePrintConstants.PATH_INPUTS)
413                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
414         return getJsonNode(path)
415     }
416
417     override fun getNodeTemplateOperationOutputValue(nodeTemplateName: String, interfaceName: String,
418                                                      operationName: String, propertyName: String): JsonNode {
419         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
420                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
421                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_INTERFACES)
422                 .append(BluePrintConstants.PATH_DIVIDER).append(interfaceName)
423                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OPERATIONS)
424                 .append(BluePrintConstants.PATH_DIVIDER).append(operationName)
425                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_OUTPUTS)
426                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
427                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
428         return getJsonNode(path)
429     }
430
431     override fun getNodeTemplatePropertyValue(nodeTemplateName: String, propertyName: String): JsonNode {
432         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
433                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
434                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_PROPERTIES)
435                 .append(BluePrintConstants.PATH_DIVIDER).append(propertyName).toString()
436         return getJsonNode(path)
437     }
438
439     override fun getNodeTemplateAttributeValue(nodeTemplateName: String, attributeName: String): JsonNode {
440         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
441                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
442                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_ATTRIBUTES)
443                 .append(BluePrintConstants.PATH_DIVIDER).append(attributeName).toString()
444         return getJsonNode(path)
445     }
446
447     override fun assignInputs(jsonNode: JsonNode) {
448         log.info("assignInputs from input JSON ({})", jsonNode.toString())
449         bluePrintContext.inputs?.forEach { propertyName, property ->
450             val valueNode: JsonNode = jsonNode.at(BluePrintConstants.PATH_DIVIDER + propertyName)
451                     ?: NullNode.getInstance()
452             setInputValue(propertyName, property, valueNode)
453         }
454     }
455
456     override fun assignWorkflowInputs(workflowName: String, jsonNode: JsonNode) {
457         log.info("assign workflow {} input value ({})", workflowName, jsonNode.toString())
458
459         val dynamicInputPropertiesName = "$workflowName-properties"
460
461         bluePrintContext.workflowByName(workflowName).inputs?.forEach { propertyName, property ->
462             if (propertyName != dynamicInputPropertiesName) {
463                 val valueNode: JsonNode = jsonNode.at(BluePrintConstants.PATH_DIVIDER + propertyName)
464                         ?: NullNode.getInstance()
465                 setInputValue(propertyName, property, valueNode)
466             }
467         }
468         // Load Dynamic data Types
469         val workflowDynamicInputs: JsonNode? = jsonNode.get(dynamicInputPropertiesName)
470
471         workflowDynamicInputs?.let {
472             bluePrintContext.dataTypeByName("dt-$dynamicInputPropertiesName")?.properties?.forEach { propertyName, property ->
473                 val valueNode: JsonNode = workflowDynamicInputs.at(BluePrintConstants.PATH_DIVIDER + propertyName)
474                         ?: NullNode.getInstance()
475                 setInputValue(propertyName, property, valueNode)
476
477             }
478         }
479     }
480
481     override fun getJsonForNodeTemplateAttributeProperties(nodeTemplateName: String, keys: List<String>): JsonNode {
482
483         val jsonNode: ObjectNode = jacksonObjectMapper().createObjectNode()
484         val path: String = StringBuilder(BluePrintConstants.PATH_NODE_TEMPLATES)
485                 .append(BluePrintConstants.PATH_DIVIDER).append(nodeTemplateName)
486                 .append(BluePrintConstants.PATH_DIVIDER).append(BluePrintConstants.PATH_ATTRIBUTES)
487                 .append(BluePrintConstants.PATH_DIVIDER).toString()
488         store.keys.filter {
489             it.startsWith(path)
490         }.map {
491             val key = it.replace(path, "")
492             if (keys.contains(key)) {
493                 val value = store[it] as JsonNode
494                 jsonNode.set(key, value)
495             }
496         }
497         return jsonNode
498     }
499
500
501 }