Support complex types in artifact properties 54/127554/4
authorandre.schmid <andre.schmid@est.tech>
Mon, 7 Mar 2022 18:48:09 +0000 (18:48 +0000)
committerMichael Morris <michael.morris@est.tech>
Fri, 11 Mar 2022 16:48:13 +0000 (16:48 +0000)
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:
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaArtifactDefinition.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/model/ToscaPropertyAssignmentJsonSerializer.java [new file with mode: 0644]
catalog-be/src/test/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverterTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaListValueConverter.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverterTest.java
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.html
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.spec.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list.component.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.less
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
catalog-ui/src/assets/languages/en_US.json
common-app-api/src/main/java/org/openecomp/sdc/common/util/JsonUtils.java

index 64e6169..b689959 100644 (file)
@@ -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);
     }
+
 }
index 689dc91..ac30607 100644 (file)
@@ -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 (file)
index 0000000..9c695f6
--- /dev/null
@@ -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
index e55a92d..e3e4590 100644 (file)
@@ -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());
index 4093e9d..67894bd 100644 (file)
@@ -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;
+        }
+    }
 }
index ee25481..7505d2a 100644 (file)
@@ -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) {
index 179d3cf..5387b46 100644 (file)
@@ -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"));
index cd75fe8..7c0465f 100644 (file)
@@ -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 {
index 802bd63..273fc7e 100644 (file)
   ~  ============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>
index 72812d8..832a40e 100644 (file)
@@ -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);
index 46db3b9..ce4738a 100644 (file)
                 </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)"
             >
index cb47c8d..5edf97f 100644 (file)
@@ -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;
 
     }
 }
+
+.operation-handler::-webkit-scrollbar-track {
+    border: 0;
+}
index ed295e8..f357ddf 100644 (file)
@@ -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;
+    }
 }
index 85e2ec2..88bd407 100644 (file)
   "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",
index be534d2..c76310e 100644 (file)
@@ -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();
         }