Support TOSCA functions in operation inputs 22/133722/16
authorfranciscovila <javier.paradela.vila@est.tech>
Tue, 21 Mar 2023 16:54:46 +0000 (16:54 +0000)
committerMichael Morris <michael.morris@est.tech>
Thu, 25 May 2023 09:26:35 +0000 (09:26 +0000)
Issue-ID: SDC-4442
Signed-off-by: franciscovila <javier.paradela.vila@est.tech>
Change-Id: I1e6135da6f41d512a7758d5494df12da874d7146

14 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/csar/YamlTemplateParsingHandler.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/AttributeConverter.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/InterfacesOperationsConverter.java
catalog-be/src/main/java/org/openecomp/sdc/be/tosca/PropertyConvertor.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceImportBusinessLogicTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaMapValueConverter.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/tosca/converters/ToscaValueBaseConverter.java
catalog-ui/src/app/models/tosca-get-function.ts
catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.html
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.ts
common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaGetFunctionType.java

index e9d5c02..bdb659b 100644 (file)
@@ -107,10 +107,13 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyFilterConstraintDataDefin
 import org.openecomp.sdc.be.datatypes.elements.SubPropertyToscaFunction;
 import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterPropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
+import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
 import org.openecomp.sdc.be.datatypes.enums.FilterValueType;
 import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType;
+import org.openecomp.sdc.be.datatypes.enums.PropertySource;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
 import org.openecomp.sdc.be.model.CapabilityDefinition;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
@@ -1272,6 +1275,7 @@ public class YamlTemplateParsingHandler {
             operationInput.setUniqueId(UUID.randomUUID().toString());
             operationInput.setInputId(operationInput.getUniqueId());
             operationInput.setName(interfaceInput.getKey());
+
             handleInputToscaDefinition(interfaceInput.getKey(), interfaceInput.getValue(), operationInput);
             inputs.add(operationInput);
         }
@@ -1288,6 +1292,9 @@ public class YamlTemplateParsingHandler {
             Type type = new TypeToken<LinkedHashMap<String, Object>>() {
             }.getType();
             String stringValue = gson.toJson(value, type);
+            if (toscaFunctionYamlParsingHandler.isPropertyValueToscaFunction(value)) {
+                toscaFunctionYamlParsingHandler.buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) value).ifPresent(operationInput::setToscaFunction);
+            }
             operationInput.setValue(stringValue);
         }
         if (value instanceof String) {
@@ -1296,6 +1303,10 @@ public class YamlTemplateParsingHandler {
             operationInput.setToscaDefaultValue(stringValue);
             operationInput.setValue(stringValue);
         }
+        operationInput.setType("string");
+        if (operationInput.getValue() == null) {
+            operationInput.setValue(String.valueOf(value));
+        }
     }
 
     private Optional<ArtifactDataDefinition> handleOperationImplementation(
index 60cc6fc..3bfa76d 100644 (file)
@@ -86,6 +86,7 @@ import org.openecomp.sdc.be.datatypes.elements.PolicyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
 import org.openecomp.sdc.be.datatypes.elements.SubPropertyToscaFunction;
 import org.openecomp.sdc.be.datatypes.elements.SubstitutionFilterPropertyDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
@@ -1847,11 +1848,12 @@ public class ServiceImportBusinessLogic {
         log.debug("************* Going to create all nodes {}", yamlName);
         handleServiceNodeTypes(yamlName, service, topologyTemplateYaml, false, nodeTypesArtifactsToCreate, nodeTypesNewCreatedArtifacts,
             nodeTypesInfo, csarInfo, nodeName);
+        List<PropertyDefinition> serviceProperties = null != service ? service.getProperties() : Collections.emptyList();
         if (MapUtils.isNotEmpty(uploadComponentInstanceInfoMap)) {
             log.debug("************* Going to create all resource instances {}", yamlName);
             service = createServiceInstances(yamlName, service, uploadComponentInstanceInfoMap, csarInfo.getCreatedNodes());
             log.debug("************* Going to create all relations {}", yamlName);
-            service = createServiceInstancesRelations(csarInfo.getModifier(), yamlName, service, uploadComponentInstanceInfoMap);
+            service = createServiceInstancesRelations(csarInfo.getModifier(), yamlName, service, uploadComponentInstanceInfoMap, serviceProperties);
             log.debug("************* Going to create positions {}", yamlName);
             compositionBusinessLogic.setPositionsForComponentInstances(service, csarInfo.getModifier().getUserId());
             log.debug("************* Finished to set positions {}", yamlName);
@@ -1860,7 +1862,8 @@ public class ServiceImportBusinessLogic {
     }
 
     protected Service createServiceInstancesRelations(User user, String yamlName, Service service,
-                                                      Map<String, UploadComponentInstanceInfo> uploadResInstancesMap) {
+                                                      Map<String, UploadComponentInstanceInfo> uploadResInstancesMap,
+                                                      List<PropertyDefinition> serviceProperties) {
         log.debug("#createResourceInstancesRelations - Going to create relations ");
         List<ComponentInstance> componentInstancesList = service.getComponentInstances();
         if (MapUtils.isEmpty(uploadResInstancesMap) || CollectionUtils.isEmpty(componentInstancesList)) { // PNF can have no resource instances
@@ -1888,6 +1891,7 @@ public class ServiceImportBusinessLogic {
             final Map<String, DataTypeDefinition> allDataTypesMap =
                 componentsUtils.getAllDataTypes(applicationDataTypeCache, service.getModel());
             final Service service1 = service;
+            service1.setProperties(serviceProperties);
             uploadResInstancesMap.values().forEach(
                 i -> processComponentInstance(yamlName, service1, componentInstancesList,
                     allDataTypesMap, instProperties,
@@ -2289,6 +2293,13 @@ public class ServiceImportBusinessLogic {
                     //Inputs
                     ListDataDefinition<OperationInputDefinition> instanceInputs = instanceOperation.getInputs();
                     mergeOperationInputDefinitions(templateOperation.getInputs(), instanceInputs);
+                    component.getProperties()
+                        .forEach(property -> instanceInputs.getListToscaDataDefinition().stream()
+                            .filter(instanceInput -> instanceInput.getToscaFunction() instanceof ToscaGetFunctionDataDefinition &&
+                                property.getName().equals(instanceInput.getToscaFunction() != null ?
+                                ((ToscaGetFunctionDataDefinition) instanceInput.getToscaFunction()).getPropertyName() : null))
+                            .forEach(oldInput -> oldInput.setType(property.getType()))
+                    );
                     templateOperation.setInputs(instanceInputs);
                     //Implementation
                     templateOperation.setImplementation(instanceOperation.getImplementation());
index 40d531d..4a98fa9 100644 (file)
@@ -148,7 +148,8 @@ public class AttributeConverter {
                 return toscaMapValueConverter.handleComplexJsonValue(valueAsJson);
             }
             //if it is a data type
-            return toscaMapValueConverter.convertDataTypeToToscaObject(innerType, dataTypes, null, false, valueAsJson, preserveEmptyValue);
+            return toscaMapValueConverter.convertDataTypeToToscaObject(innerType, dataTypes, null, false, valueAsJson,
+                preserveEmptyValue, false);
         } catch (final JsonParseException e) {
             final String errorMsg = "Failed to parse json value";
             LOGGER.error(EcompLoggerErrorCode.SCHEMA_ERROR, "Attribute Converter", errorMsg, e);
index 3650422..8f5f271 100644 (file)
@@ -41,6 +41,7 @@ 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.model.Component;
 import org.openecomp.sdc.be.model.ComponentInstance;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
@@ -158,6 +159,9 @@ public class InterfacesOperationsConverter {
     }
 
     private static String getInputValue(final OperationInputDefinition input) {
+        if (null != input.getToscaFunction()) {
+            return input.getToscaFunction().getJsonObjectValue().toString();
+        }
         String inputValue = input.getValue() == null ? input.getToscaDefaultValue() : input.getValue();
         if (inputValue != null && inputValue.contains(ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName())) {
             Gson gson = new Gson();
index d1cd495..bb89d99 100644 (file)
@@ -314,7 +314,8 @@ public class PropertyConvertor {
                 convertedValue = innerConverter.convertToToscaValue(value, innerType, dataTypes);
             } else {
                 convertedValue = mapConverterInst
-                    .convertDataTypeToToscaObject(innerType, dataTypes, innerConverter, isScalar, jsonElement, preserveEmptyValue);
+                    .convertDataTypeToToscaObject(innerType, dataTypes, innerConverter, isScalar, jsonElement, preserveEmptyValue,
+                        property.isToscaFunction());
             }
             return convertedValue;
 
index bd61fdb..cf40778 100644 (file)
@@ -1278,7 +1278,7 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest
             any(ComponentInstance.class), any(UploadReqInfo.class))).thenReturn(capabilityDefinition);
         when(componentsUtils.getResponseFormat(any(ActionStatus.class), anyString())).thenReturn(responseFormat);
         when(toscaOperationFacade.getToscaElement(anyString())).thenReturn(Either.left(service));
-        Assertions.assertNotNull(sIBL.createServiceInstancesRelations(user, yamlName, service, uploadResInstancesMap));
+        Assertions.assertNotNull(sIBL.createServiceInstancesRelations(user, yamlName, service, uploadResInstancesMap, null));
     }
 
     @Test
@@ -1289,7 +1289,7 @@ class ServiceImportBusinessLogicTest extends ServiceImportBussinessLogicBaseTest
         Map<String, UploadComponentInstanceInfo> uploadResInstancesMap = new HashMap<>();
 
         Assertions.assertThrows(ComponentException.class,
-            () -> sIBL.createServiceInstancesRelations(user, yamlName, service, uploadResInstancesMap));
+            () -> sIBL.createServiceInstancesRelations(user, yamlName, service, uploadResInstancesMap, null));
     }
 
     @Test
index af1749f..42781b2 100644 (file)
@@ -1669,10 +1669,11 @@ public class ToscaOperationFacade {
         GraphVertex vertex = getVertexEither.left().value();
         Map<String, MapInterfaceDataDefinition> instInterfacesMap = new HashMap<>();
         if (instInterfaces != null) {
-            MapInterfaceDataDefinition interfacesMap = new MapInterfaceDataDefinition();
+
             for (Map.Entry<String, Map<String, InterfaceDefinition>> entryInstances : instInterfaces.entrySet()) {
                 Map<String, InterfaceDataDefinition> incomingInterfacesMap = entryInstances.getValue().entrySet().stream()
                         .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
+                MapInterfaceDataDefinition interfacesMap = new MapInterfaceDataDefinition();
                 interfacesMap.setMapToscaDataDefinition(incomingInterfacesMap);
                 instInterfacesMap.put(entryInstances.getKey(), interfacesMap);
             }
index 5edd082..0ea7371 100644 (file)
@@ -131,12 +131,13 @@ public class ToscaMapValueConverter extends ToscaValueBaseConverter implements T
                 }
             }
         }
-        final Object convertedValue = convertDataTypeToToscaObject(propType, dataTypes, innerConverterProp, scalar, e.getValue(), false);
+        final Object convertedValue = convertDataTypeToToscaObject(propType, dataTypes, innerConverterProp, scalar, e.getValue(), false, false);
         toscaMap.put(e.getKey(), convertedValue);
     }
 
     public Object convertDataTypeToToscaObject(String innerType, Map<String, DataTypeDefinition> dataTypes, ToscaValueConverter innerConverter,
-                                               final boolean isScalarF, JsonElement entryValue, boolean preserveEmptyValue) {
+                                               final boolean isScalarF, JsonElement entryValue, boolean preserveEmptyValue,
+                                               final boolean isToscaFunction) {
         Object convertedValue;
         if (isScalarF && isJsonElementAJsonPrimitive(entryValue)) {
             return innerConverter.convertToToscaValue(entryValue.getAsString(), innerType, dataTypes);
@@ -149,25 +150,29 @@ public class ToscaMapValueConverter extends ToscaValueBaseConverter implements T
                 ArrayList<Object> toscaObjectPresentationArray = new ArrayList<>();
                 JsonArray jsonArray = entryValue.getAsJsonArray();
                 for (JsonElement jsonElement : jsonArray) {
-                    Object convertedDataTypeToToscaMap = convertDataTypeToToscaMap(innerType, dataTypes, isScalarF, jsonElement, preserveEmptyValue);
+                    Object convertedDataTypeToToscaMap = convertDataTypeToToscaMap(innerType, dataTypes, isScalarF, jsonElement, preserveEmptyValue,
+                        isToscaFunction);
                     toscaObjectPresentationArray.add(convertedDataTypeToToscaMap);
                 }
                 convertedValue = toscaObjectPresentationArray;
             } else {
-                convertedValue = convertDataTypeToToscaMap(innerType, dataTypes, isScalarF, entryValue, preserveEmptyValue);
+                convertedValue = convertDataTypeToToscaMap(innerType, dataTypes, isScalarF, entryValue, preserveEmptyValue, isToscaFunction);
             }
         }
         return convertedValue;
     }
 
     private Object convertDataTypeToToscaMap(String innerType, Map<String, DataTypeDefinition> dataTypes, final boolean isScalarF,
-                                             JsonElement entryValue, boolean preserveEmptyValue) {
+                                             JsonElement entryValue, boolean preserveEmptyValue, final boolean isToscaFunction) {
         Object convertedValue;
         if (entryValue.isJsonPrimitive()) {
             return json2JavaPrimitive(entryValue.getAsJsonPrimitive());
         }
         JsonObject asJsonObjectIn = entryValue.getAsJsonObject();
-        DataTypePropertyConverter.getInstance().mergeDataTypeDefaultValuesWithPropertyValue(asJsonObjectIn, innerType, dataTypes);
+        if (!isToscaFunction) {
+            DataTypePropertyConverter.getInstance()
+                .mergeDataTypeDefaultValuesWithPropertyValue(asJsonObjectIn, innerType, dataTypes);
+        }
         Map<String, Object> toscaObjectPresentation = new HashMap<>();
         Set<Entry<String, JsonElement>> entrySetIn = asJsonObjectIn.entrySet();
         for (Entry<String, JsonElement> entry : entrySetIn) {
index c9b5db8..e8d342a 100644 (file)
@@ -34,6 +34,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import org.apache.commons.lang3.math.NumberUtils;
 import org.openecomp.sdc.be.model.DataTypeDefinition;
 import org.openecomp.sdc.be.model.PropertyDefinition;
 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
@@ -134,10 +135,11 @@ public class ToscaValueBaseConverter {
         if (jsonPrimitive.isBoolean()) {
             return jsonPrimitive.getAsBoolean();
         }
-        if (jsonPrimitive.isString()) {
+        if (jsonPrimitive.isString() && !NumberUtils.isCreatable(jsonPrimitive.getAsString())) {
             return jsonPrimitive.getAsString();
         }
-        if (jsonPrimitive.isNumber()) {
+        if (jsonPrimitive.isNumber() ||
+            (jsonPrimitive.isString() && NumberUtils.isCreatable(jsonPrimitive.getAsString()))) {
             if (jsonPrimitive.getAsString().contains(".")) {
                 return jsonPrimitive.getAsDouble();
             }
index 67d9b0a..784c7ea 100644 (file)
@@ -71,22 +71,34 @@ export class ToscaGetFunction implements ToscaFunction, ToscaFunctionParameter {
 
     private buildGetInputFunctionValue(): Object {
         if (this.propertyPathFromSource.length === 1) {
-            return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], this.toscaIndexList]};
+            if (this.toscaIndexList) {
+                return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0], this.toscaIndexList]};
+            }
+            return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource[0]]};
         }
         return {[this.functionType.toLowerCase()]: [this.propertyPathFromSource, this.toscaIndexList]};
     }
 
     private buildFunctionValueWithPropertySource(): Object {
         if (this.propertySource == PropertySource.SELF) {
+            if (this.toscaIndexList) {
+                return {
+                    [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, this.toscaIndexList]
+                };
+            }
             return {
-                [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource, this.toscaIndexList]
+                [this.functionType.toLowerCase()]: [PropertySource.SELF, ...this.propertyPathFromSource]
             };
         }
         if (this.propertySource == PropertySource.INSTANCE) {
+            if (this.toscaIndexList) {
+                return {
+                    [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource, this.toscaIndexList]
+                };
+            }
             return {
-                [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource,this.toscaIndexList]
+                [this.functionType.toLowerCase()]: [this.sourceName, ...this.propertyPathFromSource]
             };
         }
     }
-
 }
\ No newline at end of file
index 44db3b0..3824d75 100644 (file)
                 [name]="property.name"
                 [type]="getDataType(property.type)"
                 [dataTypeMap]="dataTypeMap"
-                [valueObjRef]="valueObjRef[property.name]"
+                [valueObjRef]="valueObjRef ? valueObjRef[property.name] : undefined"
                 [schema]="property.schema"
                 [nestingLevel]="nestingLevel + 1"
                 [isViewOnly]="isViewOnly"
index 8ab1b97..cf9a04a 100644 (file)
                 [dataTypeMap]="dataTypeMap"
                 [isViewOnly]="isViewOnly"
                 [allowDeletion]="true"
+                [componentInstanceMap]="componentInstanceMap"
+                [showToscaFunctionOption]="true"
                 (onValueChange)="onInputValueChange($event)"
                 (onDelete)="onInputDelete($event)"
             >
index ab9cad0..4ceaa78 100644 (file)
@@ -138,8 +138,10 @@ export class InterfaceOperationHandlerComponent {
     private initCustomToscaFunctions() {
         this.customToscaFunctions = [];
         this.topologyTemplateService.getDefaultCustomFunction().toPromise().then((data) => {
-            for (let customFunction of data) {
-                this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+            if (data) {
+                for (let customFunction of data) {
+                    this.customToscaFunctions.push(new CustomToscaFunction(customFunction));
+                }
             }
         });
     }
@@ -299,7 +301,12 @@ export class InterfaceOperationHandlerComponent {
             changedInput.value = JSON.stringify(changedInput.value);
         }
         const inputOperationParameter = this.inputs.find(value => value.name == changedInput.name);
+        inputOperationParameter.toscaFunction = null;
         inputOperationParameter.value = changedInput.value;
+        if (changedInput.isToscaFunction()) {
+            inputOperationParameter.toscaFunction = changedInput.toscaFunction;
+            inputOperationParameter.value = changedInput.toscaFunction.buildValueString();
+        }
     }
 
     onArtifactPropertyValueChange(changedProperty: InputOperationParameter) {
@@ -345,7 +352,7 @@ export class InterfaceOperationHandlerComponent {
         const input1 = currentInputs.find(value => value.name === inputName);
         const indexOfInput = currentInputs.indexOf(input1);
         if (indexOfInput === -1) {
-            console.error(`Could delete input '${inputName}'. Input not found.`);
+            console.error(`Could not delete input '${inputName}'. Input not found.`);
             return;
         }
         currentInputs.splice(currentInputs.indexOf(input1), 1);
index d84c86a..c1895f3 100644 (file)
@@ -19,6 +19,8 @@
 
 package org.openecomp.sdc.be.datatypes.tosca;
 
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Optional;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
@@ -34,6 +36,16 @@ public enum ToscaGetFunctionType {
     private final String functionName;
     private final String propertyType;
 
+    private static final Map<String, ToscaGetFunctionType> BY_FUNCTION_NAME = new HashMap<>();
+    private static final Map<String, ToscaGetFunctionType> BY_PROPERTY_TYPE = new HashMap<>();
+
+    static {
+        for (ToscaGetFunctionType e : values()) {
+            BY_FUNCTION_NAME.put(e.functionName, e);
+            BY_PROPERTY_TYPE.put(e.propertyType, e);
+        }
+    }
+
     /**
      * Converts a {@link ToscaFunctionType} to a {@link ToscaGetFunctionType}
      * @param toscaFunctionType the tosca function type to convert
@@ -52,4 +64,12 @@ public enum ToscaGetFunctionType {
         }
     }
 
+    public static ToscaGetFunctionType valueOfFunctionName(String functionName) {
+        return BY_FUNCTION_NAME.get(functionName);
+    }
+
+    public static ToscaGetFunctionType valueOfPropertyType(String propertyType) {
+        return BY_PROPERTY_TYPE.get(propertyType);
+    }
+
 }