diff options
author | andre.schmid <andre.schmid@est.tech> | 2022-03-07 18:48:09 +0000 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2022-03-11 16:48:13 +0000 |
commit | e5488e5e3623646125802b8ab7e12b7159a2c0d3 (patch) | |
tree | 58c896b9d2f434041cff1cafad7835dd9cd691f3 | |
parent | f13f58eb867c763e6ed1c3b674fd99b1081a0664 (diff) |
Support complex types in artifact properties
Adds support to complex types in artifact properties of an interface
operation implementation.
Change-Id: I7a82a3652541b35230fe4ce87bf703a1dbe72d50
Issue-ID: SDC-3899
Signed-off-by: andre.schmid <andre.schmid@est.tech>
16 files changed, 284 insertions, 84 deletions
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 64e61699ed..b689959572 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 @@ -22,6 +22,7 @@ import static org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum.OPERATIONS; import com.fasterxml.jackson.annotation.JsonInclude; 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.Collections; import java.util.HashMap; @@ -38,6 +39,7 @@ import org.apache.commons.lang3.math.NumberUtils; 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.model.Component; import org.openecomp.sdc.be.model.ComponentInstance; import org.openecomp.sdc.be.model.DataTypeDefinition; @@ -53,6 +55,8 @@ import org.openecomp.sdc.be.tosca.model.ToscaInterfaceOperationImplementation; import org.openecomp.sdc.be.tosca.model.ToscaLifecycleOperationDefinition; import org.openecomp.sdc.be.tosca.model.ToscaNodeType; import org.openecomp.sdc.be.tosca.model.ToscaProperty; +import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignment; +import org.openecomp.sdc.be.tosca.model.ToscaPropertyAssignmentJsonSerializer; import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil; import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum; import org.openecomp.sdc.tosca.datatypes.ToscaFunctions; @@ -147,12 +151,8 @@ public class InterfacesOperationsConverter { return toscaResourceName.substring(toscaResourceName.lastIndexOf(DOT) + 1); } - private static boolean isArtifactPresent(Map.Entry<String, OperationDataDefinition> operationEntry) { - final boolean isImplementationPresent = !Objects.isNull(operationEntry.getValue().getImplementation()); - if (isImplementationPresent) { - return !Objects.isNull(operationEntry.getValue().getImplementation().getArtifactName()); - } - return false; + private static boolean isArtifactPresent(final OperationDataDefinition operationDataDefinition) { + return operationDataDefinition.getImplementation() != null && operationDataDefinition.getImplementation().getArtifactName() != null; } private static String getInputValue(final OperationInputDefinition input) { @@ -178,13 +178,22 @@ public class InterfacesOperationsConverter { return interfaceType; } - private static Map<String, Object> getObjectAsMap(Object obj) { - ObjectMapper objectMapper = new ObjectMapper(); - if (obj instanceof ToscaInterfaceDefinition) { - //Prevent empty field serialization in interface definition - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + private static Map<String, Object> getObjectAsMap(final Object obj) { + final Map<String, Object> objectAsMap; + if (obj instanceof Map) { + objectAsMap = (Map<String, Object>) obj; + } else { + final ObjectMapper objectMapper = new ObjectMapper(); + final SimpleModule module = new SimpleModule("ToscaPropertyAssignmentSerializer"); + module.addSerializer(ToscaPropertyAssignment.class, new ToscaPropertyAssignmentJsonSerializer()); + objectMapper.registerModule(module); + if (obj instanceof ToscaInterfaceDefinition) { + //Prevent empty field serialization in interface definition + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + } + objectAsMap = objectMapper.convertValue(obj, Map.class); } - Map<String, Object> objectAsMap = obj instanceof Map ? (Map<String, Object>) obj : objectMapper.convertValue(obj, Map.class); + final String defaultEntry = DEFAULT.getElementName(); if (objectAsMap.containsKey(defaultEntry)) { objectAsMap.put(DEFAULT_HAS_UNDERSCORE, objectAsMap.remove(defaultEntry)); @@ -263,10 +272,10 @@ public class InterfacesOperationsConverter { final Map<String, Object> toscaOperationMap = new HashMap<>(); for (final Entry<String, OperationDataDefinition> operationEntry : operations.entrySet()) { final ToscaLifecycleOperationDefinition toscaLifecycleOperationDefinition = new ToscaLifecycleOperationDefinition(); - handleInterfaceOperationImplementation(component, componentInstance, isAssociatedComponent, operationEntry, - toscaLifecycleOperationDefinition); + handleInterfaceOperationImplementation(component, componentInstance, isAssociatedComponent, operationEntry.getValue(), + toscaLifecycleOperationDefinition, dataTypes); toscaLifecycleOperationDefinition.setDescription(operationEntry.getValue().getDescription()); - fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaLifecycleOperationDefinition, isServiceProxyInterface); + fillToscaOperationInputs(operationEntry.getValue(), dataTypes, toscaLifecycleOperationDefinition); toscaOperationMap.put(operationEntry.getValue().getName(), toscaLifecycleOperationDefinition); } toscaInterfaceDefinition.setOperations(toscaOperationMap); @@ -286,37 +295,56 @@ public class InterfacesOperationsConverter { private void handleInterfaceOperationImplementation(final Component component, final ComponentInstance componentInstance, final boolean isAssociatedComponent, - final Entry<String, OperationDataDefinition> operationEntry, - final ToscaLifecycleOperationDefinition toscaOperation) { + final OperationDataDefinition operationDataDefinition, + final ToscaLifecycleOperationDefinition toscaOperation, + final Map<String, DataTypeDefinition> dataTypes) { final String operationArtifactPath; final ToscaInterfaceOperationImplementation toscaInterfaceOperationImplementation = new ToscaInterfaceOperationImplementation(); toscaInterfaceOperationImplementation.setPrimary(new ToscaArtifactDefinition()); final ToscaArtifactDefinition toscaArtifactDefinition = toscaInterfaceOperationImplementation.getPrimary(); - if (isArtifactPresent(operationEntry) && StringUtils.isNotEmpty(operationEntry.getValue().getImplementation().getArtifactName())) { + if (isArtifactPresent(operationDataDefinition) && StringUtils.isNotEmpty(operationDataDefinition.getImplementation().getArtifactName())) { operationArtifactPath = OperationArtifactUtil - .createOperationArtifactPath(component, componentInstance, operationEntry.getValue(), isAssociatedComponent); + .createOperationArtifactPath(component, componentInstance, operationDataDefinition, isAssociatedComponent); toscaArtifactDefinition.setFile(operationArtifactPath); - toscaArtifactDefinition.setArtifact_version(!operationEntry.getValue().getImplementation().getArtifactVersion() - .equals(NumberUtils.INTEGER_ZERO.toString()) ? operationEntry.getValue().getImplementation().getArtifactVersion() : null); - toscaArtifactDefinition.setType(operationEntry.getValue().getImplementation().getArtifactType()); - handleInterfaceOperationImplementationProperties(operationEntry, toscaArtifactDefinition); + toscaArtifactDefinition.setArtifact_version(!operationDataDefinition.getImplementation().getArtifactVersion() + .equals(NumberUtils.INTEGER_ZERO.toString()) ? operationDataDefinition.getImplementation().getArtifactVersion() : null); + toscaArtifactDefinition.setType(operationDataDefinition.getImplementation().getArtifactType()); + final Map<String, ToscaPropertyAssignment> propertiesMap = handleImplementationProperties(operationDataDefinition, dataTypes); + if (!propertiesMap.isEmpty()) { + toscaArtifactDefinition.setProperties(propertiesMap); + } toscaOperation.setImplementation( toscaArtifactDefinition.getType() != null ? toscaInterfaceOperationImplementation : operationArtifactPath); } else { - toscaArtifactDefinition.setFile(operationEntry.getValue().getImplementation().getArtifactName()); + toscaArtifactDefinition.setFile(operationDataDefinition.getImplementation().getArtifactName()); toscaOperation.setImplementation(toscaInterfaceOperationImplementation); } } - private void handleInterfaceOperationImplementationProperties(final Entry<String, OperationDataDefinition> operationEntry, - final ToscaArtifactDefinition toscaArtifactDefinition) { - final var properties = operationEntry.getValue().getImplementation().getProperties(); - if (CollectionUtils.isNotEmpty(properties)) { - final Map<String, String> propertiesMap = new HashMap<>(); - properties.stream().filter(propertyDataDefinition -> StringUtils.isNotEmpty(propertyDataDefinition.getValue())) - .forEach(propertyDataDefinition -> propertiesMap.put(propertyDataDefinition.getName(), propertyDataDefinition.getValue())); - toscaArtifactDefinition.setProperties(propertiesMap); + private Map<String, ToscaPropertyAssignment> handleImplementationProperties(final OperationDataDefinition operationDataDefinition, + final Map<String, DataTypeDefinition> dataTypes) { + if (operationDataDefinition.getImplementation() == null) { + return new HashMap<>(); } + + final List<PropertyDataDefinition> properties = operationDataDefinition.getImplementation().getProperties(); + if (CollectionUtils.isEmpty(properties)) { + return new HashMap<>(); + } + + final Map<String, ToscaPropertyAssignment> propertiesMap = new HashMap<>(); + properties.stream() + .filter(propertyDataDefinition -> StringUtils.isNotEmpty(propertyDataDefinition.getValue())) + .forEach(propertyDataDefinition -> { + final String propertyValue = + propertyDataDefinition.getValue() != null ? propertyDataDefinition.getValue() : propertyDataDefinition.getDefaultValue(); + final ToscaPropertyAssignment toscaPropertyAssignment = new ToscaPropertyAssignment(); + toscaPropertyAssignment.setValue(propertyConvertor.convertToToscaObject(propertyDataDefinition, propertyValue, dataTypes, false)); + propertiesMap.put(propertyDataDefinition.getName(), toscaPropertyAssignment); + } + ); + + return propertiesMap; } public void removeInterfacesWithoutOperations(final Map<String, Object> interfaceMap) { @@ -373,7 +401,7 @@ public class InterfacesOperationsConverter { } private void fillToscaOperationInputs(OperationDataDefinition operation, Map<String, DataTypeDefinition> dataTypes, - ToscaLifecycleOperationDefinition toscaOperation, boolean isServiceProxyInterface) { + ToscaLifecycleOperationDefinition toscaOperation) { if (Objects.isNull(operation.getInputs()) || operation.getInputs().isEmpty()) { toscaOperation.setInputs(null); return; @@ -389,4 +417,5 @@ public class InterfacesOperationsConverter { } toscaOperation.setInputs(toscaInputs); } + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaArtifactDefinition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaArtifactDefinition.java index 689dc91d23..ac306073c1 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaArtifactDefinition.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaArtifactDefinition.java @@ -36,5 +36,6 @@ public class ToscaArtifactDefinition { private String artifact_version; private String checksum; private String checksum_algorithm; - private Map<String, String> properties; + private Map<String, ToscaPropertyAssignment> properties; + } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignmentJsonSerializer.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignmentJsonSerializer.java new file mode 100644 index 0000000000..9c695f6924 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignmentJsonSerializer.java @@ -0,0 +1,42 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2022 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.tosca.model; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.std.StdSerializer; +import java.io.IOException; + +/** + * Jackson JSON serializer for the ToscaPropertyAssignment class + */ +public class ToscaPropertyAssignmentJsonSerializer extends StdSerializer<ToscaPropertyAssignment> { + + public ToscaPropertyAssignmentJsonSerializer() { + super(ToscaPropertyAssignment.class); + } + + @Override + public void serialize(ToscaPropertyAssignment toscaPropertyAssignment, JsonGenerator gen, SerializerProvider provider) throws IOException { + gen.writeObject(toscaPropertyAssignment.getValue()); + } +}
\ No newline at end of file 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 e55a92dd0b..e3e4590d0f 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 @@ -66,6 +66,8 @@ import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; 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.enums.JsonPresentationFields; import org.openecomp.sdc.be.model.Component; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InputDefinition; @@ -73,6 +75,7 @@ import org.openecomp.sdc.be.model.InterfaceDefinition; 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.be.tosca.model.ToscaTemplate; @@ -366,10 +369,10 @@ class InterfacesOperationsConverterTest { @Test void interfaceWithInputsToscaExportTest() { final Component component = new Service(); - final InterfaceDefinition aInterfaceWithInput = new InterfaceDefinition(); + final InterfaceDefinition anInterfaceWithInput = new InterfaceDefinition(); final String interfaceName = "myInterfaceName"; final String interfaceType = "my.type." + interfaceName; - aInterfaceWithInput.setType(interfaceType); + anInterfaceWithInput.setType(interfaceType); final String input1Name = "input1"; final InputDataDefinition input1 = createInput("string", "input1 description", false, "input1 value"); final String input2Name = "input2"; @@ -377,9 +380,9 @@ class InterfacesOperationsConverterTest { final Map<String, InputDataDefinition> inputMap = new HashMap<>(); inputMap.put(input1Name, input1); inputMap.put(input2Name, input2); - aInterfaceWithInput.setInputs(inputMap); + anInterfaceWithInput.setInputs(inputMap); component.setInterfaces(new HashMap<>()); - component.getInterfaces().put(interfaceName, aInterfaceWithInput); + component.getInterfaces().put(interfaceName, anInterfaceWithInput); final ToscaNodeType nodeType = new ToscaNodeType(); interfacesOperationsConverter.addInterfaceDefinitionElement(component, nodeType, dataTypes, false); final ToscaExportHandler handler = new ToscaExportHandler(null, null, null, null, null, null, null, null, null, null, @@ -395,6 +398,62 @@ class InterfacesOperationsConverterTest { validateInterfaceInputs(toscaTemplateYaml, interfaceName, inputMap); } + @Test + void interfaceWithOperationImplementationArtifactPropertiesTest() { + //given + final Component component = new Service(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + final String interfaceName = "myInterfaceName"; + interfaceDefinition.setType("my.type." + interfaceName); + final var operation1DataDefinition = new OperationDataDefinition(); + operation1DataDefinition.setName("anOperation"); + + final PropertyDataDefinition listOfStringProperty = new PropertyDataDefinition(); + listOfStringProperty.setName("listProperty"); + listOfStringProperty.setType(ToscaType.LIST.getType()); + final PropertyDataDefinition listOfStringSchemaProperty = new PropertyDataDefinition(); + listOfStringSchemaProperty.setType(ToscaType.STRING.getType()); + final SchemaDefinition listPropertySchema = new SchemaDefinition(); + listPropertySchema.setProperty(listOfStringProperty); + listOfStringProperty.setSchema(listPropertySchema); + listOfStringProperty.setValue("[ \"value1\", \"value2\", \"value3\" ]"); + final ArrayList<Object> propertyList = new ArrayList<>(); + propertyList.add(listOfStringProperty); + final HashMap<String, Object> artifactDefinitionMapInitializer = new HashMap<>(); + artifactDefinitionMapInitializer.put(JsonPresentationFields.PROPERTIES.getPresentation(), propertyList); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(artifactDefinitionMapInitializer); + artifactDataDefinition.setArtifactName("artifact1"); + artifactDataDefinition.setArtifactType("my.artifact.Type"); + operation1DataDefinition.setImplementation(artifactDataDefinition); + interfaceDefinition.setOperations(Map.of(operation1DataDefinition.getName(), operation1DataDefinition)); + component.setInterfaces(new HashMap<>()); + component.getInterfaces().put(interfaceName, interfaceDefinition); + //when + Map<String, Object> interfacesMap = interfacesOperationsConverter + .getInterfacesMap(component, null, component.getInterfaces(), null, false, true); + //then + assertTrue(interfacesMap.containsKey(interfaceName)); + final Map<String, Object> actualInterfaceMap = (Map<String, Object>) interfacesMap.get(interfaceName); + assertTrue(actualInterfaceMap.containsKey(operation1DataDefinition.getName())); + final Map<String, Object> actualOperationMap = (Map<String, Object>) actualInterfaceMap.get(operation1DataDefinition.getName()); + assertTrue(actualOperationMap.containsKey("implementation")); + final Map<String, Object> actualImplementationMap = (Map<String, Object>) actualOperationMap.get("implementation"); + assertTrue(actualImplementationMap.containsKey("primary")); + final Map<String, Object> actualArtifactImplementationMap = (Map<String, Object>) actualImplementationMap.get("primary"); + assertTrue(actualArtifactImplementationMap.containsKey("properties")); + final Map<String, Object> actualArtifactPropertiesMap = (Map<String, Object>) actualArtifactImplementationMap.get("properties"); + assertEquals(actualArtifactPropertiesMap.keySet().size(), 1); + assertTrue(actualArtifactPropertiesMap.containsKey(listOfStringProperty.getName())); + final Object expectedListObject = actualArtifactPropertiesMap.get(listOfStringProperty.getName()); + assertTrue(expectedListObject instanceof List); + final List<String> expectedListOfStringPropValue = (List<String>) expectedListObject; + assertEquals(expectedListOfStringPropValue.size(), 3); + assertTrue(expectedListOfStringPropValue.contains("value1")); + assertTrue(expectedListOfStringPropValue.contains("value2")); + assertTrue(expectedListOfStringPropValue.contains("value3")); + } + + private void validateInterfaceInputs(final String yaml, final String interfaceName, final Map<String, InputDataDefinition> expectedInputMap) { String fixedMainYaml = yaml; final String nullString = "null"; @@ -404,7 +463,7 @@ class InterfacesOperationsConverterTest { if (fixedMainYaml.endsWith(nullString)) { fixedMainYaml = fixedMainYaml.substring(0, fixedMainYaml.length() - nullString.length()); } - final Map<String, Object> yamlMap = (Map<String, Object>) new Yaml().load(fixedMainYaml); + final Map<String, Object> yamlMap = new Yaml().load(fixedMainYaml); final Map<String, Object> nodeTypesMap = (Map<String, Object>) yamlMap.get(NODE_TYPES.getElementName()); final Map<String, Object> node = (Map<String, Object>) nodeTypesMap.get(NODE_TYPE_NAME); final Map<String, Object> interfacesMap = (Map<String, Object>) node.get(INTERFACES.getElementName()); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaListValueConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaListValueConverter.java index 4093e9d364..67894bdade 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaListValueConverter.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaListValueConverter.java @@ -32,17 +32,18 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.jetbrains.annotations.Nullable; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.common.log.wrappers.Logger; +import org.openecomp.sdc.common.util.JsonUtils; public class ToscaListValueConverter extends ToscaValueBaseConverter implements ToscaValueConverter { private static final Logger log = Logger.getLogger(ToscaListValueConverter.class.getName()); - private static ToscaListValueConverter listConverter = new ToscaListValueConverter(); - private JsonParser jsonParser = new JsonParser(); + private static final ToscaListValueConverter listConverter = new ToscaListValueConverter(); private ToscaListValueConverter() { } @@ -77,16 +78,8 @@ public class ToscaListValueConverter extends ToscaValueBaseConverter implements return value; } } - JsonElement jsonElement = null; - try { - StringReader reader = new StringReader(value); - JsonReader jsonReader = new JsonReader(reader); - jsonReader.setLenient(true); - jsonElement = jsonParser.parse(jsonReader); - } catch (JsonSyntaxException e) { - log.debug("convertToToscaValue failed to parse json value :", e); - return null; - } + JsonElement jsonElement; + jsonElement = parseToJson(value); if (jsonElement == null || jsonElement.isJsonNull()) { log.debug("convertToToscaValue json element is null"); return null; @@ -122,7 +115,6 @@ public class ToscaListValueConverter extends ToscaValueBaseConverter implements if (propertyDefinition == null) { log.debug("The property {} was not found under data type {}", propName, dataTypeDefinition.getName()); continue; - // return null; } String type = propertyDefinition.getType(); ToscaPropertyType propertyType = ToscaPropertyType.isValidType(type); @@ -132,13 +124,17 @@ public class ToscaListValueConverter extends ToscaValueBaseConverter implements ToscaValueConverter valueConverter = propertyType.getValueConverter(); convValue = valueConverter.convertToToscaValue(elementValue.getAsString(), type, dataTypes); } else { - if (ToscaPropertyType.MAP.equals(type) || ToscaPropertyType.LIST.equals(propertyType)) { - ToscaValueConverter valueConverter = propertyType.getValueConverter(); - String json = gson.toJson(elementValue); - String innerTypeRecursive = propertyDefinition.getSchema().getProperty().getType(); - convValue = valueConverter.convertToToscaValue(json, innerTypeRecursive, dataTypes); + if (JsonUtils.isEmptyJson(elementValue)) { + convValue = null; } else { - convValue = handleComplexJsonValue(elementValue); + if (ToscaPropertyType.MAP == propertyType || ToscaPropertyType.LIST == propertyType) { + ToscaValueConverter valueConverter = propertyType.getValueConverter(); + String json = gson.toJson(elementValue); + String innerTypeRecursive = propertyDefinition.getSchema().getProperty().getType(); + convValue = valueConverter.convertToToscaValue(json, innerTypeRecursive, dataTypes); + } else { + convValue = handleComplexJsonValue(elementValue); + } } } } else { @@ -158,4 +154,16 @@ public class ToscaListValueConverter extends ToscaValueBaseConverter implements return null; } } + + private JsonElement parseToJson(final String value) { + try { + final StringReader reader = new StringReader(value); + final JsonReader jsonReader = new JsonReader(reader); + jsonReader.setLenient(true); + return JsonParser.parseReader(jsonReader); + } catch (final JsonSyntaxException e) { + log.debug("convertToToscaValue failed to parse json value :", e); + return null; + } + } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java index ee254811b1..7505d2af88 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java @@ -98,12 +98,19 @@ public class ToscaValueBaseConverter { } private Map<String, Object> handleJsonObject(final JsonElement jsonElement) { - final Map<String, Object> jsonObjectAsMap = new HashMap<>(); final JsonObject jsonObject = jsonElement.getAsJsonObject(); + if (jsonObject.entrySet().isEmpty()) { + return null; + } + final Map<String, Object> jsonObjectAsMap = new HashMap<>(); for (final Entry<String, JsonElement> entry : jsonObject.entrySet()) { - jsonObjectAsMap.put(entry.getKey(), handleComplexJsonValue(entry.getValue())); + final Object value = handleComplexJsonValue(entry.getValue()); + if (value != null) { + jsonObjectAsMap.put(entry.getKey(), value); + } + } - return jsonObjectAsMap; + return jsonObjectAsMap.isEmpty() ? null : jsonObjectAsMap; } private List<Object> handleJsonArray(final JsonElement entry) { diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverterTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverterTest.java index 179d3cf7a1..5387b46dd6 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverterTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverterTest.java @@ -138,7 +138,7 @@ class ToscaValueBaseConverterTest { final Object objectProperty = jsonObjectAsMap.get("objectProperty"); assertTrue(objectProperty instanceof Map); final Map<String, Object> objectPropertyAsMap = (Map<String, Object>) objectProperty; - assertEquals(4, objectPropertyAsMap.keySet().size()); + assertEquals(3, objectPropertyAsMap.keySet().size()); assertTrue(objectPropertyAsMap.containsKey("string")); assertEquals(innerObject.get("string").getAsString(), objectPropertyAsMap.get("string")); assertEquals(innerObject.get("int").getAsInt(), objectPropertyAsMap.get("int")); 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 cd75fe87e6..7c0465f62a 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 @@ -42,6 +42,7 @@ export class InputListItemComponent implements OnInit { @Input() isMapChild: boolean = false; @Input() listIndex: number; @Input() isViewOnly: boolean; + @Input() allowDeletion: boolean = false; @Output('onValueChange') onValueChangeEvent: EventEmitter<any> = new EventEmitter<any>(); @Output('onDelete') onDeleteEvent: EventEmitter<string> = new EventEmitter<string>(); @Output('onChildListItemDelete') onChildListItemDeleteEvent: EventEmitter<number> = new EventEmitter<number>(); @@ -145,7 +146,7 @@ export class InputListItemComponent implements OnInit { } showInputDelete(): boolean { - return !this.isViewOnly && (this.isRoot() || this.isMapChild); + return this.allowDeletion && !this.isViewOnly && (this.isRoot() || this.isMapChild); } resolveType(): string { 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 802bd63838..273fc7eac1 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 @@ -19,8 +19,11 @@ ~ ============LICENSE_END========================================================= --> -<label>{{ 'INPUT_LIST_TITLE' | translate }}</label> +<label *ngIf="title">{{title}}</label> <div class="input-tree"> + <div *ngIf="!_inputs.length"> + {{emptyMessage}} + </div> <ul *ngFor="let input of _inputs"> <app-input-list-item [name]="input.name" @@ -29,6 +32,7 @@ [valueObjRef]="input.value" [schema]="input.schema" [isViewOnly]="isViewOnly" + [allowDeletion]="allowDeletion" (onValueChange)="onValueChange($event)" (onDelete)="onDelete($event)"> </app-input-list-item> 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 b07a4bb55f..99cfd21566 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 @@ -34,6 +34,7 @@ class InputListItemStubComponent { @Input() dataTypeMap: any; @Input() valueObjRef: any; @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 72812d810d..832a40e841 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 @@ -45,10 +45,13 @@ export class InputListComponent { } @Input() dataTypeMap: Map<string, DataTypeModel>; @Input() isViewOnly: boolean; + @Input() title: string; + @Input() emptyMessage: string; + @Input() allowDeletion: boolean = false; @Output('onValueChange') inputValueChangeEvent: EventEmitter<InputOperationParameter> = new EventEmitter<InputOperationParameter>(); @Output('onDelete') inputDeleteEvent: EventEmitter<string> = new EventEmitter<string>(); - _inputs: Array<InputOperationParameter>; + _inputs: Array<InputOperationParameter> = []; getDataType(type: string): DataTypeModel { return this.dataTypeMap.get(type); diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html index 46db3b94a9..ce4738a780 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html @@ -104,30 +104,27 @@ </div> </div> <div class="form-item" *ngIf="toscaArtifactTypeSelected && enableAddArtifactImplementation"> - <label class="sdc-input__label">{{ 'ENTITY_VIEWER_PROPERTIES_TAB' | translate }}</label> - <div class="generic-table"> - <div class="header-row table-row"> - <span class="cell header-cell field-input-name">{{ 'IMPLEMENTATION_ARTIFACT_PROPERTY_NAME' | translate }}</span> - <span class="cell header-cell field-input-type">{{ 'IMPLEMENTATION_ARTIFACT_PROPERTY_TYPE' | translate }}</span> - <span class="cell header-cell field-input-value">{{ 'IMPLEMENTATION_ARTIFACT_PROPERTY_VALUE' | translate }}</span> - </div> - - <div class="empty-msg data-row" *ngIf="!toscaArtifactTypeProperties.length"> - <div>{{ 'EMPTY_PARAM_TABLE_HEADER' | translate }}</div> - </div> - <property-param-row - *ngFor="let property of toscaArtifactTypeProperties" - class="data-row" - [artifactProperty]="property" - [isPropertyValueValid]="propertyValueValidation"> - </property-param-row> - </div> + <input-list + *ngIf="artifactTypeProperties && dataTypeMap" + [title]="'ARTIFACT_PROPERTY_LIST_TITLE' | translate" + [emptyMessage]="'ARTIFACT_PROPERTY_LIST_EMPTY' | translate" + [inputs]="artifactTypeProperties" + [dataTypeMap]="dataTypeMap" + [isViewOnly]="isViewOnly" + [allowDeletion]="false" + (onValueChange)="onArtifactPropertyValueChange($event)" + > + </input-list> </div> </div> <div class="group-with-border content-row" *ngIf="dataTypeMap"> <input-list - [inputs]="inputs" [dataTypeMap]="dataTypeMap" + [title]="'INPUT_LIST_TITLE' | translate" + [emptyMessage]="'INPUT_LIST_EMPTY' | translate" + [inputs]="inputs" + [dataTypeMap]="dataTypeMap" [isViewOnly]="isViewOnly" + [allowDeletion]="true" (onValueChange)="onInputValueChange($event)" (onDelete)="onInputDelete($event)" > diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less index cb47c8d167..5edf97f33c 100644 --- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less +++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less @@ -22,6 +22,9 @@ @import '../../../../../../assets/styles/override.less'; .operation-handler { + overflow: scroll; + max-height: 700px; + max-width: 100%; font-family: @font-opensans-regular; user-select: none; padding-top: 12px; @@ -221,3 +224,7 @@ } } + +.operation-handler::-webkit-scrollbar-track { + border: 0; +} 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 ed295e867c..f357ddfc54 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 @@ -66,6 +66,7 @@ export class InterfaceOperationHandlerComponent { toscaArtifactTypeSelected: string; toscaArtifactTypeProperties: Array<PropertyBEModel> = []; + artifactTypeProperties: Array<InputOperationParameter> = []; toscaArtifactTypes: Array<DropdownValue> = []; @@ -112,6 +113,7 @@ export class InterfaceOperationHandlerComponent { this.artifactVersion = this.operationToUpdate.implementation.artifactVersion; this.artifactName = this.operationToUpdate.implementation.artifactName; this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties; + this.artifactTypeProperties = this.convertArtifactsPropertiesToInput(); this.getArtifactTypesSelected(); } @@ -142,6 +144,7 @@ export class InterfaceOperationHandlerComponent { this.artifactName = undefined; } this.toscaArtifactTypeProperties = undefined; + this.artifactTypeProperties = undefined; } else { this.getArtifactTypesSelected(); } @@ -158,6 +161,7 @@ export class InterfaceOperationHandlerComponent { artifact.artifactType = toscaArtifactType.type; artifact.properties = toscaArtifactType.properties; this.toscaArtifactTypeProperties = artifact.properties; + this.artifactTypeProperties = this.convertArtifactsPropertiesToInput(); this.toscaArtifactTypeSelected = artifact.artifactType; this.operationToUpdate.implementation = artifact; this.getArtifactTypesSelected(); @@ -225,6 +229,7 @@ export class InterfaceOperationHandlerComponent { this.toscaArtifactTypeSelected = this.operationToUpdate.implementation.artifactType; this.artifactVersion = this.operationToUpdate.implementation.artifactVersion; this.toscaArtifactTypeProperties = this.operationToUpdate.implementation.properties; + this.artifactTypeProperties = this.convertArtifactsPropertiesToInput(); this.enableAddArtifactImplementation = true; } this.validateRequiredField(); @@ -272,6 +277,15 @@ export class InterfaceOperationHandlerComponent { inputOperationParameter.value = changedInput.value; } + onArtifactPropertyValueChange(changedProperty: InputOperationParameter) { + if (changedProperty.value instanceof Object) { + changedProperty.value = JSON.stringify(changedProperty.value); + } + this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name); + const property = this.toscaArtifactTypeProperties.find(artifactProperty => artifactProperty.name == changedProperty.name); + property.value = changedProperty.value; + } + /** * Handles the add input event. * @param input the input to add @@ -304,4 +318,21 @@ export class InterfaceOperationHandlerComponent { currentInputs.splice(currentInputs.indexOf(input1), 1); this.inputs = Array.from(currentInputs); } + + private convertArtifactsPropertiesToInput(): Array<InputOperationParameter> { + if (!this.toscaArtifactTypeProperties) { + return []; + } + const inputList: Array<InputOperationParameter> = []; + this.toscaArtifactTypeProperties.forEach(property => { + const input = new InputOperationParameter(); + input.name = property.name; + input.type = property.type; + input.schema = property.schema; + input.toscaDefaultValue = property.defaultValue; + input.value = property.value; + inputList.push(input); + }); + return inputList; + } } diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json index 85e2ec2141..88bd40767f 100644 --- a/catalog-ui/src/assets/languages/en_US.json +++ b/catalog-ui/src/assets/languages/en_US.json @@ -445,7 +445,10 @@ "INPUT_LIST_ADD_MAP_ENTRY": "Add Map Entry", "INPUT_LIST_ADD_LIST_ENTRY": "Add List Entry", "INPUT_LIST_TITLE": "Inputs", + "INPUT_LIST_EMPTY": "The input list is empty", "ADD_INPUT_TITLE": "New Input", + "ARTIFACT_PROPERTY_LIST_EMPTY": "The artifact type has no properties", + "ARTIFACT_PROPERTY_LIST_TITLE": "Artifact properties", "INTERFACE_OPERATION_IMPLEMENTATION": "Implementation", "INTERFACE_OPERATION_IMPLEMENTATION_NAME": "Name", "INTERFACE_OPERATION_IMPLEMENTATION_FILE": "File", diff --git a/common-app-api/src/main/java/org/openecomp/sdc/common/util/JsonUtils.java b/common-app-api/src/main/java/org/openecomp/sdc/common/util/JsonUtils.java index be534d2909..c76310ecf4 100644 --- a/common-app-api/src/main/java/org/openecomp/sdc/common/util/JsonUtils.java +++ b/common-app-api/src/main/java/org/openecomp/sdc/common/util/JsonUtils.java @@ -24,6 +24,10 @@ import com.google.gson.JsonObject; public class JsonUtils { + private JsonUtils() { + + } + public static String toString(JsonElement jsonElement) { if (jsonElement == null) { return null; @@ -48,6 +52,9 @@ public class JsonUtils { } public static boolean isEmptyJson(final JsonElement json) { + if (json == null || json.isJsonNull()) { + return true; + } if (json.isJsonArray()) { return json.getAsJsonArray().isEmpty(); } |