From bfd727385b9c55d079a5c213b425e88b88a67b7f Mon Sep 17 00:00:00 2001 From: JvD_Ericsson Date: Tue, 30 May 2023 14:57:47 +0100 Subject: [PATCH] Fix formatting error for operation input of complex type Issue-ID: SDC-4523 Signed-off-by: JvD_Ericsson Change-Id: I3dff94cee1d1dbcb26099d02505a679249a6b46e --- .../csar/YamlTemplateParsingHandler.java | 11 + .../be/tosca/InterfacesOperationsConverter.java | 129 +++++++---- .../tosca/InterfacesOperationsConverterTest.java | 258 +++++++-------------- catalog-ui/src/app/models/interfaceOperation.ts | 2 + .../input-list-item/input-list-item.component.html | 3 + .../input-list-item/input-list-item.component.ts | 25 ++ .../input-list/input-list.component.html | 1 + .../input-list/input-list.component.spec.ts | 2 + .../interface-operation-handler.component.ts | 3 + .../tosca-get-function.component.ts | 2 +- 10 files changed, 216 insertions(+), 220 deletions(-) diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java index bdb659b259..b90e3bb0b8 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java @@ -1288,12 +1288,23 @@ public class YamlTemplateParsingHandler { final OperationInputDefinition operationInput ) { if (value instanceof Map) { + final Map valueMap = (Map) value; log.debug("Creating interface operation input '{}'", inputName); Type type = new TypeToken>() { }.getType(); String stringValue = gson.toJson(value, type); if (toscaFunctionYamlParsingHandler.isPropertyValueToscaFunction(value)) { toscaFunctionYamlParsingHandler.buildToscaFunctionBasedOnPropertyValue((Map) value).ifPresent(operationInput::setToscaFunction); + } else { + final Collection subPropertyToscaFunctions = buildSubPropertyToscaFunctions(valueMap, new ArrayList<>()); + if (CollectionUtils.isNotEmpty(subPropertyToscaFunctions)) { + Collection existingSubPropertyToscaFunctions = operationInput.getSubPropertyToscaFunctions(); + if (existingSubPropertyToscaFunctions == null) { + operationInput.setSubPropertyToscaFunctions(subPropertyToscaFunctions); + } else { + operationInput.getSubPropertyToscaFunctions().addAll(subPropertyToscaFunctions); + } + } } operationInput.setValue(stringValue); } 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 8f5f271407..e56472a426 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 @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.openecomp.sdc.be.tosca; import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT; @@ -20,28 +21,35 @@ 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.ToscaGetFunctionDataDefinition; +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; @@ -82,42 +90,6 @@ public class InterfacesOperationsConverter { this.propertyConvertor = propertyConvertor; } - /** - * Creates the interface_types element. - * - * @param component to work on - * @return the added element - */ - public Map addInterfaceTypeElement(Component component, List allInterfaceTypes) { - if (component instanceof Product) { - return null; - } - final Map interfaces = component.getInterfaces(); - if (MapUtils.isEmpty(interfaces)) { - return null; - } - Map toscaInterfaceTypes = new HashMap<>(); - for (InterfaceDefinition interfaceDefinition : interfaces.values()) { - boolean isInterfaceTypeExistInGlobalType = allInterfaceTypes.stream() - .anyMatch(type -> type.equalsIgnoreCase(interfaceDefinition.getType())); - if (!isInterfaceTypeExistInGlobalType) { - ToscaInterfaceNodeType toscaInterfaceType = new ToscaInterfaceNodeType(); - toscaInterfaceType.setDerived_from(DERIVED_FROM_STANDARD_INTERFACE); - final Map operations = interfaceDefinition.getOperations(); - Map toscaOperations = new HashMap<>(); - for (Map.Entry operationEntry : operations.entrySet()) { - toscaOperations.put(operationEntry.getValue().getName(), null); - } - toscaInterfaceType.setOperations(toscaOperations); - Map interfacesAsMap = getObjectAsMap(toscaInterfaceType); - Map operationsMap = (Map) interfacesAsMap.remove(OPERATIONS.getElementName()); - interfacesAsMap.putAll(operationsMap); - toscaInterfaceTypes.put(getInterfaceType(component, LOCAL_INTERFACE_TYPE), interfacesAsMap); - } - } - return MapUtils.isNotEmpty(toscaInterfaceTypes) ? toscaInterfaceTypes : null; - } - private static Object getDefaultValue(Map inputValueMap) { Object defaultValue = null; for (Map.Entry operationEntry : inputValueMap.entrySet()) { @@ -153,11 +125,6 @@ public class InterfacesOperationsConverter { return toscaResourceName.substring(toscaResourceName.lastIndexOf(DOT) + 1); } - private boolean isArtifactPresent(final OperationDataDefinition operationDataDefinition) { - return operationDataDefinition.getImplementation() != null - && StringUtils.isNotEmpty(operationDataDefinition.getImplementation().getArtifactName()); - } - private static String getInputValue(final OperationInputDefinition input) { if (null != input.getToscaFunction()) { return input.getToscaFunction().getJsonObjectValue().toString(); @@ -173,10 +140,42 @@ 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(); @@ -207,6 +206,47 @@ public class InterfacesOperationsConverter { return objectAsMap; } + /** + * Creates the interface_types element. + * + * @param component to work on + * @return the added element + */ + public Map addInterfaceTypeElement(Component component, List allInterfaceTypes) { + if (component instanceof Product) { + return null; + } + final Map interfaces = component.getInterfaces(); + if (MapUtils.isEmpty(interfaces)) { + return null; + } + Map toscaInterfaceTypes = new HashMap<>(); + for (InterfaceDefinition interfaceDefinition : interfaces.values()) { + boolean isInterfaceTypeExistInGlobalType = allInterfaceTypes.stream() + .anyMatch(type -> type.equalsIgnoreCase(interfaceDefinition.getType())); + if (!isInterfaceTypeExistInGlobalType) { + ToscaInterfaceNodeType toscaInterfaceType = new ToscaInterfaceNodeType(); + toscaInterfaceType.setDerived_from(DERIVED_FROM_STANDARD_INTERFACE); + final Map operations = interfaceDefinition.getOperations(); + Map toscaOperations = new HashMap<>(); + for (Map.Entry operationEntry : operations.entrySet()) { + toscaOperations.put(operationEntry.getValue().getName(), null); + } + toscaInterfaceType.setOperations(toscaOperations); + Map interfacesAsMap = getObjectAsMap(toscaInterfaceType); + Map operationsMap = (Map) interfacesAsMap.remove(OPERATIONS.getElementName()); + interfacesAsMap.putAll(operationsMap); + toscaInterfaceTypes.put(getInterfaceType(component, LOCAL_INTERFACE_TYPE), interfacesAsMap); + } + } + return MapUtils.isNotEmpty(toscaInterfaceTypes) ? toscaInterfaceTypes : null; + } + + private boolean isArtifactPresent(final OperationDataDefinition operationDataDefinition) { + return operationDataDefinition.getImplementation() != null + && StringUtils.isNotEmpty(operationDataDefinition.getImplementation().getArtifactName()); + } + /** * Adds the 'interfaces' element to the node type provided. * @@ -302,9 +342,10 @@ public class InterfacesOperationsConverter { interfaceDefinitionAsMap.putAll(operationsMap); toscaInterfaceDefinitions.put(getLastPartOfName(interfaceType), interfaceDefinitionAsMap); } - + private boolean operationHasAnImplementation(OperationDataDefinition operation) { - return operation.getImplementation() != null && StringUtils.isNotEmpty(operation.getImplementation().getArtifactName()) && !operation.getImplementation().getArtifactName().equals("''"); + return operation.getImplementation() != null && StringUtils.isNotEmpty(operation.getImplementation().getArtifactName()) && + !operation.getImplementation().getArtifactName().equals("''"); } private void handleInterfaceOperationImplementation(final Component component, final ComponentInstance componentInstance, 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 b3470561f2..5158ae7945 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 @@ -19,41 +19,27 @@ package org.openecomp.sdc.be.tosca; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; 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.junit.jupiter.api.Assertions.fail; import static org.openecomp.sdc.be.tosca.InterfacesOperationsConverter.SELF; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DEFAULT; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.DESCRIPTION; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INPUTS; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.INTERFACES; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.NODE_TYPES; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.REQUIRED; -import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.TYPE; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import java.util.ArrayList; +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.function.Function; -import java.util.stream.Collectors; import org.apache.commons.collections4.MapUtils; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.onap.sdc.tosca.services.YamlUtil; import org.openecomp.sdc.be.DummyConfigurationManager; import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InputDataDefinition; @@ -68,15 +54,14 @@ import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.ServiceMetadataDefinition; import org.openecomp.sdc.be.model.tosca.ToscaType; import org.openecomp.sdc.be.tosca.model.ToscaInterfaceDefinition; import org.openecomp.sdc.be.tosca.model.ToscaNodeType; -import org.openecomp.sdc.common.util.YamlToObjectConverter; import org.openecomp.sdc.tosca.datatypes.ToscaFunctions; -import org.yaml.snakeyaml.Yaml; class InterfacesOperationsConverterTest { @@ -84,10 +69,9 @@ class InterfacesOperationsConverterTest { private static final String INPUT_NAME_PREFIX = "input_"; private static final String OUTPUT_NAME_PREFIX = "output_"; private static final String NODE_TYPE_NAME = "test"; - private final String[] inputTypes = {"string", "integer", "float", "boolean"}; - private static ObjectMapper mapper; private static final Map dataTypes = new HashMap<>(); - + private static ObjectMapper mapper; + private final String[] inputTypes = {"string", "integer", "float", "boolean"}; private InterfacesOperationsConverter interfacesOperationsConverter; @BeforeAll @@ -112,7 +96,7 @@ class InterfacesOperationsConverterTest { component.getComponentMetadataDefinition().getMetadataDataDefinition().setSystemName("NodeTypeName"); InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType("Local"); - addOperationsToInterface(component, addedInterface, 5, 3, true, false); + addOperationsToInterface(component, addedInterface, 5, 3, true, false, false); final String interfaceType = "normalizedComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -135,7 +119,7 @@ class InterfacesOperationsConverterTest { component.getComponentMetadataDefinition().getMetadataDataDefinition().setSystemName("NodeTypeName"); InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType("Local"); - addOperationsToInterface(component, addedInterface, 5, 3, true, false); + addOperationsToInterface(component, addedInterface, 5, 3, true, false, false); final String interfaceType = "normalizedServiceComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -156,7 +140,7 @@ class InterfacesOperationsConverterTest { InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType("com.some.resource.or.other.resourceName"); - addOperationsToInterface(component, addedInterface, 3, 2, true, false); + addOperationsToInterface(component, addedInterface, 3, 2, true, false, false); final String interfaceType = "normalizedComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -179,7 +163,7 @@ class InterfacesOperationsConverterTest { component.setNormalizedName("normalizedServiceComponentName"); InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType("com.some.service.or.other.serviceName"); - addOperationsToInterface(component, addedInterface, 3, 2, true, false); + addOperationsToInterface(component, addedInterface, 3, 2, true, false, false); final String interfaceType = "normalizedServiceComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -196,7 +180,6 @@ class InterfacesOperationsConverterTest { } - @Test void testGetInterfaceAsMapServiceProxy() { Component component = new Resource(); @@ -204,7 +187,7 @@ class InterfacesOperationsConverterTest { InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setToscaResourceName("com.some.resource.or.other.resourceName"); addedInterface.setType("com.some.resource.or.other.resourceName"); - addOperationsToInterface(component, addedInterface, 3, 2, true, false); + addOperationsToInterface(component, addedInterface, 3, 2, true, false, false); final String interfaceType = "normalizedComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -225,7 +208,7 @@ class InterfacesOperationsConverterTest { component.setNormalizedName("normalizedComponentName"); InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType("com.some.resource.or.other.resourceNameNoInputs"); - addOperationsToInterface(component, addedInterface, 3, 3, false, false); + addOperationsToInterface(component, addedInterface, 3, 3, false, false, false); final String interfaceType = "normalizedComponentName-interface"; component.setInterfaces(new HashMap<>()); component.getInterfaces().put(interfaceType, addedInterface); @@ -249,7 +232,7 @@ class InterfacesOperationsConverterTest { component.setNormalizedName("normalizedComponentName"); InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType(addedInterfaceType); - addOperationsToInterface(component, addedInterface, 2, 2, true, true); + addOperationsToInterface(component, addedInterface, 2, 2, true, true, false); addedInterface.getOperationsMap().values().stream() .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase( "name_for_op_0")) @@ -280,7 +263,7 @@ class InterfacesOperationsConverterTest { InterfaceDefinition addedInterface = new InterfaceDefinition(); addedInterface.setType(addedInterfaceType); addedInterface.setToscaResourceName("com.some.resource.or.other.resourceName"); - addOperationsToInterface(component, addedInterface, 2, 2, true, true); + addOperationsToInterface(component, addedInterface, 2, 2, true, true, false); addedInterface.getOperationsMap().values().stream() .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase( "name_for_op_0")) @@ -293,7 +276,7 @@ class InterfacesOperationsConverterTest { InterfaceDefinition secondInterface = new InterfaceDefinition(); secondInterface.setType(secondInterfaceType); secondInterface.setToscaResourceName("com.some.resource.or.other.resourceName"); - addOperationsToInterface(component, secondInterface, 2, 2, true, true); + addOperationsToInterface(component, secondInterface, 2, 2, true, true, false); secondInterface.getOperationsMap().values().stream() .filter(operationInputDefinition -> operationInputDefinition.getName().equalsIgnoreCase( "name_for_op_0")) @@ -408,65 +391,8 @@ class InterfacesOperationsConverterTest { assertTrue(expectedListOfStringPropValue.contains("value3")); } - - private void validateInterfaceInputs(final String yaml, final String interfaceName, final Map expectedInputMap) { - String fixedMainYaml = yaml; - final String nullString = "null"; - if (fixedMainYaml.startsWith(nullString)) { - fixedMainYaml = yaml.substring(nullString.length()); - } - if (fixedMainYaml.endsWith(nullString)) { - fixedMainYaml = fixedMainYaml.substring(0, fixedMainYaml.length() - nullString.length()); - } - final Map yamlMap = new Yaml().load(fixedMainYaml); - final Map nodeTypesMap = (Map) yamlMap.get(NODE_TYPES.getElementName()); - final Map node = (Map) nodeTypesMap.get(NODE_TYPE_NAME); - final Map interfacesMap = (Map) node.get(INTERFACES.getElementName()); - final Map interface1 = (Map) interfacesMap.get(interfaceName); - final Map actualInputsMap = (Map) interface1.get(INPUTS.getElementName()); - assertThat(actualInputsMap.keySet(), containsInAnyOrder(expectedInputMap.keySet().toArray())); - expectedInputMap.forEach((inputName, inputDataDefinition) -> { - final Map actualInput = (Map) actualInputsMap.get(inputName); - compareInputYaml(inputName, actualInput, inputDataDefinition); - }); - } - - private void compareInputYaml(final String inputName, final Map actualInput, - final InputDataDefinition expectedInput) { - final String msgFormat = "%s should be equal in input %s"; - String field = TYPE.getElementName(); - assertThat(String.format(msgFormat, field, inputName), - actualInput.get(field), equalTo(expectedInput.getType())); - field = DESCRIPTION.getElementName(); - assertThat(String.format(msgFormat, field, inputName), - actualInput.get(field), equalTo(expectedInput.getDescription())); - field = REQUIRED.getElementName(); - assertThat(String.format(msgFormat, field, inputName), - actualInput.get(field), equalTo(expectedInput.getRequired())); - field = DEFAULT.getElementName(); - assertThat(String.format(msgFormat, field, inputName), - actualInput.get(field), equalTo(expectedInput.getDefaultValue())); - } - - @FunctionalInterface - interface MainYamlAssertion extends Function { - - } - - private static Function all(MainYamlAssertion... fs) { - return s -> io.vavr.collection.List.of(fs).map(f -> f.apply(s)).fold(true, (l, r) -> l && r); - } - - private static MainYamlAssertion containsNone(String... expected) { - return s -> io.vavr.collection.List.of(expected).map(e -> !s.contains(e)).fold(true, (l, r) -> l && r); - } - - private static MainYamlAssertion containsAll(String... expected) { - return s -> io.vavr.collection.List.of(expected).map(s::contains).fold(true, (l, r) -> l && r); - } - private void addOperationsToInterface(Component component, InterfaceDefinition addedInterface, int numOfOps, - int numOfInputsPerOp, boolean hasInputs, boolean hasOutputs) { + int numOfInputsPerOp, boolean hasInputs, boolean hasOutputs, boolean addAComplexType) { addedInterface.setOperations(new HashMap<>()); for (int i = 0; i < numOfOps; i++) { @@ -477,7 +403,7 @@ class InterfacesOperationsConverterTest { implementation.setArtifactName(i + "_createBPMN.bpmn"); operation.setImplementation(implementation); if (hasInputs) { - operation.setInputs(createInputs(component, numOfInputsPerOp)); + operation.setInputs(createInputs(component, numOfInputsPerOp, addAComplexType)); } if (hasOutputs) { operation.setOutputs(createOutputs(addedInterface.getToscaResourceName(), @@ -505,8 +431,14 @@ class InterfacesOperationsConverterTest { return new InputDataDefinition(propertyDataDefinition); } - private ListDataDefinition createInputs(Component component, int numOfInputs) { + private ListDataDefinition createInputs(Component component, int numOfInputs, boolean addAComplexType) { ListDataDefinition operationInputDefinitionList = new ListDataDefinition<>(); + if (addAComplexType) { + String mappedPropertyName = java.util.UUID.randomUUID() + "." + MAPPED_PROPERTY_NAME + numOfInputs; + operationInputDefinitionList.add( + createMockComplexOperationInputDefinition(INPUT_NAME_PREFIX + "Complex" + "_" + numOfInputs, mappedPropertyName)); + numOfInputs -= 1; + } for (int i = 0; i < numOfInputs; i++) { String mappedPropertyName = java.util.UUID.randomUUID() + "." + MAPPED_PROPERTY_NAME + i; operationInputDefinitionList.add(createMockOperationInputDefinition( @@ -554,6 +486,17 @@ class InterfacesOperationsConverterTest { return operationInputDefinition; } + private OperationInputDefinition createMockComplexOperationInputDefinition(String name, String id) { + OperationInputDefinition operationInputDefinition = new OperationInputDefinition(); + operationInputDefinition.setName(name); + operationInputDefinition.setInputId(id); + operationInputDefinition.setType("complexDataType"); + operationInputDefinition.setRequired(false); + operationInputDefinition.setValue( + "{\"intProp\":1,\"stringProp\":{\"type\":\"GET_ATTRIBUTE\",\"propertyUniqueId\":\"ac4bc339-56d1-4ea2-9802-2da219a1247a.designer\",\"propertyName\":\"designer\",\"propertySource\":\"SELF\",\"sourceUniqueId\":\"ac4bc339-56d1-4ea2-9802-2da219a1247a\",\"sourceName\":\"service\",\"functionType\":\"GET_ATTRIBUTE\",\"propertyPathFromSource\":[\"designer\"]}}"); + return operationInputDefinition; + } + private OperationOutputDefinition createMockOperationOutputDefinition(String interfaceName, String operationName, String outputName, int index) { OperationOutputDefinition operationInputDefinition = new OperationOutputDefinition(); @@ -570,91 +513,6 @@ class InterfacesOperationsConverterTest { return operationInputDefinition; } - private void validateOperationInputs(final String mainYaml, int numOfInputsPerOp, String mappedOperationName) { - String nodeTypeKey = NODE_TYPE_NAME + ":"; - String nodeTypesRepresentation = mainYaml.substring(mainYaml.indexOf(nodeTypeKey) + nodeTypeKey.length(), - mainYaml.lastIndexOf(MAPPED_PROPERTY_NAME) + MAPPED_PROPERTY_NAME.length() - + String.valueOf(numOfInputsPerOp).length()); - YamlToObjectConverter objectConverter = new YamlToObjectConverter(); - ToscaNodeType toscaNodeType = objectConverter.convert(nodeTypesRepresentation.getBytes(), ToscaNodeType.class); - Map interfaces = toscaNodeType.getInterfaces(); - for (Map.Entry interfaceEntry : interfaces.entrySet()) { - Map interfaceDefinition = mapper.convertValue(interfaceEntry.getValue(), Map.class); - final Map operationsMap = interfaceDefinition.entrySet().stream() - .filter(entry -> !INPUTS.getElementName().equals(entry.getKey()) && - !TYPE.getElementName().equals(entry.getKey())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - for (Map.Entry operationEntry : operationsMap.entrySet()) { - Object operationVal = operationEntry.getValue(); - if (operationVal instanceof Map) { - //Since the inputs are mapped to output operations from only first interface so using that name - validateOperationInputDefinition(interfaces.keySet().iterator().next(), mappedOperationName, - operationVal); - } - } - } - } - - private void validateOperationInputDefinition(String interfaceType, String operationName, Object operationVal) { - Map operation = mapper.convertValue(operationVal, Map.class); - Map inputs = (Map) operation.get("inputs"); - for (Map.Entry inputEntry : inputs.entrySet()) { - String[] inputNameSplit = inputEntry.getKey().split("_"); - Map inputValueObject = (Map) inputEntry.getValue(); - validateOperationInputDefinitionDefaultValue(interfaceType, operationName, inputNameSplit[1], - Integer.parseInt(inputNameSplit[2]), inputValueObject); - } - } - - - private void validateOperationInputDefinitionDefaultValue(String interfaceType, String operationName, - String inputType, int index, - Map inputValueObject) { - if (inputValueObject.containsKey(ToscaFunctions.GET_PROPERTY.getFunctionName())) { - String mappedPropertyValue = MAPPED_PROPERTY_NAME + index; - List mappedPropertyDefaultValue = (List) inputValueObject - .get(ToscaFunctions.GET_PROPERTY.getFunctionName()); - assertEquals(2, mappedPropertyDefaultValue.size()); - assertTrue(mappedPropertyDefaultValue.contains(SELF)); - assertTrue(mappedPropertyDefaultValue.contains(mappedPropertyValue)); - } else if (inputValueObject.containsKey(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName())) { - List mappedPropertyDefaultValue = (List) inputValueObject - .get(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName()); - assertEquals(4, mappedPropertyDefaultValue.size()); - String mappedPropertyValue = OUTPUT_NAME_PREFIX + inputType + "_" + index; - assertTrue(mappedPropertyDefaultValue.contains(SELF)); - assertTrue(mappedPropertyDefaultValue.contains(interfaceType)); - assertTrue(mappedPropertyDefaultValue.contains(operationName)); - assertTrue(mappedPropertyDefaultValue.contains(mappedPropertyValue)); - } else { - fail("Invalid Tosca function in default value. Allowed values: " + ToscaFunctions.GET_PROPERTY.getFunctionName() + - "/" + ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName()); - } - } - - private void validateServiceProxyOperationInputs(String mainYaml) { - String nodeTypeKey = NODE_TYPE_NAME + ":"; - String nodeTypesRepresentation = mainYaml.substring(mainYaml.indexOf(nodeTypeKey) + nodeTypeKey.length(), - mainYaml.lastIndexOf(MAPPED_PROPERTY_NAME) + MAPPED_PROPERTY_NAME.length()); - YamlUtil yamlUtil = new YamlUtil(); - ToscaNodeType toscaNodeType = yamlUtil.yamlToObject(nodeTypesRepresentation, ToscaNodeType.class); - for (Object interfaceVal : toscaNodeType.getInterfaces().values()) { - Map interfaceDefinition = mapper.convertValue(interfaceVal, Map.class); - for (Object operationVal : interfaceDefinition.values()) { - if (operationVal instanceof Map) { - Map operation = (Map) mapper.convertValue(operationVal, Map.class); - Map operationInputs = (Map) operation.get("inputs"); - for (Object inputValue : operationInputs.values()) { - Map inputValueAsMap = (Map) inputValue; - assertFalse(inputValueAsMap.keySet().contains("type")); - assertFalse(inputValueAsMap.keySet().contains("required")); - assertFalse(inputValueAsMap.keySet().contains("default")); - } - } - } - } - } - @Test void testAddInterfaceTypeElementGetCorrectLocalInterfaceName() { Service service = new Service(); @@ -684,6 +542,56 @@ class InterfacesOperationsConverterTest { && resultMap.containsKey("NotLocal")); } + @Test + void testGetInterfaceAsMapWithComplexType() { + addComplexTypeToDataTypes(); + Component component = new Resource(); + component.setNormalizedName("normalizedComponentName"); + InterfaceDefinition addedInterface = new InterfaceDefinition(); + addedInterface.setToscaResourceName("com.some.resource.or.other.resourceName"); + addedInterface.setType("com.some.resource.or.other.resourceName"); + addOperationsToInterface(component, addedInterface, 3, 2, true, false, true); + final String interfaceType = "normalizedComponentName-interface"; + component.setInterfaces(new HashMap<>()); + component.getInterfaces().put(interfaceType, addedInterface); + final var interfacesMap = interfacesOperationsConverter.getInterfacesMap(component, null, component.getInterfaces(), dataTypes, false); + assertNotNull(interfacesMap); + assertEquals(1, interfacesMap.size()); + assertTrue(interfacesMap.containsKey("resourceName")); + Object resourceName = interfacesMap.get("resourceName"); + assertNotNull(resourceName); + assertTrue(resourceName instanceof Map); + assertEquals(4, ((Map) resourceName).size()); + assertTrue(resourceName instanceof Map); + Map resource = (Map) resourceName; + assertTrue(resource.containsKey("name_for_op_0")); + Map operation0 = (Map) resource.get("name_for_op_0"); + assertTrue(operation0.containsKey("inputs")); + Map operation0Inputs = (Map) operation0.get("inputs"); + assertTrue(operation0Inputs.containsKey("input_Complex_2")); + 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)); + } + + private void addComplexTypeToDataTypes() { + PropertyDefinition intProp = new PropertyDefinition(); + intProp.setType("integer"); + intProp.setName("intProp"); + PropertyDefinition stringProp = new PropertyDefinition(); + stringProp.setType("string"); + stringProp.setName("stringProp"); + DataTypeDefinition dataType = new DataTypeDefinition(); + dataType.setName("complexDataType"); + dataType.setProperties(new ArrayList<>(Arrays.asList(stringProp, intProp))); + dataTypes.put("complexDataType", dataType); + } + @Test void testRemoveInterfacesWithoutOperationsEmptyMap() { final Map interfaceMap = new HashMap<>(); diff --git a/catalog-ui/src/app/models/interfaceOperation.ts b/catalog-ui/src/app/models/interfaceOperation.ts index 14715b77a7..20f73af3e7 100644 --- a/catalog-ui/src/app/models/interfaceOperation.ts +++ b/catalog-ui/src/app/models/interfaceOperation.ts @@ -33,6 +33,7 @@ export class InputOperationParameter { value?: any; toscaFunction?: ToscaFunction; valid:boolean= true; + subPropertyToscaFunctions: any; constructor(param?: any) { if (param) { @@ -44,6 +45,7 @@ export class InputOperationParameter { this.value = param.value; this.toscaFunction = param.toscaFunction; this.valid = param.valid; + this.subPropertyToscaFunctions = param.subPropertyToscaFunctions; } } 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 3824d75055..88a4d6b437 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 @@ -104,6 +104,7 @@ [dataTypeMap]="dataTypeMap" [valueObjRef]="valueObjRef ? valueObjRef[property.name] : undefined" [schema]="property.schema" + [toscaFunction]="getToscaFunction(property.name)" [nestingLevel]="nestingLevel + 1" [isViewOnly]="isViewOnly" [showToscaFunctionOption]="showToscaFunctionOption" @@ -130,6 +131,7 @@ [dataTypeMap]="dataTypeMap" [valueObjRef]="valueObjRef[i]" [schema]="buildSchemaGroupProperty()" + [toscaFunction]="getToscaFunction(i)" [nestingLevel]="nestingLevel + 1" [listIndex]="i" [isListChild]="true" @@ -162,6 +164,7 @@ [dataTypeMap]="dataTypeMap" [valueObjRef]="valueObjRef[key]" [schema]="buildSchemaGroupProperty()" + [toscaFunction]="getToscaFunction(key)" [isMapChild]="true" [nestingLevel]="nestingLevel + 1" [isViewOnly]="isViewOnly" 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 103fc5c4f1..61708ab948 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 @@ -25,6 +25,7 @@ import {SchemaProperty, SchemaPropertyGroupModel} from '../../../../../../../mod import {PropertyBEModel} from '../../../../../../../models/properties-inputs/property-be-model'; import {PROPERTY_DATA, PROPERTY_TYPES} from '../../../../../../../utils/constants'; import {ToscaFunction} from '../../../../../../../models/tosca-function'; +import {ToscaFunctionType} from "../../../../../../../models/tosca-function-type.enum"; import {ToscaFunctionValidationEvent} from "../../../../../properties-assignment/tosca-function/tosca-function.component"; import {InstanceFeDetails} from "../../../../../../../models/instance-fe-details"; import {ToscaTypeHelper} from "app/utils/tosca-type-helper"; @@ -48,6 +49,7 @@ export class InputListItemComponent implements OnInit { @Input() isMapChild: boolean = false; @Input() showToscaFunctionOption: boolean = false; @Input() listIndex: number; + @Input() subPropertyToscaFunctions: SubPropertyToscaFunctions[]; @Input() isViewOnly: boolean; @Input() allowDeletion: boolean = false; @Input() toscaFunction: ToscaFunction; @@ -96,6 +98,24 @@ 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); + 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; + } + isTypeSimple(typeName: string): boolean { return ToscaTypeHelper.isTypeSimple(typeName) || this.isTypeDerivedFromSimple(typeName) && (this.isTypeWithoutProperties(typeName)); } @@ -327,3 +347,8 @@ 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.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html index d4b70f9be5..64726f1268 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html @@ -32,6 +32,7 @@ [valueObjRef]="input.value" [schema]="input.schema" [toscaFunction]="input.toscaFunction" + [subPropertyToscaFunctions]="input.subPropertyToscaFunctions" [showToscaFunctionOption]="showToscaFunctionOption" [isViewOnly]="isViewOnly" [allowDeletion]="allowDeletion" 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 3230306e68..824592f58f 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,6 +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"; @Component({selector: 'app-input-list-item', template: ''}) class InputListItemStubComponent { @@ -36,6 +37,7 @@ class InputListItemStubComponent { @Input() type: DataTypeModel; @Input() dataTypeMap: any; @Input() valueObjRef: any; + @Input() subPropertyToscaFunctions: SubPropertyToscaFunctions[]; @Input() schema: any; @Input() allowDeletion: any; @Input() isViewOnly: boolean; 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 4ceaa78148..812490c12a 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 @@ -303,6 +303,9 @@ 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; + } if (changedInput.isToscaFunction()) { inputOperationParameter.toscaFunction = changedInput.toscaFunction; inputOperationParameter.value = changedInput.toscaFunction.buildValueString(); diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts index cbbc2d98c0..07058ea069 100644 --- a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts +++ b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts @@ -125,7 +125,7 @@ export class ToscaGetFunctionComponent implements OnInit, OnChanges { this.loadPropertyDropdown(() => { this.selectedProperty .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName)); - if (this.toscaGetFunction.toscaIndexList.length > 0) { + if (this.toscaGetFunction.toscaIndexList && this.toscaGetFunction.toscaIndexList.length > 0) { let tempSelectedProperty : PropertyDropdownValue = this.selectedProperty.value; this.toscaGetFunction.toscaIndexList.forEach((indexValue: string, index) => { let tempIndexFlag = false; -- 2.16.6