2a3820f079a97309199fc80d4f3b3a0372220b42
[ccsdk/cds.git] /
1 /*
2  * Copyright © 2017-2018 AT&T Intellectual Property.
3  * Modifications Copyright (c) 2019 IBM, Bell Canada.
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.blueprintsprocessor.functions.resource.resolution.utils
19
20 import com.fasterxml.jackson.databind.JsonNode
21 import com.fasterxml.jackson.databind.ObjectMapper
22 import com.fasterxml.jackson.databind.node.ArrayNode
23 import com.fasterxml.jackson.databind.node.NullNode
24 import com.fasterxml.jackson.databind.node.ObjectNode
25 import com.fasterxml.jackson.databind.node.TextNode
26 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceAssignmentRuntimeService
27 import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.ResourceResolutionConstants
28 import org.onap.ccsdk.cds.controllerblueprints.core.*
29 import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService
30 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils
31 import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils
32 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
33 import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceDefinition
34 import org.slf4j.LoggerFactory
35 import java.util.*
36
37 class ResourceAssignmentUtils {
38     companion object {
39
40         private val logger = LoggerFactory.getLogger(ResourceAssignmentUtils::class.toString())
41
42         suspend fun resourceDefinitions(blueprintBasePath: String): MutableMap<String, ResourceDefinition> {
43             val dictionaryFile = normalizedFile(
44                 blueprintBasePath, BluePrintConstants.TOSCA_DEFINITIONS_DIR,
45                 ResourceResolutionConstants.FILE_NAME_RESOURCE_DEFINITION_TYPES
46             )
47             checkFileExists(dictionaryFile) { "resource definition file(${dictionaryFile.absolutePath}) is missing" }
48             return JacksonReactorUtils.getMapFromFile(dictionaryFile, ResourceDefinition::class.java)
49         }
50
51         @Throws(BluePrintProcessorException::class)
52         fun setResourceDataValue(
53             resourceAssignment: ResourceAssignment,
54             raRuntimeService: ResourceAssignmentRuntimeService, value: Any?
55         ) {
56             // TODO("See if Validation is needed in future with respect to conversion and Types")
57             return setResourceDataValue(resourceAssignment, raRuntimeService, value.asJsonType())
58         }
59
60         @Throws(BluePrintProcessorException::class)
61         fun setResourceDataValue(
62             resourceAssignment: ResourceAssignment,
63             raRuntimeService: ResourceAssignmentRuntimeService, value: JsonNode
64         ) {
65             val resourceProp = checkNotNull(resourceAssignment.property) {
66                 "Failed in setting resource value for resource mapping $resourceAssignment"
67             }
68             checkNotEmpty(resourceAssignment.name) {
69                 "Failed in setting resource value for resource mapping $resourceAssignment"
70             }
71
72             if (resourceAssignment.dictionaryName.isNullOrEmpty()) {
73                 resourceAssignment.dictionaryName = resourceAssignment.name
74                 logger.warn(
75                     "Missing dictionary key, setting with template key (${resourceAssignment.name}) " +
76                             "as dictionary key (${resourceAssignment.dictionaryName})"
77                 )
78             }
79
80             try {
81                 if (resourceProp.type.isNotEmpty()) {
82                     val metadata = resourceAssignment.property!!.metadata
83                     val valueToPrint = getValueToLog(metadata, value)
84                     logger.info(
85                         "Setting Resource Value ($valueToPrint) for Resource Name " +
86                                 "(${resourceAssignment.name}), definition(${resourceAssignment.dictionaryName}) " +
87                                 "of type (${resourceProp.type})"
88                     )
89                     setResourceValue(resourceAssignment, raRuntimeService, value)
90                     resourceAssignment.updatedDate = Date()
91                     resourceAssignment.updatedBy = BluePrintConstants.USER_SYSTEM
92                     resourceAssignment.status = BluePrintConstants.STATUS_SUCCESS
93                 }
94             } catch (e: Exception) {
95                 throw BluePrintProcessorException(
96                     "Failed in setting value for template key " +
97                             "(${resourceAssignment.name}) and dictionary key (${resourceAssignment.dictionaryName}) of " +
98                             "type (${resourceProp.type}) with error message (${e.message})", e
99                 )
100             }
101         }
102
103         private fun setResourceValue(
104             resourceAssignment: ResourceAssignment,
105             raRuntimeService: ResourceAssignmentRuntimeService, value: JsonNode
106         ) {
107             // TODO("See if Validation is needed wrt to type before storing")
108             raRuntimeService.putResolutionStore(resourceAssignment.name, value)
109             raRuntimeService.putDictionaryStore(resourceAssignment.dictionaryName!!, value)
110             resourceAssignment.property!!.value = value
111         }
112
113         fun setFailedResourceDataValue(resourceAssignment: ResourceAssignment, message: String?) {
114             if (isNotEmpty(resourceAssignment.name)) {
115                 resourceAssignment.updatedDate = Date()
116                 resourceAssignment.updatedBy = BluePrintConstants.USER_SYSTEM
117                 resourceAssignment.status = BluePrintConstants.STATUS_FAILURE
118                 resourceAssignment.message = message
119             }
120         }
121
122         @Throws(BluePrintProcessorException::class)
123         fun assertTemplateKeyValueNotNull(resourceAssignment: ResourceAssignment) {
124             val resourceProp = checkNotNull(resourceAssignment.property) {
125                 "Failed to populate mandatory resource resource mapping $resourceAssignment"
126             }
127             if (resourceProp.required != null && resourceProp.required!!
128                 && (resourceProp.value == null || resourceProp.value!!.returnNullIfMissing() == null)
129             ) {
130                 logger.error("failed to populate mandatory resource mapping ($resourceAssignment)")
131                 throw BluePrintProcessorException("failed to populate mandatory resource mapping ($resourceAssignment)")
132             }
133         }
134
135         @Throws(BluePrintProcessorException::class)
136         fun generateResourceDataForAssignments(assignments: List<ResourceAssignment>): String {
137             val result: String
138             try {
139                 val mapper = ObjectMapper()
140                 val root: ObjectNode = mapper.createObjectNode()
141
142                 var containsLogProtected = false
143                 assignments.forEach {
144                     if (isNotEmpty(it.name) && it.property != null) {
145                         val rName = it.name
146                         val metadata = it.property!!.metadata
147                         val type = nullToEmpty(it.property?.type).toLowerCase()
148                         val value = useDefaultValueIfNull(it, rName)
149                         val valueToPrint = getValueToLog(metadata, value)
150                         if (checkIfLogIsProtected(metadata)) {
151                             containsLogProtected = true
152                         }
153                         logger.trace("Generating Resource name ($rName), type ($type), value ($valueToPrint)")
154                         root.set(rName, value)
155                     }
156                 }
157                 result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(root)
158
159                 if (!containsLogProtected) {
160                     logger.info("Generated Resource Param Data ($result)")
161                 }
162             } catch (e: Exception) {
163                 throw BluePrintProcessorException("Resource Assignment is failed with $e.message", e)
164             }
165
166             return result
167         }
168
169         @Throws(BluePrintProcessorException::class)
170         fun generateResourceForAssignments(assignments: List<ResourceAssignment>): MutableMap<String, JsonNode> {
171             val data: MutableMap<String, JsonNode> = hashMapOf()
172             assignments.forEach {
173                 if (isNotEmpty(it.name) && it.property != null) {
174                     val rName = it.name
175                     val metadata = it.property!!.metadata
176                     val type = nullToEmpty(it.property?.type).toLowerCase()
177                     val value = useDefaultValueIfNull(it, rName)
178                     val valueToPrint = getValueToLog(metadata, value)
179
180                     logger.trace("Generating Resource name ($rName), type ($type), value ($valueToPrint)")
181                     data[rName] = value
182                 }
183             }
184             return data
185         }
186
187         private fun useDefaultValueIfNull(
188             resourceAssignment: ResourceAssignment,
189             resourceAssignmentName: String
190         ): JsonNode {
191             if (resourceAssignment.property?.value == null) {
192                 val defaultValue = "\${$resourceAssignmentName}"
193                 return TextNode(defaultValue)
194             } else {
195                 return resourceAssignment.property!!.value!!
196             }
197         }
198
199         fun transformToRARuntimeService(blueprintRuntimeService: BluePrintRuntimeService<*>,
200                                         templateArtifactName: String): ResourceAssignmentRuntimeService {
201
202             val resourceAssignmentRuntimeService = ResourceAssignmentRuntimeService(
203                 blueprintRuntimeService.id(),
204                 blueprintRuntimeService.bluePrintContext()
205             )
206             resourceAssignmentRuntimeService.createUniqueId(templateArtifactName)
207             resourceAssignmentRuntimeService.setExecutionContext(blueprintRuntimeService.getExecutionContext() as MutableMap<String, JsonNode>)
208
209             return resourceAssignmentRuntimeService
210         }
211
212         @Throws(BluePrintProcessorException::class)
213         fun getPropertyType(raRuntimeService: ResourceAssignmentRuntimeService, dataTypeName: String,
214                             propertyName: String): String {
215             lateinit var type: String
216             try {
217                 val dataTypeProps =
218                     checkNotNull(raRuntimeService.bluePrintContext().dataTypeByName(dataTypeName)?.properties)
219
220                 val propertyDefinition = checkNotNull(dataTypeProps[propertyName])
221                 type = checkNotEmpty(propertyDefinition.type) { "Couldn't get data type ($dataTypeName)" }
222                 logger.trace("Data type({})'s property ({}) is ({})", dataTypeName, propertyName, type)
223             } catch (e: Exception) {
224                 logger.error("couldn't get data type($dataTypeName)'s property ($propertyName), error message $e")
225                 throw BluePrintProcessorException("${e.message}", e)
226             }
227             return type
228         }
229
230         @Throws(BluePrintProcessorException::class)
231         fun parseResponseNode(responseNode: JsonNode, resourceAssignment: ResourceAssignment,
232                               raRuntimeService: ResourceAssignmentRuntimeService, outputKeyMapping: MutableMap<String, String>): JsonNode {
233             val metadata = resourceAssignment.property!!.metadata
234             try {
235                 if ((resourceAssignment.property?.type).isNullOrEmpty()) {
236                     throw BluePrintProcessorException("Couldn't get data dictionary type for dictionary name (${resourceAssignment.name})")
237                 }
238                 val type = resourceAssignment.property!!.type
239                 val valueToPrint = getValueToLog(metadata, responseNode)
240
241                 logger.info("For template key (${resourceAssignment.name}) setting value as ($valueToPrint)")
242                 return when (type) {
243                     in BluePrintTypes.validPrimitiveTypes() -> {
244                         parseResponseNodeForPrimitiveTypes(responseNode, outputKeyMapping)
245                     }
246                     in BluePrintTypes.validCollectionTypes() -> {
247                         // Array Types
248                         parseResponseNodeForCollection(responseNode, resourceAssignment, raRuntimeService, outputKeyMapping)
249                     }
250                     else -> {
251                         // Complex Types
252                         parseResponseNodeForComplexType(responseNode, resourceAssignment, raRuntimeService, outputKeyMapping)
253                     }
254                 }
255             } catch (e: Exception) {
256                 logger.error("Fail to parse response data, error message $e")
257                 throw BluePrintProcessorException("${e.message}", e)
258             }
259         }
260
261         //TODO: Need to Refactor
262         private fun parseResponseNodeForPrimitiveTypes(responseNode: JsonNode,
263                                                        outputKeyMapping: MutableMap<String, String>): JsonNode {
264             var result: JsonNode? = responseNode
265
266             if (responseNode.isComplexType()) {
267                 val key = outputKeyMapping.keys.firstOrNull()
268                 var returnNode: JsonNode?
269                 if (responseNode is ArrayNode) {
270                     val arrayNode = responseNode.toList()
271                     val firstElement = if (key.isNullOrEmpty()) {
272                         arrayNode.first()
273                     } else {
274                         arrayNode.firstOrNull { element ->
275                             element.isComplexType() && element.has(outputKeyMapping[key])
276                         }
277                     }
278                     returnNode = firstElement
279                 } else {
280                     returnNode = responseNode
281                 }
282
283                 if (returnNode.isNull() || (returnNode!!.isComplexType() && !returnNode.has(outputKeyMapping[key]))) {
284                     if (key.isNullOrEmpty()) {
285                         throw BluePrintProcessorException("Fail to find mapping in the responseNode.")
286                     } else {
287                         throw BluePrintProcessorException("Fail to find response with output key mapping ($key) in result.")
288                     }
289                 }
290                 result = if (returnNode.isComplexType()) {
291                     returnNode[outputKeyMapping[key]]
292                 } else {
293                     responseNode
294                 }
295             } else {
296                 if (outputKeyMapping.isNotEmpty()) {
297                     throw BluePrintProcessorException("Fail to find key-value in response node to map output-key-mapping.")
298                 }
299             }
300             return result!!
301         }
302
303         private fun parseResponseNodeForCollection(
304             responseNode: JsonNode, resourceAssignment: ResourceAssignment,
305             raRuntimeService: ResourceAssignmentRuntimeService,
306             outputKeyMapping: MutableMap<String, String>
307         ): JsonNode {
308             val dName = resourceAssignment.dictionaryName
309             val metadata = resourceAssignment.property!!.metadata
310             var resultNode: JsonNode
311             if ((resourceAssignment.property?.entrySchema?.type).isNullOrEmpty()) {
312                 throw BluePrintProcessorException(
313                     "Couldn't get data type for dictionary type " +
314                             "(${resourceAssignment.property!!.type}) and dictionary name ($dName)"
315                 )
316             }
317             val entrySchemaType = resourceAssignment.property!!.entrySchema!!.type
318
319             var arrayNode = JacksonUtils.objectMapper.createArrayNode()
320             if (outputKeyMapping.isNotEmpty()) {
321                 when (responseNode) {
322                     is ArrayNode -> {
323                         val responseArrayNode = responseNode.toList()
324                         for (responseSingleJsonNode in responseArrayNode) {
325                             val arrayChildNode = parseSingleElementOfArrayResponseNode(
326                                 entrySchemaType,
327                                 outputKeyMapping, raRuntimeService, responseSingleJsonNode, metadata
328                             )
329                             arrayNode.add(arrayChildNode)
330                         }
331                         resultNode = arrayNode
332                     }
333                     is ObjectNode -> {
334                         val responseArrayNode = responseNode.rootFieldsToMap()
335                         resultNode =
336                             parseObjectResponseNode(entrySchemaType, outputKeyMapping, responseArrayNode, metadata)
337                     }
338                     else -> {
339                         throw BluePrintProcessorException("Key-value response expected to match the responseNode.")
340                     }
341                 }
342             } else {
343                 when (responseNode) {
344                     is ArrayNode -> {
345                         responseNode.forEach { elementNode ->
346                             arrayNode.add(elementNode)
347                         }
348                         resultNode = arrayNode
349                     }
350                     is ObjectNode -> {
351                         val responseArrayNode = responseNode.rootFieldsToMap()
352                         for ((key, responseSingleJsonNode) in responseArrayNode) {
353                             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
354                             logKeyValueResolvedResource(metadata, key, responseSingleJsonNode, entrySchemaType)
355                             JacksonUtils.populateJsonNodeValues(
356                                 key,
357                                 responseSingleJsonNode,
358                                 entrySchemaType,
359                                 arrayChildNode
360                             )
361                             arrayNode.add(arrayChildNode)
362                         }
363                         resultNode = arrayNode
364                     }
365                     else -> {
366                         resultNode = responseNode
367                     }
368                 }
369             }
370
371             return resultNode
372         }
373
374         private fun parseSingleElementOfArrayResponseNode(
375             entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
376             raRuntimeService: ResourceAssignmentRuntimeService,
377             responseNode: JsonNode, metadata: MutableMap<String, String>?
378         ): ObjectNode {
379             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
380             when (entrySchemaType) {
381                 in BluePrintTypes.validPrimitiveTypes() -> {
382                     if (outputKeyMappingHasOnlyOneElement) {
383                         val outputKeyMap = outputKeyMapping.entries.first()
384                         return parseSingleElementNodeWithOneOutputKeyMapping(
385                             responseNode,
386                             outputKeyMap.key,
387                             outputKeyMap.value,
388                             entrySchemaType,
389                             metadata
390                         )
391                     } else {
392                         throw BluePrintProcessorException("Expect one entry in output-key-mapping")
393                     }
394                 }
395                 else -> {
396                     return when {
397                         checkOutputKeyMappingAllElementsInDataTypeProperties(
398                             entrySchemaType,
399                             outputKeyMapping,
400                             raRuntimeService
401                         ) -> {
402                             parseSingleElementNodeWithAllOutputKeyMapping(
403                                 responseNode,
404                                 outputKeyMapping,
405                                 entrySchemaType,
406                                 metadata
407                             )
408                         }
409                         outputKeyMappingHasOnlyOneElement -> {
410                             val outputKeyMap = outputKeyMapping.entries.first()
411                             parseSingleElementNodeWithOneOutputKeyMapping(
412                                 responseNode,
413                                 outputKeyMap.key,
414                                 outputKeyMap.value,
415                                 entrySchemaType,
416                                 metadata
417                             )
418                         }
419                         else -> {
420                             throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
421                         }
422                     }
423                 }
424             }
425         }
426
427         private fun parseObjectResponseNode(
428             entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
429             responseArrayNode: MutableMap<String, JsonNode>, metadata: MutableMap<String, String>?
430         ): ObjectNode {
431             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
432             if (outputKeyMappingHasOnlyOneElement) {
433                 val outputKeyMap = outputKeyMapping.entries.first()
434                 return parseObjectResponseNodeWithOneOutputKeyMapping(
435                     responseArrayNode, outputKeyMap.key, outputKeyMap.value,
436                     entrySchemaType, metadata
437                 )
438             } else {
439                 throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
440             }
441         }
442
443         private fun parseSingleElementNodeWithOneOutputKeyMapping(
444             responseSingleJsonNode: JsonNode, outputKeyMappingKey:
445             String, outputKeyMappingValue: String, type: String, metadata: MutableMap<String, String>?
446         ): ObjectNode {
447             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
448
449             val responseKeyValue = if (responseSingleJsonNode.has(outputKeyMappingValue)) {
450                 responseSingleJsonNode.get(outputKeyMappingValue)
451             } else {
452                 NullNode.getInstance()
453             }
454
455             logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseKeyValue, type)
456             JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseKeyValue, type, arrayChildNode)
457
458             return arrayChildNode
459         }
460
461         private fun parseSingleElementNodeWithAllOutputKeyMapping(
462             responseSingleJsonNode: JsonNode,
463             outputKeyMapping: MutableMap<String, String>,
464             type: String, metadata: MutableMap<String, String>?
465         ): ObjectNode {
466             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
467             outputKeyMapping.map {
468                 val responseKeyValue = if (responseSingleJsonNode.has(it.value)) {
469                     responseSingleJsonNode.get(it.value)
470                 } else {
471                     NullNode.getInstance()
472                 }
473
474                 logKeyValueResolvedResource(metadata, it.key, responseKeyValue, type)
475                 JacksonUtils.populateJsonNodeValues(it.key, responseKeyValue, type, arrayChildNode)
476             }
477             return arrayChildNode
478         }
479
480         private fun parseObjectResponseNodeWithOneOutputKeyMapping(
481             responseArrayNode: MutableMap<String, JsonNode>,
482             outputKeyMappingKey: String, outputKeyMappingValue: String,
483             type: String, metadata: MutableMap<String, String>?
484         ): ObjectNode {
485             val objectNode = JacksonUtils.objectMapper.createObjectNode()
486             val responseSingleJsonNode = responseArrayNode.filterKeys { key ->
487                 key == outputKeyMappingValue
488             }.entries.firstOrNull()
489
490             if (responseSingleJsonNode == null) {
491                 logKeyValueResolvedResource(metadata, outputKeyMappingKey, NullNode.getInstance(), type)
492                 JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, NullNode.getInstance(), type, objectNode)
493             } else {
494                 logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseSingleJsonNode.value, type)
495                 JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseSingleJsonNode.value, type, objectNode)
496             }
497             return objectNode
498         }
499
500         private fun parseResponseNodeForComplexType(
501             responseNode: JsonNode, resourceAssignment: ResourceAssignment,
502             raRuntimeService: ResourceAssignmentRuntimeService,
503             outputKeyMapping: MutableMap<String, String>
504         ): JsonNode {
505             val entrySchemaType = resourceAssignment.property!!.type
506             val dictionaryName = resourceAssignment.dictionaryName!!
507             val metadata = resourceAssignment.property!!.metadata
508             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
509
510             if (outputKeyMapping.isNotEmpty()) {
511                 return when {
512                     checkOutputKeyMappingAllElementsInDataTypeProperties(
513                         entrySchemaType,
514                         outputKeyMapping,
515                         raRuntimeService
516                     ) -> {
517                         parseSingleElementNodeWithAllOutputKeyMapping(
518                             responseNode,
519                             outputKeyMapping,
520                             entrySchemaType,
521                             metadata
522                         )
523                     }
524                     outputKeyMappingHasOnlyOneElement -> {
525                         val outputKeyMap = outputKeyMapping.entries.first()
526                         parseSingleElementNodeWithOneOutputKeyMapping(
527                             responseNode, outputKeyMap.key, outputKeyMap.value,
528                             entrySchemaType, metadata
529                         )
530                     }
531                     else -> {
532                         throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
533                     }
534                 }
535             } else {
536                 val childNode = JacksonUtils.objectMapper.createObjectNode()
537                 JacksonUtils.populateJsonNodeValues(dictionaryName, responseNode, entrySchemaType, childNode)
538                 return childNode
539             }
540         }
541
542         private fun checkOutputKeyMappingAllElementsInDataTypeProperties(
543             dataTypeName: String, outputKeyMapping: MutableMap<String, String>,
544             raRuntimeService: ResourceAssignmentRuntimeService
545         ): Boolean {
546             val dataTypeProps = raRuntimeService.bluePrintContext().dataTypeByName(dataTypeName)?.properties
547             val result = outputKeyMapping.filterKeys { !dataTypeProps!!.containsKey(it) }.keys.firstOrNull()
548             return result == null
549         }
550
551         private fun logKeyValueResolvedResource(
552             metadata: MutableMap<String, String>?,
553             key: String,
554             value: JsonNode,
555             type: String
556         ) {
557             val valueToPrint = getValueToLog(metadata, value)
558
559             logger.info(
560                 "For List Type Resource: key ($key), value ($valueToPrint), " +
561                         "type  ({$type})"
562             )
563         }
564
565         private fun checkIfOutputKeyMappingProvideOneElement(outputKeyMapping: MutableMap<String, String>): Boolean {
566             return (outputKeyMapping.size == 1)
567         }
568
569         fun getValueToLog(metadata: MutableMap<String, String>?, value: Any): Any {
570             return if (checkIfLogIsProtected(metadata)) {
571                 "*************"
572             } else {
573                 value
574             }
575         }
576
577         private fun checkIfLogIsProtected(metadata: MutableMap<String, String>?): Boolean {
578             var checkProtected = false
579             if (metadata != null &&
580                 metadata.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA)
581             ) {
582                 val protectedMetadata = metadata[ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA]
583                 if (protectedMetadata == "yes" || protectedMetadata == "y") {
584                     checkProtected = true
585                 }
586             }
587             return checkProtected
588         }
589     }
590 }