05e7b6941d1ab449f4838fcd1163164958f42de7
[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(
200             blueprintRuntimeService: BluePrintRuntimeService<*>,
201             templateArtifactName: String
202         ): ResourceAssignmentRuntimeService {
203
204             val resourceAssignmentRuntimeService = ResourceAssignmentRuntimeService(
205                 blueprintRuntimeService.id(),
206                 blueprintRuntimeService.bluePrintContext()
207             )
208             resourceAssignmentRuntimeService.createUniqueId(templateArtifactName)
209             resourceAssignmentRuntimeService.setExecutionContext(blueprintRuntimeService.getExecutionContext() as MutableMap<String, JsonNode>)
210
211             return resourceAssignmentRuntimeService
212         }
213
214         @Throws(BluePrintProcessorException::class)
215         fun getPropertyType(
216             raRuntimeService: ResourceAssignmentRuntimeService, dataTypeName: String,
217             propertyName: String
218         ): String {
219             lateinit var type: String
220             try {
221                 val dataTypeProps =
222                     checkNotNull(raRuntimeService.bluePrintContext().dataTypeByName(dataTypeName)?.properties)
223
224                 val propertyDefinition = checkNotNull(dataTypeProps[propertyName])
225                 type = checkNotEmpty(propertyDefinition.type) { "Couldn't get data type ($dataTypeName)" }
226                 logger.trace("Data type({})'s property ({}) is ({})", dataTypeName, propertyName, type)
227             } catch (e: Exception) {
228                 logger.error("couldn't get data type($dataTypeName)'s property ($propertyName), error message $e")
229                 throw BluePrintProcessorException("${e.message}", e)
230             }
231             return type
232         }
233
234         @Throws(BluePrintProcessorException::class)
235         fun parseResponseNode(
236             responseNode: JsonNode, resourceAssignment: ResourceAssignment,
237             raRuntimeService: ResourceAssignmentRuntimeService, outputKeyMapping: MutableMap<String, String>
238         ): JsonNode {
239             val metadata = resourceAssignment.property!!.metadata
240             try {
241                 if ((resourceAssignment.property?.type).isNullOrEmpty()) {
242                     throw BluePrintProcessorException("Couldn't get data dictionary type for dictionary name (${resourceAssignment.name})")
243                 }
244                 val type = resourceAssignment.property!!.type
245                 val valueToPrint = getValueToLog(metadata, responseNode)
246
247                 logger.info("For template key (${resourceAssignment.name}) setting value as ($valueToPrint)")
248                 return when (type) {
249                     in BluePrintTypes.validPrimitiveTypes() -> {
250                         parseResponseNodeForPrimitiveTypes(responseNode, outputKeyMapping)
251                     }
252                     in BluePrintTypes.validCollectionTypes() -> {
253                         // Array Types
254                         parseResponseNodeForCollection(responseNode, resourceAssignment, raRuntimeService, outputKeyMapping)
255                     }
256                     else -> {
257                         // Complex Types
258                         parseResponseNodeForComplexType(responseNode, resourceAssignment, raRuntimeService, outputKeyMapping)
259                     }
260                 }
261             } catch (e: Exception) {
262                 logger.error("Fail to parse response data, error message $e")
263                 throw BluePrintProcessorException("${e.message}", e)
264             }
265         }
266
267         private fun parseResponseNodeForPrimitiveTypes(
268             responseNode: JsonNode,
269             outputKeyMapping: MutableMap<String, String>
270         ): JsonNode {
271             if (responseNode.isComplexType()) {
272                 val outputKey = outputKeyMapping.keys.firstOrNull()
273                 var returnNode = if (responseNode is ArrayNode) {
274                     val arrayNode = responseNode.toList()
275                     if (outputKey.isNullOrEmpty()) {
276                         arrayNode.first()
277                     } else {
278                         arrayNode.firstOrNull { element ->
279                             element.isComplexType() && element.has(outputKeyMapping[outputKey])
280                         }
281                     }
282                 } else {
283                     responseNode
284                 }
285
286                 if (returnNode.isNull() || returnNode!!.isComplexType() && !returnNode.has(outputKeyMapping[outputKey])) {
287                     throw BluePrintProcessorException("Fail to find output key mapping ($outputKey) in the responseNode.")
288                 }
289                 return if (returnNode.isComplexType()) {
290                     returnNode[outputKeyMapping[outputKey]]
291                 } else {
292                     returnNode
293                 }
294             }
295             if (outputKeyMapping.isNotEmpty()) {
296                 throw BluePrintProcessorException("Fail to find key-value in response node to map output-key-mapping.")
297             }
298             return responseNode
299         }
300
301         private fun parseResponseNodeForCollection(
302             responseNode: JsonNode, resourceAssignment: ResourceAssignment,
303             raRuntimeService: ResourceAssignmentRuntimeService,
304             outputKeyMapping: MutableMap<String, String>
305         ): JsonNode {
306             val dName = resourceAssignment.dictionaryName
307             val metadata = resourceAssignment.property!!.metadata
308             var resultNode: JsonNode
309             if ((resourceAssignment.property?.entrySchema?.type).isNullOrEmpty()) {
310                 throw BluePrintProcessorException(
311                     "Couldn't get data type for dictionary type " +
312                             "(${resourceAssignment.property!!.type}) and dictionary name ($dName)"
313                 )
314             }
315             val entrySchemaType = resourceAssignment.property!!.entrySchema!!.type
316
317             var arrayNode = JacksonUtils.objectMapper.createArrayNode()
318             if (outputKeyMapping.isNotEmpty()) {
319                 when (responseNode) {
320                     is ArrayNode -> {
321                         val responseArrayNode = responseNode.toList()
322                         for (responseSingleJsonNode in responseArrayNode) {
323                             val arrayChildNode = parseSingleElementOfArrayResponseNode(
324                                 entrySchemaType,
325                                 outputKeyMapping, raRuntimeService, responseSingleJsonNode, metadata
326                             )
327                             arrayNode.add(arrayChildNode)
328                         }
329                         resultNode = arrayNode
330                     }
331                     is ObjectNode -> {
332                         val responseArrayNode = responseNode.rootFieldsToMap()
333                         resultNode =
334                             parseObjectResponseNode(entrySchemaType, outputKeyMapping, responseArrayNode, metadata)
335                     }
336                     else -> {
337                         throw BluePrintProcessorException("Key-value response expected to match the responseNode.")
338                     }
339                 }
340             } else {
341                 when (responseNode) {
342                     is ArrayNode -> {
343                         responseNode.forEach { elementNode ->
344                             arrayNode.add(elementNode)
345                         }
346                         resultNode = arrayNode
347                     }
348                     is ObjectNode -> {
349                         val responseArrayNode = responseNode.rootFieldsToMap()
350                         for ((key, responseSingleJsonNode) in responseArrayNode) {
351                             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
352                             logKeyValueResolvedResource(metadata, key, responseSingleJsonNode, entrySchemaType)
353                             JacksonUtils.populateJsonNodeValues(
354                                 key,
355                                 responseSingleJsonNode,
356                                 entrySchemaType,
357                                 arrayChildNode
358                             )
359                             arrayNode.add(arrayChildNode)
360                         }
361                         resultNode = arrayNode
362                     }
363                     else -> {
364                         resultNode = responseNode
365                     }
366                 }
367             }
368
369             return resultNode
370         }
371
372         private fun parseSingleElementOfArrayResponseNode(
373             entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
374             raRuntimeService: ResourceAssignmentRuntimeService,
375             responseNode: JsonNode, metadata: MutableMap<String, String>?
376         ): ObjectNode {
377             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
378             when (entrySchemaType) {
379                 in BluePrintTypes.validPrimitiveTypes() -> {
380                     if (outputKeyMappingHasOnlyOneElement) {
381                         val outputKeyMap = outputKeyMapping.entries.first()
382                         return parseSingleElementNodeWithOneOutputKeyMapping(
383                             responseNode,
384                             outputKeyMap.key,
385                             outputKeyMap.value,
386                             entrySchemaType,
387                             metadata
388                         )
389                     } else {
390                         throw BluePrintProcessorException("Expect one entry in output-key-mapping")
391                     }
392                 }
393                 else -> {
394                     return when {
395                         checkOutputKeyMappingAllElementsInDataTypeProperties(
396                             entrySchemaType,
397                             outputKeyMapping,
398                             raRuntimeService
399                         ) -> {
400                             parseSingleElementNodeWithAllOutputKeyMapping(
401                                 responseNode,
402                                 outputKeyMapping,
403                                 entrySchemaType,
404                                 metadata
405                             )
406                         }
407                         outputKeyMappingHasOnlyOneElement -> {
408                             val outputKeyMap = outputKeyMapping.entries.first()
409                             parseSingleElementNodeWithOneOutputKeyMapping(
410                                 responseNode,
411                                 outputKeyMap.key,
412                                 outputKeyMap.value,
413                                 entrySchemaType,
414                                 metadata
415                             )
416                         }
417                         else -> {
418                             throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
419                         }
420                     }
421                 }
422             }
423         }
424
425         private fun parseObjectResponseNode(
426             entrySchemaType: String, outputKeyMapping: MutableMap<String, String>,
427             responseArrayNode: MutableMap<String, JsonNode>, metadata: MutableMap<String, String>?
428         ): ObjectNode {
429             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
430             if (outputKeyMappingHasOnlyOneElement) {
431                 val outputKeyMap = outputKeyMapping.entries.first()
432                 return parseObjectResponseNodeWithOneOutputKeyMapping(
433                     responseArrayNode, outputKeyMap.key, outputKeyMap.value,
434                     entrySchemaType, metadata
435                 )
436             } else {
437                 throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
438             }
439         }
440
441         private fun parseSingleElementNodeWithOneOutputKeyMapping(
442             responseSingleJsonNode: JsonNode, outputKeyMappingKey:
443             String, outputKeyMappingValue: String, type: String, metadata: MutableMap<String, String>?
444         ): ObjectNode {
445             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
446
447             val responseKeyValue = if (responseSingleJsonNode.has(outputKeyMappingValue)) {
448                 responseSingleJsonNode.get(outputKeyMappingValue)
449             } else {
450                 NullNode.getInstance()
451             }
452
453             logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseKeyValue, type)
454             JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseKeyValue, type, arrayChildNode)
455
456             return arrayChildNode
457         }
458
459         private fun parseSingleElementNodeWithAllOutputKeyMapping(
460             responseSingleJsonNode: JsonNode,
461             outputKeyMapping: MutableMap<String, String>,
462             type: String, metadata: MutableMap<String, String>?
463         ): ObjectNode {
464             val arrayChildNode = JacksonUtils.objectMapper.createObjectNode()
465             outputKeyMapping.map {
466                 val responseKeyValue = if (responseSingleJsonNode.has(it.value)) {
467                     responseSingleJsonNode.get(it.value)
468                 } else {
469                     NullNode.getInstance()
470                 }
471
472                 logKeyValueResolvedResource(metadata, it.key, responseKeyValue, type)
473                 JacksonUtils.populateJsonNodeValues(it.key, responseKeyValue, type, arrayChildNode)
474             }
475             return arrayChildNode
476         }
477
478         private fun parseObjectResponseNodeWithOneOutputKeyMapping(
479             responseArrayNode: MutableMap<String, JsonNode>,
480             outputKeyMappingKey: String, outputKeyMappingValue: String,
481             type: String, metadata: MutableMap<String, String>?
482         ): ObjectNode {
483             val objectNode = JacksonUtils.objectMapper.createObjectNode()
484             val responseSingleJsonNode = responseArrayNode.filterKeys { key ->
485                 key == outputKeyMappingValue
486             }.entries.firstOrNull()
487
488             if (responseSingleJsonNode == null) {
489                 logKeyValueResolvedResource(metadata, outputKeyMappingKey, NullNode.getInstance(), type)
490                 JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, NullNode.getInstance(), type, objectNode)
491             } else {
492                 logKeyValueResolvedResource(metadata, outputKeyMappingKey, responseSingleJsonNode.value, type)
493                 JacksonUtils.populateJsonNodeValues(outputKeyMappingKey, responseSingleJsonNode.value, type, objectNode)
494             }
495             return objectNode
496         }
497
498         private fun parseResponseNodeForComplexType(
499             responseNode: JsonNode, resourceAssignment: ResourceAssignment,
500             raRuntimeService: ResourceAssignmentRuntimeService,
501             outputKeyMapping: MutableMap<String, String>
502         ): JsonNode {
503             val entrySchemaType = resourceAssignment.property!!.type
504             val dictionaryName = resourceAssignment.dictionaryName!!
505             val metadata = resourceAssignment.property!!.metadata
506             val outputKeyMappingHasOnlyOneElement = checkIfOutputKeyMappingProvideOneElement(outputKeyMapping)
507
508             if (outputKeyMapping.isNotEmpty()) {
509                 return when {
510                     checkOutputKeyMappingAllElementsInDataTypeProperties(
511                         entrySchemaType,
512                         outputKeyMapping,
513                         raRuntimeService
514                     ) -> {
515                         parseSingleElementNodeWithAllOutputKeyMapping(
516                             responseNode,
517                             outputKeyMapping,
518                             entrySchemaType,
519                             metadata
520                         )
521                     }
522                     outputKeyMappingHasOnlyOneElement -> {
523                         val outputKeyMap = outputKeyMapping.entries.first()
524                         parseSingleElementNodeWithOneOutputKeyMapping(
525                             responseNode, outputKeyMap.key, outputKeyMap.value,
526                             entrySchemaType, metadata
527                         )
528                     }
529                     else -> {
530                         throw BluePrintProcessorException("Output-key-mapping do not map the Data Type $entrySchemaType")
531                     }
532                 }
533             } else {
534                 val childNode = JacksonUtils.objectMapper.createObjectNode()
535                 JacksonUtils.populateJsonNodeValues(dictionaryName, responseNode, entrySchemaType, childNode)
536                 return childNode
537             }
538         }
539
540         private fun checkOutputKeyMappingAllElementsInDataTypeProperties(
541             dataTypeName: String, outputKeyMapping: MutableMap<String, String>,
542             raRuntimeService: ResourceAssignmentRuntimeService
543         ): Boolean {
544             val dataTypeProps = raRuntimeService.bluePrintContext().dataTypeByName(dataTypeName)?.properties
545             val result = outputKeyMapping.filterKeys { !dataTypeProps!!.containsKey(it) }.keys.firstOrNull()
546             return result == null
547         }
548
549         private fun logKeyValueResolvedResource(
550             metadata: MutableMap<String, String>?,
551             key: String,
552             value: JsonNode,
553             type: String
554         ) {
555             val valueToPrint = getValueToLog(metadata, value)
556
557             logger.info(
558                 "For List Type Resource: key ($key), value ($valueToPrint), " +
559                         "type  ({$type})"
560             )
561         }
562
563         private fun checkIfOutputKeyMappingProvideOneElement(outputKeyMapping: MutableMap<String, String>): Boolean {
564             return (outputKeyMapping.size == 1)
565         }
566
567         fun getValueToLog(metadata: MutableMap<String, String>?, value: Any): Any {
568             return if (checkIfLogIsProtected(metadata)) {
569                 "*************"
570             } else {
571                 value
572             }
573         }
574
575         private fun checkIfLogIsProtected(metadata: MutableMap<String, String>?): Boolean {
576             var checkProtected = false
577             if (metadata != null &&
578                 metadata.containsKey(ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA)
579             ) {
580                 val protectedMetadata = metadata[ResourceResolutionConstants.RESOURCE_RESOLUTION_LOG_PROTECTED_METADATA]
581                 if (protectedMetadata == "yes" || protectedMetadata == "y") {
582                     checkProtected = true
583                 }
584             }
585             return checkProtected
586         }
587     }
588 }