From: JvD_Ericsson Date: Fri, 2 Jun 2023 16:02:18 +0000 (+0100) Subject: Fix unable to set tosca function on complex type on input operation X-Git-Tag: 1.13.2~17 X-Git-Url: https://gerrit.onap.org/r/gitweb?p=sdc.git;a=commitdiff_plain;h=cf0a8b21e85ec41260da802a2b923fabe89c9aaa Fix unable to set tosca function on complex type on input operation Issue-ID: SDC-4527 Signed-off-by: JvD_Ericsson Change-Id: Icc7166978c13f3692dc25d9f33a7613d64f87f6a --- diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java index e56472a426..cce0ad19a3 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java @@ -21,35 +21,27 @@ import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.google.gson.Gson; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.collections.MapUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.json.JSONObject; -import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException; -import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.ToscaFunction; -import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.DataTypeDefinition; @@ -140,42 +132,10 @@ public class InterfacesOperationsConverter { mappedOutputValue.remove(1); mappedOutputValue.add(1, interfaceName); inputValue = gson.toJson(consumptionValue); - } else { - String finalInputValue = inputValue; - if (inputValue != null && - Arrays.stream(ToscaFunctionType.values()).anyMatch(toscaType -> finalInputValue.contains(toscaType.getName().toUpperCase()))) { - inputValue = getInputValuesAsToscaFunction(inputValue); - } } return inputValue; } - private static String getInputValuesAsToscaFunction(String inputValue) { - Gson gson = new Gson(); - Map mapOfValues = gson.fromJson(inputValue, Map.class); - for (Entry entry : mapOfValues.entrySet()) { - Object value = entry.getValue(); - if (value instanceof Map) { - Map valueMap = (Map) value; - if (valueMap.containsKey("type")) { - String type = (String) valueMap.get("type"); - Optional toscaType = ToscaFunctionType.findType(type); - if (toscaType.isPresent()) { - ObjectMapper mapper = new ObjectMapper(); - try { - String json = gson.toJson(value); - ToscaFunction toscaFunction = mapper.readValue(json, ToscaFunction.class); - entry.setValue(toscaFunction.getJsonObjectValue()); - } catch (JsonProcessingException e) { - throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR); - } - } - } - } - } - return String.valueOf(new JSONObject(mapOfValues)); - } - private static String getInterfaceType(Component component, String interfaceType) { if (LOCAL_INTERFACE_TYPE.equals(interfaceType)) { return DERIVED_FROM_BASE_DEFAULT + component.getComponentMetadataDefinition().getMetadataDataDefinition().getSystemName(); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java index 5158ae7945..5ba29cbbef 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java @@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.createMappedOutputDefaultValue; import static org.openecomp.sdc.be.tosca.InterfacesOperationsConverter.SELF; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -49,6 +50,7 @@ import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; +import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; @@ -238,8 +240,11 @@ class InterfacesOperationsConverterTest { "name_for_op_0")) .forEach(operation -> operation.getInputs().getListToscaDataDefinition().stream() .filter(operationInputDefinition -> operationInputDefinition.getName().contains("integer")) - .forEach(operationInputDefinition -> operationInputDefinition.setInputId(addedInterfaceType + - ".name_for_op_1.output_integer_1"))); + .forEach(operationInputDefinition -> { + operationInputDefinition.setInputId(addedInterfaceType + ".name_for_op_1.output_integer_1"); + operationInputDefinition.setToscaDefaultValue( + new Gson().toJson(createMappedOutputDefaultValue(SELF, operationInputDefinition.getInputId()))); + })); component.setInterfaces(new HashMap<>()); component.getInterfaces().put(addedInterfaceType, addedInterface); ToscaNodeType nodeType = new ToscaNodeType(); @@ -572,11 +577,12 @@ class InterfacesOperationsConverterTest { Map complexInput = (Map) operation0Inputs.get("input_Complex_2"); assertTrue(complexInput.containsKey("stringProp")); Map complexInputStringProp = (Map) complexInput.get("stringProp"); - assertTrue(complexInputStringProp.containsKey("get_attribute")); - List complexInputStringPropToscaFunction = (List) complexInputStringProp.get("get_attribute"); - assertEquals(2, complexInputStringPropToscaFunction.size()); - assertEquals("SELF", complexInputStringPropToscaFunction.get(0)); - assertEquals("designer", complexInputStringPropToscaFunction.get(1)); + assertTrue(complexInputStringProp.containsKey("type")); + assertTrue(ToscaFunctionType.findType((String) complexInputStringProp.get("type")).isPresent()); + assertTrue(complexInputStringProp.containsKey("propertyName")); + assertEquals("designer", complexInputStringProp.get("propertyName")); + assertTrue(complexInputStringProp.containsKey("propertySource")); + assertEquals("SELF", complexInputStringProp.get("propertySource")); } private void addComplexTypeToDataTypes() { diff --git a/catalog-ui/src/app/models/interfaceOperation.ts b/catalog-ui/src/app/models/interfaceOperation.ts index 20f73af3e7..a6279a589f 100644 --- a/catalog-ui/src/app/models/interfaceOperation.ts +++ b/catalog-ui/src/app/models/interfaceOperation.ts @@ -23,6 +23,7 @@ import {ArtifactModel} from "./artifacts"; import {SchemaPropertyGroupModel} from "./schema-property"; import {PROPERTY_DATA, PROPERTY_TYPES} from "../utils/constants"; import {ToscaFunction} from "./tosca-function"; +import {SubPropertyToscaFunction} from "./sub-property-tosca-function"; export class InputOperationParameter { name: string; @@ -32,8 +33,8 @@ export class InputOperationParameter { toscaDefaultValue?: string; value?: any; toscaFunction?: ToscaFunction; + subPropertyToscaFunctions: SubPropertyToscaFunction[]; valid:boolean= true; - subPropertyToscaFunctions: any; constructor(param?: any) { if (param) { diff --git a/catalog-ui/src/app/models/tosca-get-function.ts b/catalog-ui/src/app/models/tosca-get-function.ts index 784c7ea407..2eb47472da 100644 --- a/catalog-ui/src/app/models/tosca-get-function.ts +++ b/catalog-ui/src/app/models/tosca-get-function.ts @@ -71,19 +71,19 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter { private buildGetInputFunctionValue(): Object { if (this.propertyPathFromSource.length === 1) { - if (this.toscaIndexList) { - return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], this.toscaIndexList]}; + if (this.isToscaIndexEmpty()) { + return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], ...this.toscaIndexList]}; } return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0]]}; } - return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource, this.toscaIndexList]}; + return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource, ...this.toscaIndexList]}; } private buildFunctionValueWithPropertySource(): Object { if (this.propertySource == PropertySource.SELF) { - if (this.toscaIndexList) { + if (this.isToscaIndexEmpty()) { return { - [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, this.toscaIndexList] + [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, ...this.toscaIndexList] }; } return { @@ -91,9 +91,9 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter { }; } if (this.propertySource == PropertySource.INSTANCE) { - if (this.toscaIndexList) { + if (this.isToscaIndexEmpty()) { return { - [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource, this.toscaIndexList] + [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource, ...this.toscaIndexList] }; } return { @@ -101,4 +101,8 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter { }; } } + + private isToscaIndexEmpty(): boolean { + return this.toscaIndexList && this.toscaIndexList.length > 0; + } } \ No newline at end of file diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html index 88a4d6b437..c67563ebf1 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html @@ -109,6 +109,7 @@ [isViewOnly]="isViewOnly" [showToscaFunctionOption]="showToscaFunctionOption" [allowDeletion]="allowDeletion" + [componentInstanceMap]="componentInstanceMap" (onValueChange)="onPropertyValueChange($event)"> @@ -137,6 +138,7 @@ [isListChild]="true" [isViewOnly]="isViewOnly" [allowDeletion]="allowDeletion" + [componentInstanceMap]="componentInstanceMap" (onValueChange)="onPropertyValueChange($event)" (onChildListItemDelete)="onListItemDelete($event)"> @@ -169,6 +171,7 @@ [nestingLevel]="nestingLevel + 1" [isViewOnly]="isViewOnly" [allowDeletion]="allowDeletion" + [componentInstanceMap]="componentInstanceMap" (onValueChange)="onPropertyValueChange($event)" (onDelete)="onMapKeyDelete($event)"> diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts index 61708ab948..21e8363eb8 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts @@ -30,6 +30,7 @@ import {ToscaFunctionValidationEvent} from "../../../../../properties-assignment import {InstanceFeDetails} from "../../../../../../../models/instance-fe-details"; import {ToscaTypeHelper} from "app/utils/tosca-type-helper"; import {CustomToscaFunction} from "../../../../../../../models/default-custom-functions"; +import {SubPropertyToscaFunction} from "../../../../../../../models/sub-property-tosca-function"; @Component({ selector: 'app-input-list-item', @@ -49,7 +50,7 @@ export class InputListItemComponent implements OnInit { @Input() isMapChild: boolean = false; @Input() showToscaFunctionOption: boolean = false; @Input() listIndex: number; - @Input() subPropertyToscaFunctions: SubPropertyToscaFunctions[]; + @Input() subPropertyToscaFunctions: SubPropertyToscaFunction[]; @Input() isViewOnly: boolean; @Input() allowDeletion: boolean = false; @Input() toscaFunction: ToscaFunction; @@ -86,6 +87,15 @@ export class InputListItemComponent implements OnInit { } } + ngOnChanges(): void { + if (this.isToscaFunction) { + this.property.toscaFunction = this.toscaFunction; + this.valueObjRef = this.toscaFunction.value; + } else { + this.property.toscaFunction = undefined; + } + } + private initEmptyPropertyInValueObjRef(property: PropertyBEModel) { if (this.valueObjRef[property.name] == undefined) { if (this.isTypeComplex(property.type) || this.isTypeMap(property.type)) { @@ -101,18 +111,12 @@ export class InputListItemComponent implements OnInit { getToscaFunction(key: any): any { if (this.subPropertyToscaFunctions) { for (let subPropertyToscaFunction of this.subPropertyToscaFunctions) { - let found = subPropertyToscaFunction.subPropertyPath.find(value => value === key); + let found = subPropertyToscaFunction.subPropertyPath ? subPropertyToscaFunction.subPropertyPath.find(value => value === key) : false; if (found) { return subPropertyToscaFunction.toscaFunction; } } } - if ((key && this.valueObjRef[key] && this.valueObjRef[key].type)) { - const type = this.valueObjRef[key].type; - if (type in ToscaFunctionType) { - return this.valueObjRef[key]; - } - } return undefined; } @@ -347,8 +351,3 @@ export class InputListItemComponent implements OnInit { } } - -export interface SubPropertyToscaFunctions { - subPropertyPath: string[]; - toscaFunction: ToscaFunction; -} diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts index 824592f58f..53848645d7 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts @@ -29,7 +29,7 @@ import {TranslateService} from '../../../../../shared/translator/translate.servi import {ToscaFunction} from '../../../../../../models/tosca-function'; import {InstanceFeDetails} from "../../../../../../models/instance-fe-details"; import {CustomToscaFunction} from "../../../../../../models/default-custom-functions"; -import {SubPropertyToscaFunctions} from "./input-list-item/input-list-item.component"; +import {SubPropertyToscaFunction} from "../../../../../../models/sub-property-tosca-function"; @Component({selector: 'app-input-list-item', template: ''}) class InputListItemStubComponent { @@ -37,7 +37,7 @@ class InputListItemStubComponent { @Input() type: DataTypeModel; @Input() dataTypeMap: any; @Input() valueObjRef: any; - @Input() subPropertyToscaFunctions: SubPropertyToscaFunctions[]; + @Input() subPropertyToscaFunctions: SubPropertyToscaFunction[]; @Input() schema: any; @Input() allowDeletion: any; @Input() isViewOnly: boolean; diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts index 208c0030f6..62c5e8a52a 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts @@ -23,9 +23,12 @@ import {Component, EventEmitter, Input, Output} from '@angular/core'; import {InputOperationParameter} from "../../../../../../models/interfaceOperation"; import {DataTypeModel} from "../../../../../../models/data-types"; import {DerivedPropertyType} from "../../../../../../models/properties-inputs/property-be-model"; +import {SubPropertyToscaFunction} from "../../../../../../models/sub-property-tosca-function"; import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../../utils/constants"; import {InstanceFeDetails} from "../../../../../../models/instance-fe-details"; +import {ToscaFunction} from "../../../../../../models/tosca-function"; import {CustomToscaFunction} from "../../../../../../models/default-custom-functions"; +import {ToscaFunctionType} from 'app/models/tosca-function-type.enum'; @Component({ selector: 'input-list', @@ -121,6 +124,9 @@ export class InputListComponent { onValueChange($event: any) { const inputOperationParameter = this._inputs.find(input => input.name == $event.name); + if (!inputOperationParameter.subPropertyToscaFunctions) { + inputOperationParameter.subPropertyToscaFunctions = []; + } if (inputOperationParameter) { inputOperationParameter.valid = true; if ($event.isToscaFunction) { @@ -128,15 +134,44 @@ export class InputListComponent { if (!inputOperationParameter.toscaFunction) { inputOperationParameter.valid = false; } + } else if (this.isTypeComplex(inputOperationParameter.type)) { + this.setComplexType($event, inputOperationParameter); } else { inputOperationParameter.value = $event.value; inputOperationParameter.toscaFunction = null; } + } this.inputsValidityChangeEvent.emit(this._inputs.every(input => input.valid === true)); this.inputValueChangeEvent.emit(new InputOperationParameter(inputOperationParameter)); - } } + private setComplexType ($event, inputOperationParameter): void { + Object.keys($event.value).forEach(function (key) { + let value = $event.value[key]; + if (!value || value.length < 1) { + return; + } + let subPropertyToscaFunction = inputOperationParameter.subPropertyToscaFunctions.find(existingSubPropertyToscaFunction => { + const prop = existingSubPropertyToscaFunction.subPropertyPath; + return prop && [key] && prop.length === [key].length && prop.every(function(value, index) { return value === [key][index]}); + }); + let valueKeys = value instanceof Object ? Object.keys(value) : undefined; + if (value && value.type && value.type in ToscaFunctionType) { + if (!subPropertyToscaFunction){ + subPropertyToscaFunction = new SubPropertyToscaFunction(); + inputOperationParameter.subPropertyToscaFunctions.push(subPropertyToscaFunction); + } + subPropertyToscaFunction.toscaFunction = value; + $event.value[key] = (value as ToscaFunction).buildValueObject(); + let array: string[] = []; + array.push(key) + subPropertyToscaFunction.subPropertyPath = array; + } else if (subPropertyToscaFunction && (!valueKeys || !valueKeys.every(value => value.toUpperCase() in ToscaFunctionType))) { + inputOperationParameter.subPropertyToscaFunctions.splice(inputOperationParameter.subPropertyToscaFunctions.indexOf(subPropertyToscaFunction), 1) + } + }); +} + onDelete(inputName: string) { this.inputDeleteEvent.emit(inputName); } diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts index 812490c12a..4a68de26bc 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts @@ -36,7 +36,6 @@ import {DataTypeModel} from "../../../../../models/data-types"; import {InstanceFeDetails} from "../../../../../models/instance-fe-details"; import {TopologyTemplateService} from "app/ng2/services/component-services/topology-template.service"; import {CustomToscaFunction} from "../../../../../models/default-custom-functions"; -import {ToscaFunctionType} from "../../../../../models/tosca-function-type.enum"; @Component({ selector: 'operation-handler', @@ -303,9 +302,7 @@ export class InterfaceOperationHandlerComponent { const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name); inputOperationParameter.toscaFunction = null; inputOperationParameter.value = changedInput.value; - if (inputOperationParameter.subPropertyToscaFunctions) { - inputOperationParameter.subPropertyToscaFunctions = undefined; - } + inputOperationParameter.subPropertyToscaFunctions = changedInput.subPropertyToscaFunctions; if (changedInput.isToscaFunction()) { inputOperationParameter.toscaFunction = changedInput.toscaFunction; inputOperationParameter.value = changedInput.toscaFunction.buildValueString();