Support for concat TOSCA function 18/129918/3
authorandre.schmid <andre.schmid@est.tech>
Thu, 7 Jul 2022 16:17:52 +0000 (17:17 +0100)
committerMichael Morris <michael.morris@est.tech>
Mon, 18 Jul 2022 14:22:12 +0000 (14:22 +0000)
Adds support for the concat TOSCA function in an instance property.
Refactors the TOSCA function structure so it can be more generic to
support other functions in the future.

Change-Id: I338e4138d26afe21779da57c4eeb3f2d486c20a9
Issue-ID: SDC-4095
Signed-off-by: andre.schmid <andre.schmid@est.tech>
44 files changed:
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/GroupBusinessLogicNew.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ToscaFunctionExceptionSupplier.java [new file with mode: 0644]
catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ToscaGetFunctionExceptionSupplier.java
catalog-be/src/main/java/org/openecomp/sdc/be/impl/ComponentsUtils.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogicTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/GroupsOperation.java
catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/GroupsOperationTest.java
catalog-ui/src/app/models/properties-inputs/property-be-model.ts
catalog-ui/src/app/models/tosca-concat-function.ts [new file with mode: 0644]
catalog-ui/src/app/models/tosca-function-parameter.ts [new file with mode: 0644]
catalog-ui/src/app/models/tosca-function-type.enum.ts [new file with mode: 0644]
catalog-ui/src/app/models/tosca-function.ts [new file with mode: 0644]
catalog-ui/src/app/models/tosca-get-function-dto.ts
catalog-ui/src/app/models/tosca-get-function-type-converter.ts
catalog-ui/src/app/models/tosca-get-function.ts
catalog-ui/src/app/models/tosca-string-parameter.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/properties-assignment.page.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.html
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.component.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-function.module.ts
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.html [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.less [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.spec.ts [new file with mode: 0644]
catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts [new file with mode: 0644]
catalog-ui/src/app/view-models/forms/property-forms/component-property-form/property-form-view-model.ts
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CustomYamlFunction.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaConcatFunction.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunction.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializer.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionParameter.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionType.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaGetFunctionDataDefinition.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaStringParameter.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/enums/PropertySource.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/tosca/ToscaGetFunctionType.java
common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/PropertyDataDefinitionTest.java
common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializerTest.java [new file with mode: 0644]
common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaGetFunctionDataDefinitionTest.java

index 4bf8172..dcccfd9 100644 (file)
@@ -48,6 +48,7 @@ import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException;
 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
+import org.openecomp.sdc.be.components.impl.exceptions.ToscaFunctionExceptionSupplier;
 import org.openecomp.sdc.be.components.impl.exceptions.ToscaGetFunctionExceptionSupplier;
 import org.openecomp.sdc.be.components.impl.instance.ComponentInstanceChangeOperationOrchestrator;
 import org.openecomp.sdc.be.components.impl.utils.DirectivesUtil;
@@ -1960,9 +1961,14 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
                 validateMandatoryFields(property);
                 validatePropertyExistsOnComponent(property, containerComponent, foundResourceInstance);
                 String propertyParentUniqueId = property.getParentUniqueId();
-                if (property.isGetFunction()) {
-                    validateToscaGetFunction(property, containerComponent);
-                    property.setValue(property.getToscaGetFunction().generatePropertyValue());
+                if (property.isToscaFunction()) {
+                    if (property.getToscaFunction().getType() == null) {
+                        throw ToscaFunctionExceptionSupplier.missingFunctionType().get();
+                    }
+                    if (property.isToscaGetFunction()) {
+                        validateToscaGetFunction(property, containerComponent);
+                    }
+                    property.setValue(property.getToscaFunction().getValue());
                 }
                 Either<String, ResponseFormat> updatedPropertyValue = updatePropertyObjectValue(property, containerComponent.getModel());
                 if (updatedPropertyValue.isRight()) {
@@ -2297,7 +2303,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
         // Specific Update Logic
         String newValue = property.getValue();
 
-        if (property.hasGetFunction()) {
+        if (property.hasToscaFunction()) {
             return Either.left(newValue);
         }
 
@@ -2369,7 +2375,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     }
 
     private <T extends PropertyDefinition> void validateToscaGetFunction(T property, Component parentComponent) {
-        final ToscaGetFunctionDataDefinition toscaGetFunction = property.getToscaGetFunction();
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) property.getToscaFunction();
         validateGetToscaFunctionAttributes(toscaGetFunction);
         validateGetPropertySource(toscaGetFunction.getFunctionType(), toscaGetFunction.getPropertySource());
         if (toscaGetFunction.getFunctionType() == ToscaGetFunctionType.GET_INPUT) {
@@ -2407,7 +2413,7 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
     private <T extends PropertyDefinition> void validateGetFunction(final T property,
                                                                     final List<? extends ToscaPropertyData> parentProperties,
                                                                     final String model) {
-        final ToscaGetFunctionDataDefinition toscaGetFunction = property.getToscaGetFunction();
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) property.getToscaFunction();
         if (CollectionUtils.isEmpty(parentProperties)) {
             throw ToscaGetFunctionExceptionSupplier
                 .propertyNotFoundOnTarget(toscaGetFunction.getPropertyName(), toscaGetFunction.getPropertySource(),
@@ -2428,11 +2434,11 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic {
 
         if (!property.getType().equals(referredProperty.getType())) {
             throw ToscaGetFunctionExceptionSupplier
-                .propertyTypeDiverge(toscaGetFunction.getFunctionType(), referredProperty.getType(), property.getType()).get();
+                .propertyTypeDiverge(toscaGetFunction.getType(), referredProperty.getType(), property.getType()).get();
         }
         if (PropertyType.typeHasSchema(referredProperty.getType()) && !referredProperty.getSchemaType().equals(property.getSchemaType())) {
             throw ToscaGetFunctionExceptionSupplier
-                .propertySchemaDiverge(toscaGetFunction.getFunctionType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
+                .propertySchemaDiverge(toscaGetFunction.getType(), referredProperty.getSchemaType(), property.getSchemaType()).get();
         }
     }
 
index 7c01a35..e810999 100644 (file)
@@ -140,8 +140,8 @@ public class GroupBusinessLogicNew {
             if (!isOnlyGroupPropertyValueChanged(gp, originalProperties.get(updatedPropertyName))) {
                 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY, updatedPropertyName);
             }
-            if (gp.hasGetFunction()) {
-                gp.setValue(gp.getToscaGetFunction().generatePropertyValue());
+            if (gp.hasToscaFunction()) {
+                gp.setValue(gp.getToscaFunction().getValue());
             }
             if (StringUtils.isEmpty(gp.getValue())) {
                 gp.setValue(originalProperties.get(updatedPropertyName).getDefaultValue());
@@ -237,13 +237,13 @@ public class GroupBusinessLogicNew {
         groupProperty1Duplicate.setValue(null);
         groupProperty1Duplicate.setSchema(null);
         groupProperty1Duplicate.setParentUniqueId(null);
-        groupProperty1Duplicate.setToscaGetFunction(null);
+        groupProperty1Duplicate.setToscaFunction(null);
         groupProperty1Duplicate.setToscaGetFunctionType(null);
         GroupProperty groupProperty2Duplicate = new GroupProperty(groupProperty2);
         groupProperty2Duplicate.setValue(null);
         groupProperty2Duplicate.setSchema(null);
         groupProperty2Duplicate.setParentUniqueId(null);
-        groupProperty2Duplicate.setToscaGetFunction(null);
+        groupProperty2Duplicate.setToscaFunction(null);
         groupProperty2Duplicate.setToscaGetFunctionType(null);
         return StringUtils.equals(groupProperty1Duplicate.getValueUniqueUid(), groupProperty2Duplicate.getValueUniqueUid()) && groupProperty1Duplicate
             .equals(groupProperty2Duplicate);
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ToscaFunctionExceptionSupplier.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/exceptions/ToscaFunctionExceptionSupplier.java
new file mode 100644 (file)
index 0000000..2ba72ab
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * -
+ *  ============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.components.impl.exceptions;
+
+import java.util.function.Supplier;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.openecomp.sdc.be.dao.api.ActionStatus;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ToscaFunctionExceptionSupplier {
+
+    public static Supplier<ByActionStatusComponentException> missingFunctionType() {
+        return () -> new ByActionStatusComponentException(ActionStatus.TOSCA_FUNCTION_MISSING_ATTRIBUTE, "type");
+    }
+
+}
index 44d6f50..7adc937 100644 (file)
@@ -26,7 +26,7 @@ import java.util.function.Supplier;
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
 import org.openecomp.sdc.be.dao.api.ActionStatus;
-import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
 
@@ -38,6 +38,7 @@ public class ToscaGetFunctionExceptionSupplier {
         final String errorMsg = String.format("%s on %s", toscaGetFunctionType.getFunctionName(), propertySource.getName());
         return () -> new ByActionStatusComponentException(ActionStatus.NOT_SUPPORTED, errorMsg);
     }
+
     public static Supplier<ByActionStatusComponentException> propertyNotFoundOnTarget(final String propertyName,
                                                                                       final PropertySource propertySource,
                                                                                       final ToscaGetFunctionType functionType) {
@@ -106,21 +107,21 @@ public class ToscaGetFunctionExceptionSupplier {
         return () -> new ByActionStatusComponentException(ActionStatus.NOT_SUPPORTED, "Tosca function " + functionType.getFunctionName());
     }
 
-    public static Supplier<ByActionStatusComponentException> propertyTypeDiverge(final ToscaGetFunctionType functionType,
+    public static Supplier<ByActionStatusComponentException> propertyTypeDiverge(final ToscaFunctionType functionType,
                                                                                  final String referredPropertyType,
                                                                                  final String propertyType) {
         return () -> new ByActionStatusComponentException(
             ActionStatus.TOSCA_GET_FUNCTION_TYPE_DIVERGE,
-            functionType.getFunctionName(), referredPropertyType, propertyType
+            functionType.getName(), referredPropertyType, propertyType
         );
     }
 
-    public static Supplier<ByActionStatusComponentException> propertySchemaDiverge(final ToscaGetFunctionType functionType,
+    public static Supplier<ByActionStatusComponentException> propertySchemaDiverge(final ToscaFunctionType functionType,
                                                                                    final String referredPropertySchemaType,
                                                                                    final String propertySchemaType) {
         return () -> new ByActionStatusComponentException(
             ActionStatus.TOSCA_GET_FUNCTION_SCHEMA_DIVERGE,
-            functionType.getFunctionName(), referredPropertySchemaType, propertySchemaType
+            functionType.getName(), referredPropertySchemaType, propertySchemaType
         );
     }
 
index c1f45fe..7d58687 100644 (file)
@@ -83,6 +83,8 @@ import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.datamodel.utils.ConstraintConvertor;
 import org.openecomp.sdc.be.datatypes.elements.AdditionalInfoParameterInfo;
 import org.openecomp.sdc.be.datatypes.elements.RequirementNodeFilterPropertyDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionJsonDeserializer;
 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
 import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
@@ -228,6 +230,7 @@ public class ComponentsUtils {
             log.trace("convert json to object. json=\n{}", data);
             SimpleModule module = new SimpleModule("customDeserializationModule");
             module.addDeserializer(PropertyConstraint.class, new PropertyConstraintJacksonDeserializer());
+            module.addDeserializer(ToscaFunction.class, new ToscaFunctionJsonDeserializer());
             mapper.registerModule(module);
             component = mapper.readValue(data, clazz);
             if (component == null) {
index cd916d0..96c6762 100644 (file)
@@ -73,6 +73,7 @@ import org.mockito.MockitoAnnotations;
 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
+import org.openecomp.sdc.be.components.impl.exceptions.ToscaFunctionExceptionSupplier;
 import org.openecomp.sdc.be.components.impl.exceptions.ToscaGetFunctionExceptionSupplier;
 import org.openecomp.sdc.be.components.validation.UserValidations;
 import org.openecomp.sdc.be.config.ConfigurationManager;
@@ -385,7 +386,7 @@ class ComponentInstanceBusinessLogicTest {
         propertyGetInput.setType("list");
         final SchemaDefinition listStringPropertySchema = createSchema(schemaType);
         propertyGetInput.setSchema(listStringPropertySchema);
-        propertyGetInput.setToscaGetFunction(
+        propertyGetInput.setToscaFunction(
             createGetToscaFunction(inputName, inputId, List.of(propertyGetInput.getName()), PropertySource.SELF, ToscaGetFunctionType.GET_INPUT,
                 containerComponentId, containerComponentName)
         );
@@ -552,7 +553,7 @@ class ComponentInstanceBusinessLogicTest {
             componentInstanceProperty.setSchema(schemaDefinition);
         }
         if (toscaGetFunction != null) {
-            componentInstanceProperty.setToscaGetFunction(toscaGetFunction);
+            componentInstanceProperty.setToscaFunction(toscaGetFunction);
         }
 
         return componentInstanceProperty;
@@ -612,7 +613,7 @@ class ComponentInstanceBusinessLogicTest {
         final ResponseFormat actualResponse = responseFormatEither.right().value();
         final ResponseFormat expectedResponse =
             ToscaGetFunctionExceptionSupplier
-                .propertySchemaDiverge(propertyGetInput.getToscaGetFunction().getFunctionType(), inputDefinition.getSchemaType(),
+                .propertySchemaDiverge(propertyGetInput.getToscaFunction().getType(), inputDefinition.getSchemaType(),
                     propertyGetInput.getSchemaType())
                 .get().getResponseFormat();
         assertEquals(expectedResponse.getFormattedMessage(), actualResponse.getFormattedMessage());
@@ -672,7 +673,7 @@ class ComponentInstanceBusinessLogicTest {
         final ResponseFormat actualResponse = responseFormatEither.right().value();
         final ResponseFormat expectedResponse =
             ToscaGetFunctionExceptionSupplier
-                .propertyTypeDiverge(propertyGetInput.getToscaGetFunction().getFunctionType(), inputDefinition.getType(), propertyGetInput.getType())
+                .propertyTypeDiverge(propertyGetInput.getToscaFunction().getType(), inputDefinition.getType(), propertyGetInput.getType())
                 .get().getResponseFormat();
         assertEquals(expectedResponse.getFormattedMessage(), actualResponse.getFormattedMessage());
         assertEquals(expectedResponse.getStatus(), actualResponse.getStatus());
@@ -689,7 +690,7 @@ class ComponentInstanceBusinessLogicTest {
         final List<ComponentInstanceProperty> properties = new ArrayList<>();
         final ComponentInstanceProperty propertyGetInput = new ComponentInstanceProperty();
         propertyGetInput.setName("anyName");
-        propertyGetInput.setToscaGetFunction(toscaGetFunction);
+        propertyGetInput.setToscaFunction(toscaGetFunction);
         properties.add(propertyGetInput);
 
         final Component component = new Service();
@@ -2659,8 +2660,8 @@ class ComponentInstanceBusinessLogicTest {
 
     private static Stream<Arguments> getToscaFunctionForValidation() {
         final var toscaGetFunction1 = new ToscaGetFunctionDataDefinition();
-        final ResponseFormat expectedResponse1 = ToscaGetFunctionExceptionSupplier
-            .targetFunctionTypeNotFound().get().getResponseFormat();
+        final ResponseFormat expectedResponse1 = ToscaFunctionExceptionSupplier
+            .missingFunctionType().get().getResponseFormat();
 
         final var toscaGetFunction2 = new ToscaGetFunctionDataDefinition();
         toscaGetFunction2.setFunctionType(ToscaGetFunctionType.GET_INPUT);
index d20d2af..d346d93 100644 (file)
@@ -313,8 +313,7 @@ public class GroupsOperation extends BaseOperation {
                 Optional<PropertyDataDefinition> currentProp = properties.stream().filter(p -> p.getName().equals(np.getName())).findAny();
                 if (currentProp.isPresent()) {
                     currentProp.get().setValue(np.getValue());
-                    currentProp.get().setToscaGetFunction(np.getToscaGetFunction());
-                    currentProp.get().setToscaGetFunctionType(np.getToscaGetFunctionType());
+                    currentProp.get().setToscaFunction(np.getToscaFunction());
                 }
             });
             updateVersion(promoteMinorVersion, group);
index ab4e991..bb45b9b 100644 (file)
@@ -22,6 +22,8 @@ package org.openecomp.sdc.be.model.jsonjanusgraph.operations;
 
 import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import fj.data.Either;
 import java.util.List;
@@ -33,9 +35,11 @@ import org.openecomp.sdc.be.dao.config.JanusGraphSpringConfig;
 import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphDao;
 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
 import org.openecomp.sdc.be.dao.jsongraph.GraphVertex;
+import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum;
 import org.openecomp.sdc.be.model.Component;
 import org.openecomp.sdc.be.model.ComponentParametersView;
 import org.openecomp.sdc.be.model.GroupDefinition;
+import org.openecomp.sdc.be.model.GroupProperty;
 import org.openecomp.sdc.be.model.ModelTestBase;
 import org.openecomp.sdc.be.model.Resource;
 import org.openecomp.sdc.be.model.config.ModelOperationsSpringConfig;
@@ -75,7 +79,7 @@ public class GroupsOperationTest extends ModelTestBase {
     }
 
     @Test
-    public void addGroups_whenContainerHasNoGroups_associateContainerWithGroup() {
+    void addGroups_whenContainerHasNoGroups_associateContainerWithGroup() {
         GroupDefinition g1 = createGroupDefinition("g1");
         GroupDefinition g2 = createGroupDefinition("g2");
         Either<List<GroupDefinition>, StorageOperationStatus> createGroups = groupsOperation.addGroups(container, asList(g1, g2));
@@ -90,7 +94,7 @@ public class GroupsOperationTest extends ModelTestBase {
     }
 
     @Test
-    public void addGroups_whenContainerHasGroups_addTheGivenGroupsToTheGroupsList() {
+    void addGroups_whenContainerHasGroups_addTheGivenGroupsToTheGroupsList() {
         GroupDefinition g1 = createGroupDefinition("g1");
         GroupDefinition g2 = createGroupDefinition("g2");
         groupsOperation.addGroups(container, asList(g1, g2)).left().value();
@@ -109,6 +113,27 @@ public class GroupsOperationTest extends ModelTestBase {
 
     }
 
+    @Test
+    void updateGroupPropertiesOnComponent() {
+        final GroupDefinition group = createGroupDefinition("groupId");
+        final GroupProperty groupProperty1 = new GroupProperty();
+        groupProperty1.setName("property1");
+
+        final GroupProperty groupProperty2 = new GroupProperty();
+        groupProperty1.setName("property2");
+        group.setProperties(List.of(groupProperty1, groupProperty2));
+
+        final GroupProperty newProperty1 = new GroupProperty();
+        newProperty1.setName("property2");
+        final List<GroupProperty> newGroupProperties = List.of(newProperty1);
+
+        final Either<List<GroupProperty>, StorageOperationStatus> resultEither =
+            groupsOperation.updateGroupPropertiesOnComponent(CONTAINER_ID, group, newGroupProperties, PromoteVersionEnum.MINOR);
+
+        assertTrue(resultEither.isLeft());
+        assertEquals(newGroupProperties, resultEither.left().value());
+    }
+
     private GroupDefinition createGroupDefinition(String id) {
         GroupDefinition groupDefinition = new GroupDefinition();
         groupDefinition.setUniqueId(id);
index a5bf3cb..ae71413 100644 (file)
@@ -23,9 +23,10 @@ import {SchemaProperty, SchemaPropertyGroupModel} from '../schema-property';
 import {ToscaPresentationData} from '../tosca-presentation';
 import {PropertyInputDetail} from './property-input-detail';
 import {Metadata} from '../metadata';
-import {ToscaGetFunctionType} from "../tosca-get-function-type";
-import {ToscaGetFunctionDto} from '../tosca-get-function-dto';
-import {PropertySource} from '../property-source';
+import {ToscaFunction} from "../tosca-function";
+import {ToscaGetFunction} from "../tosca-get-function";
+import {ToscaGetFunctionTypeConverter} from "../tosca-get-function-type-converter";
+import {ToscaGetFunctionDto} from "../tosca-get-function-dto";
 
 export enum DerivedPropertyType {
     SIMPLE,
@@ -68,9 +69,11 @@ export class PropertyBEModel {
     inputPath: string;
     toscaPresentation: ToscaPresentationData;
     metadata: Metadata;
-    //deprecated
-    toscaGetFunctionType: ToscaGetFunctionType;
+    /**
+     * @deprecated Use toscaFunction instead
+     */
     toscaGetFunction: ToscaGetFunctionDto;
+    toscaFunction: ToscaFunction;
 
     constructor(property?: PropertyBEModel) {
         if (property) {
@@ -96,12 +99,20 @@ export class PropertyBEModel {
             this.getPolicyValues = property.getPolicyValues;
             this.inputPath = property.inputPath;
             this.metadata = property.metadata;
-            if (property.toscaGetFunction) {
-                this.toscaGetFunction = property.toscaGetFunction;
-            } else if (property.toscaGetFunctionType) {
-                this.toscaGetFunction = new ToscaGetFunctionDto();
-                this.toscaGetFunction.functionType = property.toscaGetFunctionType;
-                this.toscaGetFunction.propertySource = PropertySource.SELF;
+            if (property.toscaFunction) {
+                this.toscaFunction = property.toscaFunction;
+            } else if (property.toscaGetFunction) {
+                //support for legacy tosca function
+                const toscaGetFunction1 = new ToscaGetFunction();
+                toscaGetFunction1.type = ToscaGetFunctionTypeConverter.convertToToscaFunctionType(property.toscaGetFunction.functionType);
+                toscaGetFunction1.propertyUniqueId = property.toscaGetFunction.propertyUniqueId;
+                toscaGetFunction1.propertyName = property.toscaGetFunction.propertyName;
+                toscaGetFunction1.propertySource = property.toscaGetFunction.propertySource;
+                toscaGetFunction1.sourceUniqueId = property.toscaGetFunction.sourceUniqueId;
+                toscaGetFunction1.sourceName = property.toscaGetFunction.sourceName;
+                toscaGetFunction1.functionType = property.toscaGetFunction.functionType;
+                toscaGetFunction1.propertyPathFromSource = property.toscaGetFunction.propertyPathFromSource;
+                this.toscaFunction = toscaGetFunction1;
             }
         }
 
@@ -181,7 +192,7 @@ export class PropertyBEModel {
      * Checks whether the property value is a tosca get function (e.g. get_input, get_property, get_attribute)
      */
     public isToscaGetFunction(): boolean {
-        return this.toscaGetFunction != null;
+        return this.toscaFunction != null;
     }
 }
 
diff --git a/catalog-ui/src/app/models/tosca-concat-function.ts b/catalog-ui/src/app/models/tosca-concat-function.ts
new file mode 100644 (file)
index 0000000..9656d8d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {ToscaFunction} from "./tosca-function";
+import {ToscaFunctionType} from "./tosca-function-type.enum";
+import {ToscaFunctionParameter} from "./tosca-function-parameter";
+
+export class ToscaConcatFunction implements ToscaFunction, ToscaFunctionParameter {
+    type = ToscaFunctionType.CONCAT;
+    value: any;
+    parameters: Array<ToscaFunctionParameter> = [];
+
+    constructor(toscaConcatFunction?: ToscaConcatFunction) {
+        if (!toscaConcatFunction) {
+            return;
+        }
+        this.value = toscaConcatFunction.value;
+    }
+
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/models/tosca-function-parameter.ts b/catalog-ui/src/app/models/tosca-function-parameter.ts
new file mode 100644 (file)
index 0000000..84c4f0b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {ToscaFunctionType} from "./tosca-function-type.enum";
+
+export interface ToscaFunctionParameter {
+    type: ToscaFunctionType;
+    value: any;
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/models/tosca-function-type.enum.ts b/catalog-ui/src/app/models/tosca-function-type.enum.ts
new file mode 100644 (file)
index 0000000..116c881
--- /dev/null
@@ -0,0 +1,8 @@
+export enum ToscaFunctionType {
+    GET_INPUT = 'GET_INPUT',
+    GET_ATTRIBUTE = 'GET_ATTRIBUTE',
+    GET_PROPERTY = 'GET_PROPERTY',
+    CONCAT = 'CONCAT',
+    YAML = 'YAML',
+    STRING = 'STRING'
+}
diff --git a/catalog-ui/src/app/models/tosca-function.ts b/catalog-ui/src/app/models/tosca-function.ts
new file mode 100644 (file)
index 0000000..ebb024e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {ToscaFunctionType} from "./tosca-function-type.enum";
+
+export interface ToscaFunction {
+    type: ToscaFunctionType;
+    value: any;
+}
\ No newline at end of file
index b5ddad7..b16ae8b 100644 (file)
 
 import {ToscaGetFunctionType} from './tosca-get-function-type';
 import {PropertySource} from './property-source';
+import {ToscaFunctionType} from "./tosca-function-type.enum";
 
 export class ToscaGetFunctionDto {
+    type: ToscaFunctionType;
     propertyUniqueId: string;
     propertyName: string;
     propertySource: PropertySource;
@@ -31,46 +33,3 @@ export class ToscaGetFunctionDto {
     functionType: ToscaGetFunctionType;
     propertyPathFromSource: Array<string>;
 }
-
-export class ToscaGetFunctionDtoBuilder {
-    toscaGetFunctionDto: ToscaGetFunctionDto = new ToscaGetFunctionDto();
-
-    withPropertyUniqueId(propertyUniqueId: string): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.propertyUniqueId = propertyUniqueId;
-        return this;
-    }
-
-    withPropertyName(propertyName: string): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.propertyName = propertyName;
-        return this;
-    }
-
-    withPropertySource(propertySource: PropertySource): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.propertySource = propertySource;
-        return this;
-    }
-
-    withSourceUniqueId(sourceUniqueId: string): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.sourceUniqueId = sourceUniqueId;
-        return this;
-    }
-
-    withSourceName(sourceName: string): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.sourceName = sourceName;
-        return this;
-    }
-
-    withFunctionType(functionType: ToscaGetFunctionType): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.functionType = functionType;
-        return this;
-    }
-
-    withPropertyPathFromSource(propertyPathFromSource: Array<string>): ToscaGetFunctionDtoBuilder {
-        this.toscaGetFunctionDto.propertyPathFromSource = propertyPathFromSource;
-        return this;
-    }
-
-    build(): ToscaGetFunctionDto {
-        return this.toscaGetFunctionDto;
-    }
-}
index 0447c4b..ad3385a 100644 (file)
  */
 
 import {ToscaGetFunctionType} from './tosca-get-function-type';
+import {ToscaFunctionType} from "./tosca-function-type.enum";
 
 export class ToscaGetFunctionTypeConverter {
 
-  static convertFromString(toscaGetFunction: string): ToscaGetFunctionType {
-    if (!toscaGetFunction) {
-      return;
-    }
+    static convertFromString(toscaGetFunction: string): ToscaGetFunctionType {
+        if (!toscaGetFunction) {
+            return;
+        }
 
-    if (ToscaGetFunctionType.GET_INPUT === toscaGetFunction.toUpperCase()) {
-      return ToscaGetFunctionType.GET_INPUT;
-    }
+        if (ToscaGetFunctionType.GET_INPUT === toscaGetFunction.toUpperCase()) {
+            return ToscaGetFunctionType.GET_INPUT;
+        }
 
-    if (ToscaGetFunctionType.GET_PROPERTY === toscaGetFunction.toUpperCase()) {
-      return ToscaGetFunctionType.GET_PROPERTY;
-    }
+        if (ToscaGetFunctionType.GET_PROPERTY === toscaGetFunction.toUpperCase()) {
+            return ToscaGetFunctionType.GET_PROPERTY;
+        }
+
+        if (ToscaGetFunctionType.GET_ATTRIBUTE === toscaGetFunction.toUpperCase()) {
+            return ToscaGetFunctionType.GET_ATTRIBUTE;
+        }
+
+        return undefined;
 
-    if (ToscaGetFunctionType.GET_ATTRIBUTE === toscaGetFunction.toUpperCase()) {
-      return ToscaGetFunctionType.GET_ATTRIBUTE;
     }
 
-    return undefined;
+    /**
+     * Converts a ToscaGetFunctionType to a ToscaFunctionType
+     * @param toscaGetFunctionType
+     */
+    static convertToToscaFunctionType(toscaGetFunctionType: ToscaGetFunctionType): ToscaFunctionType {
+        switch (toscaGetFunctionType) {
+            case ToscaGetFunctionType.GET_INPUT:
+                return ToscaFunctionType.GET_INPUT;
+            case ToscaGetFunctionType.GET_ATTRIBUTE:
+                return ToscaFunctionType.GET_ATTRIBUTE;
+            case ToscaGetFunctionType.GET_PROPERTY:
+                return ToscaFunctionType.GET_PROPERTY;
+            default:
+                return undefined;
+        }
 
-  }
+    }
 
 }
index 97497fc..2386338 100644 (file)
 
 import {PropertySource} from "./property-source";
 import {ToscaGetFunctionType} from "./tosca-get-function-type";
+import {ToscaFunction} from "./tosca-function";
+import {ToscaFunctionType} from "./tosca-function-type.enum";
 
-export class ToscaGetFunction {
+export class ToscaGetFunction implements ToscaFunction {
+    type: ToscaFunctionType;
     propertyUniqueId: string;
     propertyName: string;
     propertySource: PropertySource;
@@ -30,6 +33,7 @@ export class ToscaGetFunction {
     sourceName: string;
     functionType: ToscaGetFunctionType;
     propertyPathFromSource: Array<string>;
+    value: any
 
     constructor(toscaGetFunction?: ToscaGetFunction) {
         if (!toscaGetFunction) {
@@ -45,4 +49,5 @@ export class ToscaGetFunction {
             this.propertyPathFromSource = [...toscaGetFunction.propertyPathFromSource];
         }
     }
+
 }
\ No newline at end of file
diff --git a/catalog-ui/src/app/models/tosca-string-parameter.ts b/catalog-ui/src/app/models/tosca-string-parameter.ts
new file mode 100644 (file)
index 0000000..0f74235
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {ToscaFunctionParameter} from "./tosca-function-parameter";
+import {ToscaFunctionType} from "./tosca-function-type.enum";
+
+export class ToscaStringParameter implements ToscaFunctionParameter {
+    type: ToscaFunctionType = ToscaFunctionType.STRING;
+    value: string;
+}
\ No newline at end of file
index 9f721d5..2ae5ce8 100644 (file)
@@ -61,13 +61,12 @@ import {UnsavedChangesComponent} from "app/ng2/components/ui/forms/unsaved-chang
 import {PropertyCreatorComponent} from "./property-creator/property-creator.component";
 import {ModalService} from "../../services/modal.service";
 import {DeclareListComponent} from "./declare-list/declare-list.component";
-import {ToscaFunctionComponent} from "./tosca-function/tosca-function.component";
+import {ToscaFunctionComponent, ToscaFunctionValidationEvent} from "./tosca-function/tosca-function.component";
 import {CapabilitiesGroup, Capability} from "../../../models/capability";
 import {ToscaPresentationData} from "../../../models/tosca-presentation";
 import {Observable} from "rxjs";
 import {TranslateService} from "../../shared/translator/translate.service";
-import {ToscaGetFunctionDtoBuilder} from '../../../models/tosca-get-function-dto';
-import {ToscaGetFunction} from "../../../models/tosca-get-function";
+import {ToscaFunction} from "../../../models/tosca-function";
 
 const SERVICE_SELF_TITLE = "SELF";
 @Component({
@@ -539,36 +538,37 @@ export class PropertiesAssignmentComponent {
         const modalTitle = this.translateService.translate('TOSCA_FUNCTION_MODAL_TITLE');
         const modalButtons = [];
         let disableSaveButtonFlag = true;
+        const modal = this.modalService.createCustomModal(new ModalModel(
+            'sm',
+            modalTitle,
+            null,
+            modalButtons,
+            null /* type */
+        ));
         modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_SAVE'), 'blue',
             () => {
-                const toscaGetFunction: ToscaGetFunction = modal.instance.dynamicContent.instance.toscaGetFunction;
-                if (toscaGetFunction.functionType) {
-                    this.updateCheckedInstancePropertyGetFunctionValue(toscaGetFunction);
+                const toscaGetFunction: ToscaFunction = modal.instance.dynamicContent.instance.toscaFunctionForm.value;
+                if (toscaGetFunction) {
+                    this.updateCheckedInstancePropertyFunctionValue(toscaGetFunction);
                 } else {
                     this.clearCheckedInstancePropertyValue();
                 }
-                modal.instance.close();
+                this.modalService.closeCurrentModal();
             },
             (): boolean => { return disableSaveButtonFlag }
         ));
         const checkedInstanceProperty = this.buildCheckedInstanceProperty();
         modalButtons.push(new ButtonModel(this.translateService.translate('MODAL_CANCEL'), 'outline grey', () => {
-            modal.instance.close();
+            this.modalService.closeCurrentModal();
         }));
-        const modal = this.modalService.createCustomModal(new ModalModel(
-            'sm',
-            modalTitle,
-            null,
-            modalButtons,
-            null /* type */
-        ));
+
 
         this.modalService.addDynamicContentToModalAndBindInputs(modal, ToscaFunctionComponent, {
             'property': checkedInstanceProperty,
             'componentInstanceMap': this.componentInstanceMap
         });
-        modal.instance.dynamicContent.instance.onValidityChange.subscribe(isValid => {
-            disableSaveButtonFlag = !isValid;
+        modal.instance.dynamicContent.instance.onValidityChange.subscribe((validationEvent: ToscaFunctionValidationEvent) => {
+            disableSaveButtonFlag = !validationEvent.isValid;
         });
         modal.instance.open();
     }
@@ -577,23 +577,13 @@ export class PropertiesAssignmentComponent {
         const checkedInstanceProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
         checkedInstanceProperty.getInputValues = null;
         checkedInstanceProperty.value = null;
-        checkedInstanceProperty.toscaGetFunction = null;
+        checkedInstanceProperty.toscaFunction = null;
         this.updateInstanceProperty(checkedInstanceProperty);
     }
 
-    private updateCheckedInstancePropertyGetFunctionValue(toscaGetFunction: ToscaGetFunction) {
-        const toscaGetFunctionBuilder: ToscaGetFunctionDtoBuilder =
-            new ToscaGetFunctionDtoBuilder()
-                .withPropertyUniqueId(toscaGetFunction.propertyUniqueId)
-                .withFunctionType(toscaGetFunction.functionType)
-                .withPropertySource(toscaGetFunction.propertySource)
-                .withPropertyName(toscaGetFunction.propertyName)
-                .withSourceName(toscaGetFunction.sourceName)
-                .withSourceUniqueId(toscaGetFunction.sourceUniqueId)
-                .withPropertyPathFromSource(toscaGetFunction.propertyPathFromSource);
-
+    private updateCheckedInstancePropertyFunctionValue(toscaFunction: ToscaFunction) {
         const checkedProperty: PropertyBEModel = this.buildCheckedInstanceProperty();
-        checkedProperty.toscaGetFunction = toscaGetFunctionBuilder.build();
+        checkedProperty.toscaFunction = toscaFunction;
         this.updateInstanceProperty(checkedProperty);
     }
 
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.html
new file mode 100644 (file)
index 0000000..6320058
--- /dev/null
@@ -0,0 +1,48 @@
+<!--
+  ~ -
+  ~  ============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=========================================================
+  -->
+
+<div class="component-container">
+  <ng-container [formGroup]="formGroup">
+    <div formArrayName="concatParameterList">
+      <div *ngFor="let parameter of parameters; let idx = index">
+        <div *ngIf="idx > 0" class="text-center"><span class="concat-plus-icon"></span></div>
+        <div class="parameter-card">
+          <div class="card-content">
+            <ng-container *ngIf="parameter.type === STRING_FUNCTION_TYPE">
+              <input type="text" [formControlName]="idx" [value]="parameter.value"/><br/>
+            </ng-container>
+            <ng-container *ngIf="parameter.type !== STRING_FUNCTION_TYPE">
+              <tosca-function [property]="propertyInputList[idx]" [componentInstanceMap]="componentInstanceMap" [allowClear]="false"
+                              (onValidityChange)="onFunctionValidityChange($event, idx)">
+              </tosca-function>
+            </ng-container>
+            <div class="buttons-container">
+              <span class="delete-icon" (click)="removeParameter(idx)"></span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </ng-container>
+  <div class="buttons-container">
+    <a class="add-link" (click)="addStringParameter()">String Value</a> <a class="add-link" (click)="addFunction()">String Value Expression</a>
+  </div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.less
new file mode 100644 (file)
index 0000000..b9c5983
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+@import "../../../../../../assets/styles/mixins.less";
+@import "../../../../../../assets/styles/sprite.less";
+
+.component-container {
+    max-height: 500px;
+    overflow: scroll;
+    padding: 0 5px;
+    &::-webkit-scrollbar-track {
+        border: 0;
+    }
+}
+
+.buttons-container {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    gap: 10px;
+    margin-bottom: 10px;
+
+    .add-link {
+        .f-color.a();
+        .f-type._14_m();
+        cursor: pointer;
+
+        &:before {
+            .sprite-new();
+            .plus-icon();
+            margin-right: 5px;
+            content: "";
+        }
+
+        &:hover {
+            .f-color.b();
+            &:before {
+                .sprite-new();
+                .plus-icon-hover();
+            }
+        }
+    }
+
+    .delete-icon {
+        .sprite-new();
+        .delete-btn();
+        cursor: pointer;
+    }
+}
+
+.parameter-card {
+    border: 2px solid @main_color_o;
+    box-shadow: 0 0 0 0 rgba(0,0,0,0.2);
+    //padding: 10px;
+    border-radius: 2px;
+    transition: 0.3s;
+    margin-bottom: 5px;
+    &:hover {
+        box-shadow: 0 1px 8px 2px rgba(0,0,0,0.2);
+    }
+
+    .card-content {
+        padding: 5px 10px;
+    }
+
+    .text-center {
+        text-align: center;
+    }
+
+    input {
+        border: solid 1px @main_color_o;
+    }
+}
+
+.concat-plus-icon {
+    .sprite-new();
+    background-position: -216px -1388px;
+    width: 14px;
+    height: 14px;
+}
\ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.spec.ts
new file mode 100644 (file)
index 0000000..5c9af47
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {ToscaConcatFunctionComponent} from './tosca-concat-function.component';
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {ToscaFunctionComponent} from "../tosca-function.component";
+import {TranslateModule} from "../../../../shared/translator/translate.module";
+import {ToscaGetFunctionComponent} from "../tosca-get-function/tosca-get-function.component";
+import {UiElementsModule} from "../../../../components/ui/ui-elements.module";
+
+describe('ToscaConcatFunctionComponent', () => {
+    let component: ToscaConcatFunctionComponent;
+    let fixture: ComponentFixture<ToscaConcatFunctionComponent>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            declarations: [ToscaConcatFunctionComponent, ToscaFunctionComponent, ToscaGetFunctionComponent],
+            imports: [
+                FormsModule,
+                ReactiveFormsModule,
+                TranslateModule,
+                UiElementsModule
+            ]
+        })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ToscaConcatFunctionComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-concat-function/tosca-concat-function.component.ts
new file mode 100644 (file)
index 0000000..d808c28
--- /dev/null
@@ -0,0 +1,140 @@
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {FormArray, FormControl, FormGroup, Validators} from "@angular/forms";
+import {ToscaConcatFunction} from "../../../../../models/tosca-concat-function";
+import {ToscaFunctionParameter} from "../../../../../models/tosca-function-parameter";
+import {ToscaStringParameter} from "../../../../../models/tosca-string-parameter";
+import {ToscaFunctionType} from "../../../../../models/tosca-function-type.enum";
+import {PropertyBEModel} from "../../../../../models/properties-inputs/property-be-model";
+import {PROPERTY_TYPES} from "../../../../../utils/constants";
+import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
+import {ToscaFunctionValidationEvent} from "../tosca-function.component";
+
+@Component({
+    selector: 'app-tosca-concat-function',
+    templateUrl: './tosca-concat-function.component.html',
+    styleUrls: ['./tosca-concat-function.component.less']
+})
+export class ToscaConcatFunctionComponent implements OnInit {
+
+    @Input() toscaConcatFunction: ToscaConcatFunction;
+    @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    @Output() onValidFunction: EventEmitter<ToscaConcatFunction> = new EventEmitter<ToscaConcatFunction>();
+    @Output() onValidityChange: EventEmitter<ToscaConcatFunctionValidationEvent> = new EventEmitter<ToscaConcatFunctionValidationEvent>();
+
+    concatParameterFormArray: FormArray = new FormArray([], Validators.minLength(2));
+    formGroup: FormGroup = new FormGroup(
+        {
+            'concatParameterList': this.concatParameterFormArray
+        }
+    );
+
+    parameters: ToscaFunctionParameter[] = [];
+    propertyInputList: Array<PropertyBEModel> = [];
+
+    stringProperty: PropertyBEModel
+
+    STRING_FUNCTION_TYPE = ToscaFunctionType.STRING
+
+    constructor() {
+        this.stringProperty = new PropertyBEModel();
+        this.stringProperty.type = PROPERTY_TYPES.STRING
+    }
+
+    ngOnInit() {
+        this.initForm();
+    }
+
+    private initForm() {
+        this.formGroup.valueChanges.subscribe(() => {
+            this.onValidityChange.emit({
+                isValid: this.formGroup.valid,
+                toscaConcatFunction: this.formGroup.valid ? this.buildConcatFunctionFromForm() : undefined
+            })
+            if (this.formGroup.valid) {
+                this.onValidFunction.emit(this.buildConcatFunctionFromForm());
+            }
+        });
+        if (!this.toscaConcatFunction) {
+            return;
+        }
+
+        if (this.toscaConcatFunction.parameters) {
+            this.parameters = Array.from(this.toscaConcatFunction.parameters);
+            for (const parameter of this.parameters) {
+                if (parameter.type !== PROPERTY_TYPES.STRING) {
+                    this.propertyInputList.push(this.createStringProperty(parameter));
+                    this.concatParameterFormArray.push(
+                        new FormControl(parameter, [Validators.required, Validators.minLength(1)])
+                    );
+                } else {
+                    this.propertyInputList.push(undefined);
+                    this.concatParameterFormArray.push(
+                        new FormControl(parameter.value, [Validators.required, Validators.minLength(1)])
+                    );
+                }
+            }
+        }
+    }
+
+    private buildConcatFunctionFromForm(): ToscaConcatFunction {
+        const toscaConcatFunction1 = new ToscaConcatFunction();
+        this.concatParameterFormArray.controls.forEach(control => {
+            const value = control.value;
+            if (typeof value === 'string') {
+                const stringParameter = new ToscaStringParameter();
+                stringParameter.value = value;
+                toscaConcatFunction1.parameters.push(stringParameter);
+            } else {
+                toscaConcatFunction1.parameters.push(control.value);
+            }
+        });
+
+        return toscaConcatFunction1;
+    }
+
+    addFunction() {
+        this.propertyInputList.push(this.createStringProperty());
+        this.parameters.push({} as ToscaFunctionParameter);
+        this.concatParameterFormArray.push(
+            new FormControl(undefined, [Validators.required, Validators.minLength(1)])
+        );
+    }
+
+    addStringParameter() {
+        this.parameters.push({
+            type: ToscaFunctionType.STRING,
+            value: ''
+        });
+        this.propertyInputList.push(undefined);
+        this.concatParameterFormArray.push(
+            new FormControl('', [Validators.required, Validators.minLength(1)])
+        );
+    }
+
+    removeParameter(position) {
+        this.propertyInputList.splice(position, 1);
+        this.parameters.splice(position, 1);
+        this.concatParameterFormArray.removeAt(position);
+    }
+
+    createStringProperty(toscaFunctionParameter?: ToscaFunctionParameter) {
+        const property = new PropertyBEModel();
+        property.type = PROPERTY_TYPES.STRING;
+        property.toscaFunction = toscaFunctionParameter ? toscaFunctionParameter : undefined;
+        property.value = toscaFunctionParameter ? toscaFunctionParameter.value : undefined;
+        return property;
+    }
+
+    onFunctionValidityChange(event: ToscaFunctionValidationEvent, index: number) {
+        if (event.isValid && event.toscaFunction) {
+            this.concatParameterFormArray.controls[index].setValue(event.toscaFunction)
+        } else {
+            this.concatParameterFormArray.controls[index].setValue(undefined);
+        }
+    }
+}
+
+export interface ToscaConcatFunctionValidationEvent {
+    isValid: boolean,
+    toscaConcatFunction: ToscaConcatFunction,
+}
index b6b313d..e98f688 100644 (file)
   -->
 
 <div class="tosca-function">
-  <loader [display]="isLoading" [loaderDelay]="500" [relative]="true" [size]="'large'"></loader>
-  <form class="w-sdc-form">
+  <div class="w-sdc-form" [formGroup]="formGroup">
     <div class="i-sdc-form-item">
       <label class="i-sdc-form-label">{{'TOSCA_FUNCTION_LABEL' | translate}}</label>
-      <select [(ngModel)]="toscaGetFunction.functionType" (change)="onToscaFunctionChange()" name="toscaFunctionType">
+      <select formControlName="toscaFunctionType">
         <option *ngFor="let toscaFunction of toscaFunctions"
                 [ngValue]="toscaFunction">{{toscaFunction | lowercase}}</option>
       </select>
     </div>
-    <div class="i-sdc-form-item" *ngIf="showPropertySourceDropdown()">
-      <label class="i-sdc-form-label required">{{'TOSCA_FUNCTION_PROPERTY_SOURCE_LABEL' | translate}}</label>
-      <select name="propertySource" [(ngModel)]="propertySource" (change)="onPropertySourceChange()">
-        <option *ngFor="let propertySource of propertySourceList"
-                [ngValue]="propertySource">{{propertySource}}</option>
-      </select>
+    <div *ngIf="isConcatSelected()">
+      <app-tosca-concat-function [toscaConcatFunction]="toscaFunction" [componentInstanceMap]="componentInstanceMap"
+                                 (onValidityChange)="onConcatFunctionValidityChange($event)"></app-tosca-concat-function>
     </div>
-    <div *ngIf="showPropertyDropdown()" class="i-sdc-form-item">
-      <label class="i-sdc-form-label required">{{dropdownValuesLabel}}</label>
-      <select [(ngModel)]="selectedProperty" name="selectedProperty" (change)="onPropertyChange()">
-        <option *ngFor="let value of propertyDropdownList" [ngValue]="value">{{value.propertyLabel}}</option>
-      </select>
+    <div *ngIf="isGetFunctionSelected()">
+      <app-tosca-get-function [property]="property" [toscaGetFunction]="toscaFunction"
+                              [componentInstanceMap]="componentInstanceMap"
+                              [functionType]="toscaFunctionTypeForm.value"
+                              (onValidityChange)="onGetFunctionValidityChange($event)"></app-tosca-get-function>
     </div>
-    <div *ngIf="dropDownErrorMsg">{{dropDownErrorMsg}}</div>
     <div *ngIf="showClearButton()" class="button-container">
       <button (click)="onClearValues()" class="tlv-btn red ng-star-inserted">{{'TOSCA_FUNCTION_CLEAR_VALUE_BUTTON' | translate}}</button>
     </div>
-  </form>
+  </div>
   <loader [display]="isLoading" [size]="'medium'" [relative]="true"></loader>
 </div>
index b71a61d..076e118 100644 (file)
  */
 
 import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
-import {AttributeModel, ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel} from 'app/models';
+import {ComponentMetadata, PropertyBEModel} from 'app/models';
 import {TopologyTemplateService} from "../../../services/component-services/topology-template.service";
 import {WorkspaceService} from "../../workspace/workspace.service";
-import {PropertiesService} from "../../../services/properties.service";
-import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../utils/constants";
-import {DataTypeService} from "../../../services/data-type.service";
 import {ToscaGetFunctionType} from "../../../../models/tosca-get-function-type";
-import {TranslateService} from "../../../shared/translator/translate.service";
-import {ComponentGenericResponse} from '../../../services/responses/component-generic-response';
-import {Observable} from 'rxjs/Observable';
-import {PropertySource} from "../../../../models/property-source";
 import {InstanceFeDetails} from "../../../../models/instance-fe-details";
 import {ToscaGetFunction} from "../../../../models/tosca-get-function";
-import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn} from "@angular/forms";
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {ToscaFunctionType} from "../../../../models/tosca-function-type.enum";
+import {ToscaGetFunctionValidationEvent} from "./tosca-get-function/tosca-get-function.component";
+import {ToscaFunction} from "../../../../models/tosca-function";
+import {ToscaConcatFunctionValidationEvent} from "./tosca-concat-function/tosca-concat-function.component";
+import {PROPERTY_TYPES} from "../../../../utils/constants";
 
 @Component({
     selector: 'tosca-function',
@@ -44,418 +42,124 @@ export class ToscaFunctionComponent implements OnInit {
     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
     @Input() allowClear: boolean = true;
     @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
-    @Output() onValidityChange: EventEmitter<boolean> = new EventEmitter<boolean>();
+    @Output() onValidityChange: EventEmitter<ToscaFunctionValidationEvent> = new EventEmitter<ToscaFunctionValidationEvent>();
 
-    toscaGetFunctionValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
-        const toscaGetFunction: ToscaGetFunction = control.value;
-        const hasAnyValue = Object.keys(toscaGetFunction).find(key => toscaGetFunction[key]);
-        if (!hasAnyValue) {
-            return null;
-        }
-        const errors: ValidationErrors = {};
-        if (!toscaGetFunction.sourceName) {
-            errors.sourceName = { required: true };
-        }
-        if (!toscaGetFunction.functionType) {
-            errors.functionType = { required: true };
-        }
-        if (!toscaGetFunction.sourceUniqueId) {
-            errors.sourceUniqueId = { required: true };
-        }
-        if (!toscaGetFunction.sourceName) {
-            errors.sourceName = { required: true };
-        }
-        if (!toscaGetFunction.propertyPathFromSource) {
-            errors.propertyPathFromSource = { required: true };
-        }
-        if (!toscaGetFunction.propertyName) {
-            errors.propertyName = { required: true };
-        }
-        if (!toscaGetFunction.propertySource) {
-            errors.propertySource = { required: true };
-        }
-        return errors ? errors : null;
-    };
-
-    toscaGetFunctionForm: FormControl = new FormControl(new ToscaGetFunction(undefined), [this.toscaGetFunctionValidator]);
+    toscaFunctionForm: FormControl = new FormControl(undefined, [Validators.required]);
+    toscaFunctionTypeForm: FormControl = new FormControl(undefined, Validators.required);
     formGroup: FormGroup = new FormGroup({
-        'toscaGetFunction': this.toscaGetFunctionForm
+        'toscaFunction': this.toscaFunctionForm,
+        'toscaFunctionType': this.toscaFunctionTypeForm,
     });
 
-    selectedProperty: PropertyDropdownValue;
     isLoading: boolean = false;
-    propertyDropdownList: Array<PropertyDropdownValue> = [];
+    toscaFunction: ToscaFunction;
     toscaFunctions: Array<string> = [];
-    propertySourceList: Array<string> = [];
-    instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
-    dropdownValuesLabel: string;
-    dropDownErrorMsg: string;
-    propertySource: string
-    toscaGetFunction: ToscaGetFunction = new ToscaGetFunction(undefined);
 
+    private isInitialized: boolean = false;
     private componentMetadata: ComponentMetadata;
 
     constructor(private topologyTemplateService: TopologyTemplateService,
-                private workspaceService: WorkspaceService,
-                private propertiesService: PropertiesService,
-                private dataTypeService: DataTypeService,
-                private translateService: TranslateService) {
+                private workspaceService: WorkspaceService) {
     }
 
     ngOnInit(): void {
         this.componentMetadata = this.workspaceService.metadata;
+        this.toscaFunction = this.property.toscaFunction ? this.property.toscaFunction : undefined;
         this.loadToscaFunctions();
-        this.loadPropertySourceDropdown();
-        this.initToscaGetFunction();
-    }
-
-    private initToscaGetFunction(): void {
-        this.toscaGetFunctionForm.valueChanges.subscribe(toscaGetFunction => {
-            this.onValidityChange.emit(this.toscaGetFunctionForm.valid);
-            if (this.toscaGetFunctionForm.valid) {
-                this.onValidFunction.emit(toscaGetFunction);
-            }
-        });
-        if (!this.property.isToscaGetFunction()) {
-            return;
-        }
-        this.toscaGetFunction = new ToscaGetFunction(this.property.toscaGetFunction);
-        this.toscaGetFunctionForm.setValue(this.toscaGetFunction);
-        if (this.isGetPropertySelected() || this.isGetAttributeSelected()) {
-            if (this.toscaGetFunction.propertySource === PropertySource.SELF) {
-                this.propertySource = PropertySource.SELF;
-            } else {
-                this.propertySource = this.toscaGetFunction.sourceName;
-            }
-        }
-        if (this.toscaGetFunction.propertyName) {
-            this.loadPropertyDropdown(() => {
-                this.selectedProperty = this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName)
-            });
-        }
-    }
-
-    private loadToscaFunctions(): void {
-        this.toscaFunctions.push(ToscaGetFunctionType.GET_ATTRIBUTE);
-        this.toscaFunctions.push(ToscaGetFunctionType.GET_INPUT);
-        this.toscaFunctions.push(ToscaGetFunctionType.GET_PROPERTY);
-    }
-
-    private loadPropertySourceDropdown(): void {
-        this.propertySourceList.push(PropertySource.SELF);
-        this.componentInstanceMap.forEach((value, key) => {
-            const instanceName = value.name;
-            this.instanceNameAndIdMap.set(instanceName, key);
-            if (instanceName !== PropertySource.SELF) {
-                this.addToPropertySource(instanceName);
-            }
-        });
-    }
-
-    private addToPropertySource(source: string): void {
-        this.propertySourceList.push(source);
-        this.propertySourceList.sort((a, b) => {
-            if (a === PropertySource.SELF) {
-                return -1;
-            } else if (b === PropertySource.SELF) {
-                return 1;
-            }
-
-            return a.localeCompare(b);
-        });
-    }
-
-    onToscaFunctionChange(): void {
-        this.resetPropertySource();
-        this.resetPropertyDropdown();
-        if (this.isGetInputSelected()) {
-            this.setSelfPropertySource();
-            this.loadPropertyDropdown();
-        }
-    }
-
-    private loadPropertyDropdown(onComplete?: () => any): void  {
-        this.loadPropertyDropdownLabel();
-        this.loadPropertyDropdownValues(onComplete);
-    }
-
-    private resetForm(): void {
-        this.toscaGetFunction = new ToscaGetFunction();
-        this.toscaGetFunctionForm.setValue(new ToscaGetFunction());
-        this.propertySource = undefined;
-        this.selectedProperty = undefined;
-    }
-
-    private resetPropertySource(): void {
-        this.toscaGetFunction.propertyUniqueId = undefined;
-        this.toscaGetFunction.propertyName = undefined;
-        this.toscaGetFunction.propertySource = undefined;
-        this.toscaGetFunction.sourceUniqueId = undefined;
-        this.toscaGetFunction.sourceName = undefined;
-        this.toscaGetFunction.propertyPathFromSource = undefined;
-        this.propertySource = undefined;
-        this.selectedProperty = undefined;
-
-        const toscaGetFunction1 = new ToscaGetFunction(undefined);
-        toscaGetFunction1.functionType = this.toscaGetFunction.functionType;
-        this.toscaGetFunctionForm.setValue(toscaGetFunction1);
-    }
-
-    private loadPropertyDropdownLabel(): void {
-        if (!this.toscaGetFunction.functionType) {
-            return;
-        }
-        if (this.isGetInputSelected()) {
-            this.dropdownValuesLabel = this.translateService.translate('INPUT_DROPDOWN_LABEL');
-        } else if (this.isGetPropertySelected()) {
-            this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL');
-        } else if (this.isGetAttributeSelected()) {
-            this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_ATTRIBUTE_DROPDOWN_LABEL');
-        }
-    }
-
-    private loadPropertyDropdownValues(onComplete?: () => any): void {
-        if (!this.toscaGetFunction.functionType) {
-            return;
-        }
-        this.resetPropertyDropdown();
-        this.fillPropertyDropdownValues(onComplete);
-    }
-
-    private resetPropertyDropdown(): void {
-        this.dropDownErrorMsg = undefined;
-        this.selectedProperty = undefined;
-        this.propertyDropdownList = [];
-    }
-
-    private fillPropertyDropdownValues(onComplete?: () => any): void {
-        this.startLoading();
-        const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
-        propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
-            const properties: Array<PropertyBEModel | AttributeModel> = this.extractProperties(response);
-            if (!properties || properties.length === 0) {
-                const msgCode = this.getNotFoundMsgCode();
-                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+        this.formGroup.valueChanges.subscribe(() => {
+            if (!this.isInitialized) {
                 return;
             }
-            this.addPropertiesToDropdown(properties);
-            if (this.propertyDropdownList.length == 0) {
-                const msgCode = this.getNotFoundMsgCode();
-                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
-            }
-        }, (error) => {
-            console.error('An error occurred while loading properties.', error);
-            this.stopLoading();
-        }, () => {
-            if (onComplete) {
-                onComplete();
+            this.emitValidityChange();
+            if (this.formGroup.valid) {
+                this.onValidFunction.emit(this.toscaFunctionForm.value);
             }
-            this.stopLoading();
         });
+        this.initToscaGetFunction();
+        this.emitValidityChange();
+        this.isInitialized = true;
     }
 
-    private getNotFoundMsgCode(): string {
-        if (this.isGetInputSelected()) {
-            return 'TOSCA_FUNCTION_NO_INPUT_FOUND';
-        }
-        if (this.isGetAttributeSelected()) {
-            return 'TOSCA_FUNCTION_NO_ATTRIBUTE_FOUND';
-        }
-        if (this.isGetPropertySelected()) {
-            return 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
-        }
-
-        return undefined;
-    }
-
-    private propertyTypeToString() {
-        if (this.property.schemaType) {
-            return `${this.property.type} of ${this.property.schemaType}`;
-        }
-        return this.property.type;
-    }
-
-    private extractProperties(componentGenericResponse: ComponentGenericResponse): Array<PropertyBEModel | AttributeModel> {
-        if (this.isGetInputSelected()) {
-            return componentGenericResponse.inputs;
-        }
-        if (this.isGetPropertySelected()) {
-            if (this.propertySource === PropertySource.SELF) {
-                return componentGenericResponse.properties;
-            }
-            const componentInstanceProperties: PropertyModel[] = componentGenericResponse.componentInstancesProperties[this.instanceNameAndIdMap.get(this.propertySource)];
-            return this.removeSelectedProperty(componentInstanceProperties);
-        }
-        if (this.propertySource === PropertySource.SELF) {
-            return componentGenericResponse.attributes;
-        }
-        return componentGenericResponse.componentInstancesAttributes[this.instanceNameAndIdMap.get(this.propertySource)];
-    }
-
-    private getPropertyObservable(): Observable<ComponentGenericResponse> {
-        if (this.isGetInputSelected()) {
-            return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-        }
-        if (this.isGetPropertySelected()) {
-            if (this.propertySource === PropertySource.SELF) {
-                return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-            }
-            return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-        }
-        if (this.isGetAttributeSelected()) {
-            if (this.propertySource === PropertySource.SELF) {
-                return this.topologyTemplateService.findAllComponentAttributes(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-            }
-            return this.topologyTemplateService.findAllComponentInstanceAttributes(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
-        }
-    }
-
-    private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
-        if (!componentInstanceProperties) {
-            return [];
-        }
-        return componentInstanceProperties.filter(property =>
-            (property.uniqueId !== this.property.uniqueId) ||
-            (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
-        );
-    }
-
-    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue): void {
-        this.propertyDropdownList.push(propertyDropdownValue);
-        this.propertyDropdownList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
+    private validate() {
+        return (!this.toscaFunctionForm.value && !this.toscaFunctionTypeForm.value) || this.formGroup.valid;
     }
 
-    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeModel>): void {
-        for (const property of properties) {
-            if (this.hasSameType(property)) {
-                this.addPropertyToDropdown({
-                    propertyName: property.name,
-                    propertyId: property.uniqueId,
-                    propertyLabel: property.name,
-                    propertyPath: [property.name]
-                });
-            } else if (this.isComplexType(property.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(property);
-            }
-        }
-    }
-
-    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeModel,
-                                                            parentPropertyList: Array<PropertyBEModel | AttributeModel> = []): void {
-        const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
-        if (!dataTypeFound || !dataTypeFound.properties) {
+    private initToscaGetFunction() {
+        if (!this.property.isToscaGetFunction()) {
             return;
         }
-        parentPropertyList.push(inputProperty);
-        dataTypeFound.properties.forEach(dataTypeProperty => {
-            if (this.hasSameType(dataTypeProperty)) {
-                this.addPropertyToDropdown({
-                    propertyName: dataTypeProperty.name,
-                    propertyId: parentPropertyList[0].uniqueId,
-                    propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
-                    propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name]
-                });
-            } else if (this.isComplexType(dataTypeProperty.type)) {
-                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, [...parentPropertyList])
-            }
-        });
+        this.toscaFunctionForm.setValue(this.property.toscaFunction);
+        this.toscaFunctionTypeForm.setValue(this.property.toscaFunction.type);
     }
 
-    private hasSameType(property: PropertyBEModel | AttributeModel) {
-        if (this.typeHasSchema(this.property.type)) {
-            if (!property.schema || !property.schema.property) {
-                return false;
-            }
-            return property.type === this.property.type && this.property.schema.property.type === property.schema.property.type;
+    private loadToscaFunctions(): void {
+        this.toscaFunctions.push(ToscaFunctionType.GET_ATTRIBUTE);
+        this.toscaFunctions.push(ToscaFunctionType.GET_INPUT);
+        this.toscaFunctions.push(ToscaFunctionType.GET_PROPERTY);
+        if (this.property.type === PROPERTY_TYPES.STRING) {
+            this.toscaFunctions.push(ToscaFunctionType.CONCAT);
         }
+    }
 
-        return property.type === this.property.type;
+    private resetForm(): void {
+        this.formGroup.reset();
+        this.toscaFunction = undefined;
     }
 
     private isGetPropertySelected(): boolean {
-        return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_PROPERTY;
+        return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_PROPERTY;
     }
 
     private isGetAttributeSelected(): boolean {
-        return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_ATTRIBUTE;
+        return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_ATTRIBUTE;
     }
 
     private isGetInputSelected(): boolean {
-        return this.toscaGetFunction.functionType === ToscaGetFunctionType.GET_INPUT;
+        return this.formGroup.get('toscaFunctionType').value === ToscaGetFunctionType.GET_INPUT;
     }
 
-    private isComplexType(propertyType: string): boolean {
-        return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
+    isConcatSelected(): boolean {
+        return this.formGroup.get('toscaFunctionType').value === ToscaFunctionType.CONCAT;
     }
 
-    private typeHasSchema(propertyType: string): boolean {
-        return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
+    isGetFunctionSelected(): boolean {
+        return this.isGetInputSelected() || this.isGetPropertySelected() || this.isGetAttributeSelected();
     }
 
-    private stopLoading(): void {
-        this.isLoading = false;
+    onClearValues() {
+        this.resetForm();
     }
 
-    private startLoading(): void {
-        this.isLoading = true;
+    showClearButton(): boolean {
+        return this.allowClear && this.toscaFunctionTypeForm.value;
     }
 
-    showPropertyDropdown(): boolean {
-        if (this.isGetPropertySelected() || this.isGetAttributeSelected()) {
-            return this.toscaGetFunction.propertySource && !this.isLoading && !this.dropDownErrorMsg;
+    onConcatFunctionValidityChange(validationEvent: ToscaConcatFunctionValidationEvent) {
+        if (validationEvent.isValid) {
+            this.toscaFunctionForm.setValue(validationEvent.toscaConcatFunction);
+        } else {
+            this.toscaFunctionForm.setValue(undefined);
         }
-
-        return this.toscaGetFunction.functionType && !this.isLoading && !this.dropDownErrorMsg;
     }
 
-    onPropertySourceChange(): void {
-        if (!this.toscaGetFunction.functionType || !this.propertySource) {
-            return;
-        }
-        this.toscaGetFunction.propertyUniqueId = undefined;
-        this.toscaGetFunction.propertyName = undefined;
-        this.toscaGetFunction.propertyPathFromSource = undefined;
-        if (this.propertySource === PropertySource.SELF) {
-            this.setSelfPropertySource();
+    onGetFunctionValidityChange(validationEvent: ToscaGetFunctionValidationEvent) {
+        if (validationEvent.isValid) {
+            this.toscaFunctionForm.setValue(validationEvent.toscaGetFunction);
         } else {
-            this.toscaGetFunction.propertySource = PropertySource.INSTANCE;
-            this.toscaGetFunction.sourceName = this.propertySource;
-            this.toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(this.propertySource);
+            this.toscaFunctionForm.setValue(undefined);
         }
-        this.toscaGetFunctionForm.setValue(this.toscaGetFunction);
-        this.loadPropertyDropdown();
-    }
-
-    private setSelfPropertySource(): void {
-        this.toscaGetFunction.propertySource = PropertySource.SELF;
-        this.toscaGetFunction.sourceName = this.componentMetadata.name;
-        this.toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
-        this.toscaGetFunctionForm.setValue(this.toscaGetFunction);
-    }
-
-    onPropertyChange(): void {
-        this.toscaGetFunction.propertyUniqueId = this.selectedProperty.propertyId;
-        this.toscaGetFunction.propertyName = this.selectedProperty.propertyName;
-        this.toscaGetFunction.propertyPathFromSource = this.selectedProperty.propertyPath;
-        this.toscaGetFunctionForm.setValue(this.toscaGetFunction);
-    }
-
-    onClearValues() {
-        this.resetForm();
     }
 
-    showClearButton(): boolean {
-        return this.allowClear && this.toscaGetFunction.functionType !== undefined;
-    }
-
-    showPropertySourceDropdown(): boolean {
-        return this.isGetPropertySelected() || this.isGetAttributeSelected();
+    private emitValidityChange() {
+        const isValid = this.validate();
+        this.onValidityChange.emit({
+            isValid: isValid,
+            toscaFunction: isValid ? this.toscaFunctionForm.value : undefined
+        });
     }
 }
 
-export interface PropertyDropdownValue {
-    propertyName: string;
-    propertyId: string;
-    propertyLabel: string;
-    propertyPath: Array<string>;
-}
+export class ToscaFunctionValidationEvent {
+    isValid: boolean;
+    toscaFunction: ToscaFunction;
+}
\ No newline at end of file
index efe45c3..2db76cf 100644 (file)
 
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
-import { FormsModule } from '@angular/forms';
+import {FormsModule, ReactiveFormsModule} from '@angular/forms';
 import { FormElementsModule } from 'app/ng2/components/ui/form-components/form-elements.module';
 import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module';
 import { TranslateModule } from '../../../shared/translator/translate.module';
 import { ToscaFunctionComponent } from './tosca-function.component';
 import { SdcUiComponentsModule } from 'onap-ui-angular';
+import { ToscaGetFunctionComponent } from './tosca-get-function/tosca-get-function.component';
+import { ToscaConcatFunctionComponent } from './tosca-concat-function/tosca-concat-function.component';
 
 @NgModule({
     declarations: [
         ToscaFunctionComponent,
+        ToscaGetFunctionComponent,
+        ToscaConcatFunctionComponent,
     ],
     imports: [
         CommonModule,
         FormsModule,
+        ReactiveFormsModule,
         FormElementsModule,
         UiElementsModule,
         TranslateModule,
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.html b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.html
new file mode 100644 (file)
index 0000000..6f19d5e
--- /dev/null
@@ -0,0 +1,38 @@
+<!--
+  ~ ============LICENSE_START=======================================================
+  ~  Copyright (C) 2021 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=========================================================
+  -->
+
+<div class="tosca-function">
+  <form class="w-sdc-form" [formGroup]="formGroup">
+    <div class="i-sdc-form-item" *ngIf="showPropertySourceDropdown()">
+      <label class="i-sdc-form-label required">{{'TOSCA_FUNCTION_PROPERTY_SOURCE_LABEL' | translate}}</label>
+      <select formControlName="propertySource" (change)="onPropertySourceChange()">
+        <option *ngFor="let propertySource of propertySourceList"
+                [ngValue]="propertySource">{{propertySource}}</option>
+      </select>
+    </div>
+    <div *ngIf="showPropertyDropdown()" class="i-sdc-form-item">
+      <label class="i-sdc-form-label required">{{dropdownValuesLabel}}</label>
+      <select formControlName="selectedProperty">
+        <option *ngFor="let value of propertyDropdownList" [ngValue]="value">{{value.propertyLabel}}</option>
+      </select>
+    </div>
+    <div *ngIf="dropDownErrorMsg">{{dropDownErrorMsg}}</div>
+  </form>
+  <loader [display]="isLoading" [size]="'medium'" [relative]="true"></loader>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.less b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.less
new file mode 100644 (file)
index 0000000..b14edc2
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.spec.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.spec.ts
new file mode 100644 (file)
index 0000000..6c7d986
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * -
+ *  ============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=========================================================
+ */
+
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+import {ToscaGetFunctionComponent} from './tosca-get-function.component';
+import {FormsModule, ReactiveFormsModule} from "@angular/forms";
+import {TranslateModule} from "../../../../shared/translator/translate.module";
+import {UiElementsModule} from "../../../../components/ui/ui-elements.module";
+import {TopologyTemplateService} from "../../../../services/component-services/topology-template.service";
+import {WorkspaceService} from "../../../workspace/workspace.service";
+import {PropertiesService} from "../../../../services/properties.service";
+import {DataTypeService} from "../../../../services/data-type.service";
+import {TranslateService} from "../../../../shared/translator/translate.service";
+import {ComponentMetadata} from "../../../../../models/component-metadata";
+
+describe('ToscaGetFunctionComponent', () => {
+    let component: ToscaGetFunctionComponent;
+    let fixture: ComponentFixture<ToscaGetFunctionComponent>;
+    let topologyTemplateServiceMock: Partial<TopologyTemplateService>;
+    let workspaceServiceMock: Partial<WorkspaceService> = {
+        metadata: new ComponentMetadata()
+    };
+    let propertiesServiceMock: Partial<PropertiesService>;
+    let dataTypeServiceMock: Partial<DataTypeService>;
+    let translateServiceMock: Partial<TranslateService>;
+
+    beforeEach(async(() => {
+        TestBed.configureTestingModule({
+            declarations: [ToscaGetFunctionComponent],
+            imports: [
+                FormsModule,
+                ReactiveFormsModule,
+                TranslateModule,
+                UiElementsModule
+            ],
+            providers: [
+                {provide: TopologyTemplateService, useValue: topologyTemplateServiceMock},
+                {provide: WorkspaceService, useValue: workspaceServiceMock},
+                {provide: PropertiesService, useValue: propertiesServiceMock},
+                {provide: DataTypeService, useValue: dataTypeServiceMock},
+                {provide: TranslateService, useValue: translateServiceMock}
+            ]
+        })
+        .compileComponents();
+    }));
+
+    beforeEach(() => {
+        fixture = TestBed.createComponent(ToscaGetFunctionComponent);
+        component = fixture.componentInstance;
+        fixture.detectChanges();
+    });
+
+    it('should create', () => {
+        expect(component).toBeTruthy();
+    });
+});
diff --git a/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts b/catalog-ui/src/app/ng2/pages/properties-assignment/tosca-function/tosca-get-function/tosca-get-function.component.ts
new file mode 100644 (file)
index 0000000..8f50cc1
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2021 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=========================================================
+ */
+
+import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
+import {AttributeModel, ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel} from 'app/models';
+import {TopologyTemplateService} from "../../../../services/component-services/topology-template.service";
+import {WorkspaceService} from "../../../workspace/workspace.service";
+import {PropertiesService} from "../../../../services/properties.service";
+import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../utils/constants";
+import {DataTypeService} from "../../../../services/data-type.service";
+import {ToscaGetFunctionType} from "../../../../../models/tosca-get-function-type";
+import {TranslateService} from "../../../../shared/translator/translate.service";
+import {ComponentGenericResponse} from '../../../../services/responses/component-generic-response';
+import {Observable} from 'rxjs/Observable';
+import {PropertySource} from "../../../../../models/property-source";
+import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
+import {ToscaGetFunction} from "../../../../../models/tosca-get-function";
+import {FormControl, FormGroup, Validators} from "@angular/forms";
+import {ToscaGetFunctionTypeConverter} from "../../../../../models/tosca-get-function-type-converter";
+
+@Component({
+    selector: 'app-tosca-get-function',
+    templateUrl: './tosca-get-function.component.html',
+    styleUrls: ['./tosca-get-function.component.less']
+})
+export class ToscaGetFunctionComponent implements OnInit, OnChanges {
+
+    @Input() property: PropertyBEModel;
+    @Input() toscaGetFunction: ToscaGetFunction;
+    @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
+    @Input() functionType: ToscaGetFunctionType;
+    @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
+    @Output() onValidityChange: EventEmitter<ToscaGetFunctionValidationEvent> = new EventEmitter<ToscaGetFunctionValidationEvent>();
+
+    formGroup: FormGroup = new FormGroup({
+        'selectedProperty': new FormControl(undefined, Validators.required),
+        'propertySource': new FormControl(undefined, Validators.required)
+    });
+
+    isLoading: boolean = false;
+    propertyDropdownList: Array<PropertyDropdownValue> = [];
+    propertySourceList: Array<string> = [];
+    instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
+    dropdownValuesLabel: string;
+    dropDownErrorMsg: string;
+
+    private isInitialized: boolean = false;
+    private componentMetadata: ComponentMetadata;
+
+    constructor(private topologyTemplateService: TopologyTemplateService,
+                private workspaceService: WorkspaceService,
+                private propertiesService: PropertiesService,
+                private dataTypeService: DataTypeService,
+                private translateService: TranslateService) {
+    }
+
+    ngOnInit(): void {
+        this.componentMetadata = this.workspaceService.metadata;
+        this.formGroup.valueChanges.subscribe(() => {
+            if (!this.isInitialized) {
+                return;
+            }
+            this.onValidityChange.emit({
+                isValid: this.formGroup.valid,
+                toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
+            });
+            if (this.formGroup.valid) {
+                this.onValidFunction.emit(this.buildGetFunctionFromForm());
+            }
+        });
+        this.loadPropertySourceDropdown();
+        this.loadPropertyDropdownLabel();
+        this.initToscaGetFunction().subscribe(() => {
+            this.isInitialized = true;
+        });
+
+    }
+
+    ngOnChanges(_changes: SimpleChanges): void {
+        if (!this.isInitialized) {
+            return;
+        }
+        this.isInitialized = false;
+        this.resetForm();
+        this.loadPropertySourceDropdown();
+        this.loadPropertyDropdownLabel();
+        this.initToscaGetFunction().subscribe(() => {
+            this.isInitialized = true;
+        });
+    }
+
+    private initToscaGetFunction(): Observable<void> {
+        return new Observable(subscriber => {
+            if (!this.toscaGetFunction) {
+                if (this.isGetInput()) {
+                    this.setSelfPropertySource();
+                    this.loadPropertyDropdown();
+                }
+                subscriber.next();
+                return;
+            }
+            if (this.toscaGetFunction.propertySource == PropertySource.SELF) {
+                this.propertySource.setValue(PropertySource.SELF);
+            } else if (this.toscaGetFunction.propertySource == PropertySource.INSTANCE) {
+                this.propertySource
+                .setValue(this.propertySourceList.find(source => this.toscaGetFunction.sourceName === source));
+            }
+            if (this.propertySource.valid) {
+                this.loadPropertyDropdown(() => {
+                    this.selectedProperty
+                    .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName));
+                    subscriber.next();
+                });
+            } else {
+                subscriber.next();
+            }
+        });
+    }
+
+    private buildGetFunctionFromForm() {
+        const toscaGetFunction = new ToscaGetFunction();
+        toscaGetFunction.type = ToscaGetFunctionTypeConverter.convertToToscaFunctionType(this.functionType);
+        toscaGetFunction.functionType = this.functionType;
+        const propertySource = this.propertySource.value;
+        if (this.isPropertySourceSelf()) {
+            toscaGetFunction.propertySource = propertySource
+            toscaGetFunction.sourceName = this.componentMetadata.name;
+            toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
+        } else {
+            toscaGetFunction.propertySource = PropertySource.INSTANCE;
+            toscaGetFunction.sourceName = propertySource;
+            toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(propertySource);
+        }
+
+        const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
+        toscaGetFunction.propertyUniqueId = selectedProperty.propertyId;
+        toscaGetFunction.propertyName = selectedProperty.propertyName;
+        toscaGetFunction.propertyPathFromSource = selectedProperty.propertyPath;
+
+        return toscaGetFunction;
+    }
+
+    private loadPropertySourceDropdown(): void {
+        if (this.isGetInput()) {
+            return;
+        }
+        this.propertySourceList = [];
+        this.propertySourceList.push(PropertySource.SELF);
+        this.componentInstanceMap.forEach((value, key) => {
+            const instanceName = value.name;
+            this.instanceNameAndIdMap.set(instanceName, key);
+            if (instanceName !== PropertySource.SELF) {
+                this.addToPropertySource(instanceName);
+            }
+        });
+    }
+
+    private addToPropertySource(source: string): void {
+        this.propertySourceList.push(source);
+        this.propertySourceList.sort((a, b) => {
+            if (a === PropertySource.SELF) {
+                return -1;
+            } else if (b === PropertySource.SELF) {
+                return 1;
+            }
+
+            return a.localeCompare(b);
+        });
+    }
+
+    private loadPropertyDropdown(onComplete?: () => any): void  {
+        this.loadPropertyDropdownLabel();
+        this.loadPropertyDropdownValues(onComplete);
+    }
+
+    private resetForm(): void {
+        this.formGroup.reset();
+    }
+
+    private loadPropertyDropdownLabel(): void {
+        if (!this.functionType) {
+            return;
+        }
+        if (this.isGetInput()) {
+            this.dropdownValuesLabel = this.translateService.translate('INPUT_DROPDOWN_LABEL');
+        } else if (this.isGetProperty()) {
+            this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL');
+        } else if (this.isGetAttribute()) {
+            this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_ATTRIBUTE_DROPDOWN_LABEL');
+        }
+    }
+
+    private loadPropertyDropdownValues(onComplete?: () => any): void {
+        if (!this.functionType) {
+            return;
+        }
+        this.resetPropertyDropdown();
+        this.fillPropertyDropdownValues(onComplete);
+    }
+
+    private resetPropertyDropdown(): void {
+        this.dropDownErrorMsg = undefined;
+        this.selectedProperty.reset();
+        this.propertyDropdownList = [];
+    }
+
+    private fillPropertyDropdownValues(onComplete?: () => any): void {
+        this.startLoading();
+        const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
+        propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
+            const properties: Array<PropertyBEModel | AttributeModel> = this.extractProperties(response);
+            if (!properties || properties.length === 0) {
+                const msgCode = this.getNotFoundMsgCode();
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+                return;
+            }
+            this.addPropertiesToDropdown(properties);
+            if (this.propertyDropdownList.length == 0) {
+                const msgCode = this.getNotFoundMsgCode();
+                this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.propertyTypeToString()});
+            }
+        }, (error) => {
+            console.error('An error occurred while loading properties.', error);
+            this.stopLoading();
+        }, () => {
+            if (onComplete) {
+                onComplete();
+            }
+            this.stopLoading();
+        });
+    }
+
+    private getNotFoundMsgCode(): string {
+        if (this.isGetInput()) {
+            return 'TOSCA_FUNCTION_NO_INPUT_FOUND';
+        }
+        if (this.isGetAttribute()) {
+            return 'TOSCA_FUNCTION_NO_ATTRIBUTE_FOUND';
+        }
+        if (this.isGetProperty()) {
+            return 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
+        }
+
+        return undefined;
+    }
+
+    private propertyTypeToString() {
+        if (this.property.schemaType) {
+            return `${this.property.type} of ${this.property.schemaType}`;
+        }
+        return this.property.type;
+    }
+
+    private extractProperties(componentGenericResponse: ComponentGenericResponse): Array<PropertyBEModel | AttributeModel> {
+        if (this.isGetInput()) {
+            return componentGenericResponse.inputs;
+        }
+        const propertySource = this.propertySource.value;
+        if (this.isGetProperty()) {
+            if (this.isPropertySourceSelf()) {
+                return componentGenericResponse.properties;
+            }
+            const componentInstanceProperties: PropertyModel[] = componentGenericResponse.componentInstancesProperties[this.instanceNameAndIdMap.get(propertySource)];
+            return this.removeSelectedProperty(componentInstanceProperties);
+        }
+        if (this.isPropertySourceSelf()) {
+            return componentGenericResponse.attributes;
+        }
+        return componentGenericResponse.componentInstancesAttributes[this.instanceNameAndIdMap.get(propertySource)];
+    }
+
+    private isPropertySourceSelf() {
+        return this.propertySource.value === PropertySource.SELF;
+    }
+
+    private getPropertyObservable(): Observable<ComponentGenericResponse> {
+        if (this.isGetInput()) {
+            return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+        }
+        if (this.isGetProperty()) {
+            if (this.isPropertySourceSelf()) {
+                return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+            }
+            return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+        }
+        if (this.isGetAttribute()) {
+            if (this.isPropertySourceSelf()) {
+                return this.topologyTemplateService.findAllComponentAttributes(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+            }
+            return this.topologyTemplateService.findAllComponentInstanceAttributes(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
+        }
+    }
+
+    private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
+        if (!componentInstanceProperties) {
+            return [];
+        }
+        return componentInstanceProperties.filter(property =>
+            (property.uniqueId !== this.property.uniqueId) ||
+            (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
+        );
+    }
+
+    private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue): void {
+        this.propertyDropdownList.push(propertyDropdownValue);
+        this.propertyDropdownList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
+    }
+
+    private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeModel>): void {
+        for (const property of properties) {
+            if (this.hasSameType(property)) {
+                this.addPropertyToDropdown({
+                    propertyName: property.name,
+                    propertyId: property.uniqueId,
+                    propertyLabel: property.name,
+                    propertyPath: [property.name]
+                });
+            } else if (this.isComplexType(property.type)) {
+                this.fillPropertyDropdownWithMatchingChildProperties(property);
+            }
+        }
+    }
+
+    private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeModel,
+                                                            parentPropertyList: Array<PropertyBEModel | AttributeModel> = []): void {
+        const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
+        if (!dataTypeFound || !dataTypeFound.properties) {
+            return;
+        }
+        parentPropertyList.push(inputProperty);
+        dataTypeFound.properties.forEach(dataTypeProperty => {
+            if (this.hasSameType(dataTypeProperty)) {
+                this.addPropertyToDropdown({
+                    propertyName: dataTypeProperty.name,
+                    propertyId: parentPropertyList[0].uniqueId,
+                    propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
+                    propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name]
+                });
+            } else if (this.isComplexType(dataTypeProperty.type)) {
+                this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, [...parentPropertyList])
+            }
+        });
+    }
+
+    private hasSameType(property: PropertyBEModel | AttributeModel) {
+        if (this.typeHasSchema(this.property.type)) {
+            if (!property.schema || !property.schema.property) {
+                return false;
+            }
+            return property.type === this.property.type && this.property.schema.property.type === property.schema.property.type;
+        }
+
+        return property.type === this.property.type;
+    }
+
+    private isGetProperty(): boolean {
+        return this.functionType === ToscaGetFunctionType.GET_PROPERTY;
+    }
+
+    private isGetAttribute(): boolean {
+        return this.functionType === ToscaGetFunctionType.GET_ATTRIBUTE;
+    }
+
+    private isGetInput(): boolean {
+        return this.functionType === ToscaGetFunctionType.GET_INPUT;
+    }
+
+    private isComplexType(propertyType: string): boolean {
+        return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
+    }
+
+    private typeHasSchema(propertyType: string): boolean {
+        return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
+    }
+
+    private stopLoading(): void {
+        this.isLoading = false;
+    }
+
+    private startLoading(): void {
+        this.isLoading = true;
+    }
+
+    showPropertyDropdown(): boolean {
+        if (this.isGetProperty() || this.isGetAttribute()) {
+            return this.propertySource.valid && !this.isLoading && !this.dropDownErrorMsg;
+        }
+
+        return this.functionType && !this.isLoading && !this.dropDownErrorMsg;
+    }
+
+    onPropertySourceChange(): void {
+        if (!this.functionType || !this.propertySource.valid) {
+            return;
+        }
+        this.loadPropertyDropdown();
+    }
+
+    showPropertySourceDropdown(): boolean {
+        return this.isGetProperty() || this.isGetAttribute();
+    }
+
+    private setSelfPropertySource(): void {
+        this.propertySource.setValue(PropertySource.SELF);
+    }
+
+    private get propertySource(): FormControl {
+        return this.formGroup.get('propertySource') as FormControl;
+    }
+
+    private get selectedProperty(): FormControl {
+        return this.formGroup.get('selectedProperty') as FormControl;
+    }
+
+}
+
+export interface PropertyDropdownValue {
+    propertyName: string;
+    propertyId: string;
+    propertyLabel: string;
+    propertyPath: Array<string>;
+}
+
+export interface ToscaGetFunctionValidationEvent {
+    isValid: boolean,
+    toscaGetFunction: ToscaGetFunction,
+}
\ No newline at end of file
index 13460f5..008858d 100644 (file)
@@ -397,7 +397,7 @@ export class PropertyFormViewModel {
 
         this.$scope.$watch("forms.editForm.$invalid", (newVal) => {
             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
-                this.$scope.footerButtons[0].disabled = newVal || !this.$scope.editPropertyModel.property.toscaGetFunction;
+                this.$scope.footerButtons[0].disabled = newVal || !this.$scope.editPropertyModel.property.toscaFunction;
             } else {
                 this.$scope.footerButtons[0].disabled = newVal;
             }
@@ -405,7 +405,7 @@ export class PropertyFormViewModel {
 
         this.$scope.$watch("forms.editForm.$valid", (newVal) => {
             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
-                this.$scope.footerButtons[0].disabled = !newVal || !this.$scope.editPropertyModel.property.toscaGetFunction;
+                this.$scope.footerButtons[0].disabled = !newVal || !this.$scope.editPropertyModel.property.toscaFunction;
             } else {
                 this.$scope.footerButtons[0].disabled = !newVal;
             }
@@ -448,13 +448,13 @@ export class PropertyFormViewModel {
             if (this.$scope.editPropertyModel.hasGetFunctionValue) {
                 this.$scope.editPropertyModel.isGetFunctionValid = undefined;
             } else {
-                this.$scope.editPropertyModel.property.toscaGetFunction = undefined;
+                this.$scope.editPropertyModel.property.toscaFunction = undefined;
                 this.$scope.editPropertyModel.isGetFunctionValid = true;
             }
         }
 
         this.$scope.onGetFunctionValidFunction = (toscaGetFunction: ToscaGetFunction): void => {
-            this.$scope.editPropertyModel.property.toscaGetFunction = toscaGetFunction;
+            this.$scope.editPropertyModel.property.toscaFunction = toscaGetFunction;
         }
 
         this.$scope.onGetFunctionValidityChange = (isValid: boolean): void => {
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CustomYamlFunction.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/CustomYamlFunction.java
new file mode 100644 (file)
index 0000000..84543e2
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import lombok.Setter;
+import org.yaml.snakeyaml.Yaml;
+
+@Setter
+public class CustomYamlFunction implements ToscaFunction, ToscaFunctionParameter {
+
+    private Object yamlValue;
+
+    @Override
+    public ToscaFunctionType getType() {
+        return ToscaFunctionType.YAML;
+    }
+
+    @Override
+    public String getValue() {
+        return new Yaml().dump(yamlValue);
+    }
+
+    @Override
+    public Object getJsonObjectValue() {
+        return yamlValue;
+    }
+}
index 845eee8..f88514a 100644 (file)
@@ -22,6 +22,7 @@ package org.openecomp.sdc.be.datatypes.elements;
 
 import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
 
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -56,11 +57,16 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
     private Boolean immutable = Boolean.FALSE;
     private Boolean mappedToComponentProperty = Boolean.TRUE;
     /**
-     * @deprecated use {@link #toscaGetFunction#functionType} instead
+     * @deprecated use {@link #toscaFunction} instead
      */
     @Deprecated
     private ToscaGetFunctionType toscaGetFunctionType;
+    /**
+     * @deprecated use {@link #toscaFunction} instead
+     */
+    @Deprecated
     private ToscaGetFunctionDataDefinition toscaGetFunction;
+    private ToscaFunction toscaFunction;
 
     private String inputPath;
     private String status;
@@ -115,8 +121,9 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
         this.setInstanceUniqueId(propertyDataDefinition.getInstanceUniqueId());
         this.setModel(propertyDataDefinition.getModel());
         this.setPropertyId(propertyDataDefinition.getPropertyId());
-        this.setToscaGetFunctionType(propertyDataDefinition.getToscaGetFunctionType());
         this.setToscaGetFunction(propertyDataDefinition.getToscaGetFunction());
+        this.setToscaGetFunctionType(propertyDataDefinition.getToscaGetFunctionType());
+        this.setToscaFunction(propertyDataDefinition.getToscaFunction());
         this.parentPropertyType = propertyDataDefinition.getParentPropertyType();
         this.subPropertyInputPath = propertyDataDefinition.getSubPropertyInputPath();
         if (isNotEmpty(propertyDataDefinition.annotations)) {
@@ -166,10 +173,14 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
     }
 
     public ToscaGetFunctionType getToscaGetFunctionType() {
-        if (toscaGetFunction != null) {
-            return toscaGetFunction.getFunctionType();
+        if (isToscaGetFunction()) {
+            if (toscaFunction != null) {
+                return ((ToscaGetFunctionDataDefinition) toscaFunction).getFunctionType();
+            }
+            return toscaGetFunctionType;
         }
-        return toscaGetFunctionType;
+
+        return null;
     }
 
     public Boolean isHidden() {
@@ -318,12 +329,23 @@ public class PropertyDataDefinition extends ToscaDataDefinition {
         return (List<Annotation>) getToscaPresentationValue(JsonPresentationFields.ANNOTATIONS);
     }
 
-    public boolean isGetFunction() {
-        return this.toscaGetFunctionType != null || this.toscaGetFunction != null;
+    @JsonIgnoreProperties
+    public boolean isToscaFunction() {
+        return this.toscaGetFunctionType != null || this.toscaFunction != null;
+    }
+
+
+    @JsonIgnoreProperties
+    public boolean isToscaGetFunction() {
+        return this.toscaGetFunctionType != null || (this.toscaFunction != null
+            && (this.toscaFunction.getType() == ToscaFunctionType.GET_ATTRIBUTE
+                || this.toscaFunction.getType() == ToscaFunctionType.GET_INPUT
+                || this.toscaFunction.getType() == ToscaFunctionType.GET_PROPERTY));
     }
 
-    public boolean hasGetFunction() {
-        return this.toscaGetFunction != null;
+    @JsonIgnoreProperties
+    public boolean hasToscaFunction() {
+        return this.toscaFunction != null;
     }
 
 }
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaConcatFunction.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaConcatFunction.java
new file mode 100644 (file)
index 0000000..62307fb
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import com.google.gson.Gson;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class ToscaConcatFunction implements ToscaFunction, ToscaFunctionParameter {
+
+    private List<ToscaFunctionParameter> parameters = new ArrayList<>();
+
+    @Override
+    public ToscaFunctionType getType() {
+        return ToscaFunctionType.CONCAT;
+    }
+
+    @Override
+    public String getValue() {
+        return new Gson().toJson(getJsonObjectValue());
+    }
+
+    @Override
+    public Object getJsonObjectValue() {
+        return Map.of(
+            ToscaFunctionType.CONCAT.getName(),
+            parameters.stream().map(ToscaFunctionParameter::getJsonObjectValue).collect(Collectors.toList())
+        );
+    }
+
+}
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunction.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunction.java
new file mode 100644 (file)
index 0000000..40664a1
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+@JsonDeserialize(using = ToscaFunctionJsonDeserializer.class)
+public interface ToscaFunction {
+
+    ToscaFunctionType getType();
+    String getValue();
+
+}
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializer.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializer.java
new file mode 100644 (file)
index 0000000..74aed12
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.openecomp.sdc.be.datatypes.enums.PropertySource;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
+import org.yaml.snakeyaml.Yaml;
+
+public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction> {
+
+    public ToscaFunctionJsonDeserializer() {
+        this(null);
+    }
+
+    public ToscaFunctionJsonDeserializer(Class<?> vc) {
+        super(vc);
+    }
+
+    @Override
+    public ToscaFunction deserialize(final JsonParser jsonParser, final DeserializationContext context) throws IOException {
+        final JsonNode node = jsonParser.getCodec().readTree(jsonParser);
+        return deserializeToscaFunction(node, context);
+    }
+
+    private ToscaFunction deserializeToscaFunction(final JsonNode node, final DeserializationContext context) throws IOException {
+        final String functionType;
+        if (node.get("type") != null) {
+            functionType = node.get("type").asText();
+        } else if (node.get("functionType") != null) {
+            //support for legacy tosca function
+            functionType = node.get("functionType").asText();
+        } else {
+            throw context.instantiationException(ToscaFunction.class, "Attribute type not provided");
+        }
+        final ToscaFunctionType toscaFunctionType = ToscaFunctionType.findType(functionType)
+            .orElseThrow(() -> context.instantiationException(ToscaFunction.class,
+                String.format("Invalid function type '%s' or attribute type not provided", functionType))
+            );
+        if (toscaFunctionType == ToscaFunctionType.GET_INPUT || toscaFunctionType == ToscaFunctionType.GET_ATTRIBUTE
+            || toscaFunctionType == ToscaFunctionType.GET_PROPERTY) {
+            return deserializeToscaGetFunction(toscaFunctionType, node, context);
+        }
+
+        if (toscaFunctionType == ToscaFunctionType.CONCAT) {
+            return this.deserializeConcatFunction(node, context);
+        }
+
+        if (toscaFunctionType == ToscaFunctionType.YAML) {
+            return this.deserializeYamlFunction(node);
+        }
+
+        return null;
+    }
+
+    private ToscaFunction deserializeYamlFunction(JsonNode node) {
+        var yamlFunction = new CustomYamlFunction();
+        final Object value = new Yaml().load(node.get("value").asText());
+        yamlFunction.setYamlValue(value);
+        return yamlFunction;
+    }
+
+    private ToscaGetFunctionDataDefinition deserializeToscaGetFunction(final ToscaFunctionType toscaFunctionType, final JsonNode node,
+                                                                       final DeserializationContext context) throws JsonMappingException {
+        final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
+        toscaGetFunction.setFunctionType(ToscaGetFunctionType.fromToscaFunctionType(toscaFunctionType).orElse(null));
+        toscaGetFunction.setSourceName(node.get("sourceName").asText());
+        toscaGetFunction.setPropertyUniqueId(node.get("propertyUniqueId").asText());
+        final String propertySource = node.get("propertySource").asText();
+        if (StringUtils.isNotEmpty(propertySource)) {
+            final PropertySource propertySource1 = PropertySource.findType(propertySource).orElseThrow(() ->
+                context.instantiationException(ToscaGetFunctionDataDefinition.class,
+                    String.format("Invalid propertySource '%s'", propertySource))
+            );
+            toscaGetFunction.setPropertySource(propertySource1);
+        }
+        toscaGetFunction.setPropertyName(node.get("propertyName").asText());
+        toscaGetFunction.setSourceName(node.get("sourceName").asText());
+        toscaGetFunction.setSourceUniqueId(node.get("sourceUniqueId").asText());
+        final JsonNode propertyPathFromSourceNode = node.get("propertyPathFromSource");
+        if (propertyPathFromSourceNode != null) {
+            if (!propertyPathFromSourceNode.isArray()) {
+                throw context.instantiationException(ToscaGetFunctionDataDefinition.class, "Expecting an array for propertyPathFromSource attribute");
+            }
+            final List<String> pathFromSource = new ArrayList<>();
+            propertyPathFromSourceNode.forEach(jsonNode -> pathFromSource.add(jsonNode.asText()));
+            toscaGetFunction.setPropertyPathFromSource(pathFromSource);
+        }
+
+        return toscaGetFunction;
+    }
+
+    private ToscaConcatFunction deserializeConcatFunction(final JsonNode concatFunctionJsonNode,
+                                                          final DeserializationContext context) throws IOException {
+        final var toscaConcatFunction = new ToscaConcatFunction();
+        final List<ToscaFunctionParameter> functionParameterList = new ArrayList<>();
+        final JsonNode parametersNode = concatFunctionJsonNode.get("parameters");
+        if (!parametersNode.isArray()) {
+            throw context.instantiationException(List.class, "");
+        }
+        for (final JsonNode parameterNode : parametersNode) {
+            final JsonNode typeJsonNode = parameterNode.get("type");
+            if (typeJsonNode == null) {
+                throw context.instantiationException(ToscaConcatFunction.class, "TOSCA concat function parameter type attribute not provided");
+            }
+            final String parameterType = typeJsonNode.asText();
+            final ToscaFunctionType toscaFunctionType = ToscaFunctionType.findType(parameterType)
+                .orElseThrow(() -> context.instantiationException(ToscaConcatFunction.class,
+                    String.format("Invalid TOSCA concat function parameter type '%s'", parameterType))
+                );
+            if (toscaFunctionType == ToscaFunctionType.STRING) {
+                final ToscaStringParameter toscaStringParameter = new ToscaStringParameter();
+                toscaStringParameter.setValue(parameterNode.get("value").asText());
+                functionParameterList.add(toscaStringParameter);
+            } else {
+                final ToscaFunction toscaFunction = this.deserializeToscaFunction(parameterNode, context);
+                functionParameterList.add((ToscaFunctionParameter) toscaFunction);
+            }
+        }
+        toscaConcatFunction.setParameters(functionParameterList);
+        return toscaConcatFunction;
+    }
+
+}
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionParameter.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionParameter.java
new file mode 100644 (file)
index 0000000..4d4c7b0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+public interface ToscaFunctionParameter {
+
+    String getValue();
+    ToscaFunctionType getType();
+    Object getJsonObjectValue();
+
+}
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionType.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionType.java
new file mode 100644 (file)
index 0000000..4579ac2
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import java.util.Arrays;
+import java.util.Optional;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter
+public enum ToscaFunctionType {
+
+    GET_INPUT("get_input"),
+    GET_PROPERTY("get_property"),
+    GET_ATTRIBUTE("get_attribute"),
+    CONCAT("concat"),
+    YAML("yaml"),
+    STRING("string");
+
+    private final String name;
+
+    public static Optional<ToscaFunctionType> findType(final String functionType) {
+        return Arrays.stream(values()).filter(toscaFunctionType -> toscaFunctionType.getName().equalsIgnoreCase(functionType)).findFirst();
+    }
+}
index 0741d68..f19217e 100644 (file)
@@ -33,7 +33,7 @@ import org.openecomp.sdc.be.datatypes.enums.PropertySource;
 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
 
 @Data
-public class ToscaGetFunctionDataDefinition {
+public class ToscaGetFunctionDataDefinition implements ToscaFunction, ToscaFunctionParameter {
 
     private String propertyUniqueId;
     private String propertyName;
@@ -55,6 +55,11 @@ public class ToscaGetFunctionDataDefinition {
      * Builds the value of a property based on the TOSCA get function information.
      */
     public String generatePropertyValue() {
+        return new Gson().toJson(getJsonObjectValue());
+    }
+
+    @Override
+    public Object getJsonObjectValue() {
         if (functionType == null) {
             throw new IllegalStateException("functionType is required in order to generate the get function value");
         }
@@ -62,12 +67,11 @@ public class ToscaGetFunctionDataDefinition {
             throw new IllegalStateException("propertyPathFromSource is required in order to generate the get function value");
         }
 
-        final var gson = new Gson();
         if (functionType == ToscaGetFunctionType.GET_PROPERTY || functionType == ToscaGetFunctionType.GET_ATTRIBUTE) {
-            return gson.toJson(buildFunctionValueWithPropertySource());
+            return buildFunctionValueWithPropertySource();
         }
         if (functionType == ToscaGetFunctionType.GET_INPUT) {
-            return gson.toJson(buildGetInputFunctionValue());
+            return buildGetInputFunctionValue();
         }
 
         throw new UnsupportedOperationException(String.format("ToscaGetFunctionType '%s' is not supported yet", functionType));
@@ -105,4 +109,26 @@ public class ToscaGetFunctionDataDefinition {
         return Map.of(this.functionType.getFunctionName(), this.propertyPathFromSource);
     }
 
+    @Override
+    public ToscaFunctionType getType() {
+        if (functionType == null) {
+            return null;
+        }
+        switch (functionType) {
+            case GET_INPUT:
+                return ToscaFunctionType.GET_INPUT;
+            case GET_PROPERTY:
+                return ToscaFunctionType.GET_PROPERTY;
+            case GET_ATTRIBUTE:
+                return ToscaFunctionType.GET_ATTRIBUTE;
+            default:
+                return null;
+        }
+    }
+
+    @Override
+    public String getValue() {
+        return this.generatePropertyValue();
+    }
+
 }
diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaStringParameter.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaStringParameter.java
new file mode 100644 (file)
index 0000000..d6d5d9f
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import lombok.Setter;
+
+@Setter
+public class ToscaStringParameter implements ToscaFunctionParameter {
+    private String value;
+
+    @Override
+    public String getValue() {
+        return value;
+    }
+
+    @Override
+    public ToscaFunctionType getType() {
+        return ToscaFunctionType.STRING;
+    }
+
+    @Override
+    public Object getJsonObjectValue() {
+        return getValue();
+    }
+}
index 8086d22..d2e1503 100644 (file)
@@ -21,6 +21,8 @@
 
 package org.openecomp.sdc.be.datatypes.enums;
 
+import java.util.Arrays;
+import java.util.Optional;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
@@ -31,4 +33,8 @@ public enum PropertySource {
 
     private final String name;
 
+    public static Optional<PropertySource> findType(final String propertySource) {
+        return Arrays.stream(values()).filter(propertySource1 -> propertySource1.getName().equalsIgnoreCase(propertySource)).findFirst();
+    }
+
 }
index bb85ceb..d84c86a 100644 (file)
 
 package org.openecomp.sdc.be.datatypes.tosca;
 
+import java.util.Optional;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
 
 @AllArgsConstructor
 @Getter
@@ -31,4 +33,23 @@ public enum ToscaGetFunctionType {
 
     private final String functionName;
     private final String propertyType;
+
+    /**
+     * Converts a {@link ToscaFunctionType} to a {@link ToscaGetFunctionType}
+     * @param toscaFunctionType the tosca function type to convert
+     * @return the respective {@link ToscaGetFunctionType}
+     */
+    public static Optional<ToscaGetFunctionType> fromToscaFunctionType(final ToscaFunctionType toscaFunctionType) {
+        switch (toscaFunctionType) {
+            case GET_INPUT:
+                return Optional.of(GET_INPUT);
+            case GET_PROPERTY:
+                return Optional.of(GET_PROPERTY);
+            case GET_ATTRIBUTE:
+                return Optional.of(GET_ATTRIBUTE);
+            default:
+                return Optional.empty();
+        }
+    }
+
 }
index 2e8b26f..2d73faf 100644 (file)
 
 package org.openecomp.sdc.be.datatypes.elements;
 
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
-
-import java.util.List;
-
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
 
 
-public class PropertyDataDefinitionTest {
+class PropertyDataDefinitionTest {
 
        private PropertyDataDefinition propDef;
 
-       @Before
+       @BeforeEach
        public void setUp() {
                propDef = new PropertyDataDefinition();
        }
 
        @Test
-       public void setStringField() {
+    void setStringField() {
                final String name = "name";
                assertNull(propDef.getName());
                assertNull(propDef.getToscaPresentationValue(JsonPresentationFields.NAME));
@@ -56,7 +55,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void setDefaultValue() {
+    void setDefaultValue() {
                final String defaultValue = "text";
                assertNull(propDef.getDefaultValue());
                assertNull(propDef.getToscaPresentationValue(JsonPresentationFields.DEFAULT_VALUE));
@@ -66,7 +65,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void setValueNotDefinedInPropDataDefinition() {
+    void setValueNotDefinedInPropDataDefinition() {
                final String defaultValue = "VF";
                assertNull(propDef.getToscaPresentationValue(JsonPresentationFields.COMPONENT_TYPE));
                propDef.setToscaPresentationValue(JsonPresentationFields.COMPONENT_TYPE, defaultValue);
@@ -74,7 +73,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void setBooleanField() {
+    void setBooleanField() {
                assertFalse((Boolean) propDef.getToscaPresentationValue(JsonPresentationFields.PASSWORD));
                assertFalse(propDef.isPassword());
                propDef.setToscaPresentationValue(JsonPresentationFields.PASSWORD, Boolean.TRUE);
@@ -83,7 +82,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void mergeDefaultValueWhenItWasNullBeforeMerge() {
+    void mergeDefaultValueWhenItWasNullBeforeMerge() {
                final String defaultValue = "12345";
                final String type = "1";
                PropertyDataDefinition propForMerge = new PropertyDataDefinition();
@@ -99,7 +98,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void mergeDefaultValueAndOverrideIt() {
+    void mergeDefaultValueAndOverrideIt() {
                final String defaultValue = "12345";
                final String defaultValueForOther = "7890";
                final String type = "1";
@@ -117,7 +116,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void mergeDefaultValueWhenOverridingIsNotAllowed() {
+    void mergeDefaultValueWhenOverridingIsNotAllowed() {
                final String defaultValue = "12345";
                final String defaultValueForOther = "7890";
                final String type = "1";
@@ -139,7 +138,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void testConstructor() throws Exception {
+    void testConstructor() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -149,7 +148,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void testGetInputPath() throws Exception {
+    void testGetInputPath() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -160,7 +159,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetInputPath() throws Exception {
+    void testSetInputPath() {
                PropertyDataDefinition testSubject;
                String inputPath = "";
 
@@ -171,7 +170,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetName() throws Exception {
+    void testGetName() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -182,7 +181,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetName() throws Exception {
+    void testSetName() {
                PropertyDataDefinition testSubject;
                String name = "";
 
@@ -193,7 +192,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetValue() throws Exception {
+    void testGetValue() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -204,7 +203,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetValue() throws Exception {
+    void testSetValue() {
                PropertyDataDefinition testSubject;
                String value = "";
 
@@ -215,7 +214,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testIsDefinition() throws Exception {
+    void testIsDefinition() {
                PropertyDataDefinition testSubject;
                boolean result;
 
@@ -226,7 +225,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetDefinition() throws Exception {
+    void testSetDefinition() {
                PropertyDataDefinition testSubject;
                boolean definition = false;
 
@@ -237,7 +236,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetType() throws Exception {
+    void testGetType() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -248,7 +247,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetDefaultValue() throws Exception {
+    void testGetDefaultValue() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -259,7 +258,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetDefaultValue() throws Exception {
+    void testSetDefaultValue() {
                PropertyDataDefinition testSubject;
                String defaultValue = "";
 
@@ -270,7 +269,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetType() throws Exception {
+    void testSetType() {
                PropertyDataDefinition testSubject;
                String type = "";
 
@@ -281,7 +280,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testIsRequired() throws Exception {
+    void testIsRequired() {
                PropertyDataDefinition testSubject;
                Boolean result;
 
@@ -292,7 +291,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetRequired() throws Exception {
+    void testSetRequired() {
                PropertyDataDefinition testSubject;
                Boolean required = null;
 
@@ -303,7 +302,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetDescription() throws Exception {
+    void testGetDescription() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -314,7 +313,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetDescription() throws Exception {
+    void testSetDescription() {
                PropertyDataDefinition testSubject;
                String description = "";
 
@@ -325,7 +324,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testIsPassword() throws Exception {
+    void testIsPassword() {
                PropertyDataDefinition testSubject;
                boolean result;
 
@@ -336,7 +335,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetPassword() throws Exception {
+    void testSetPassword() {
                PropertyDataDefinition testSubject;
                boolean password = false;
 
@@ -347,7 +346,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetUniqueId() throws Exception {
+    void testGetUniqueId() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -358,7 +357,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetUniqueId() throws Exception {
+    void testSetUniqueId() {
                PropertyDataDefinition testSubject;
                String uniqueId = "";
 
@@ -369,7 +368,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetSchema() throws Exception {
+    void testGetSchema() {
                PropertyDataDefinition testSubject;
                SchemaDefinition result;
 
@@ -380,7 +379,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetSchema() throws Exception {
+    void testSetSchema() {
                PropertyDataDefinition testSubject;
                SchemaDefinition entrySchema = null;
 
@@ -391,7 +390,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetLabel() throws Exception {
+    void testGetLabel() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -402,7 +401,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetLabel() throws Exception {
+    void testSetLabel() {
                PropertyDataDefinition testSubject;
                String label = "";
 
@@ -413,7 +412,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testIsHidden() throws Exception {
+    void testIsHidden() {
                PropertyDataDefinition testSubject;
                Boolean result;
 
@@ -424,7 +423,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetHidden() throws Exception {
+    void testSetHidden() {
                PropertyDataDefinition testSubject;
                Boolean hidden = null;
 
@@ -435,7 +434,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testIsImmutable() throws Exception {
+    void testIsImmutable() {
                PropertyDataDefinition testSubject;
                Boolean result;
 
@@ -446,7 +445,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetImmutable() throws Exception {
+    void testSetImmutable() {
                PropertyDataDefinition testSubject;
                Boolean immutable = null;
 
@@ -457,7 +456,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetParentUniqueId() throws Exception {
+    void testGetParentUniqueId() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -468,7 +467,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetParentUniqueId() throws Exception {
+    void testSetParentUniqueId() {
                PropertyDataDefinition testSubject;
                String parentUniqueId = "";
 
@@ -479,7 +478,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetGetInputValues() throws Exception {
+    void testGetGetInputValues() {
                PropertyDataDefinition testSubject;
                List<GetInputValueDataDefinition> result;
 
@@ -490,7 +489,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetGetInputValues() throws Exception {
+    void testSetGetInputValues() {
                PropertyDataDefinition testSubject;
                List<GetInputValueDataDefinition> getInputValues = null;
 
@@ -501,7 +500,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetStatus() throws Exception {
+    void testGetStatus() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -512,7 +511,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetStatus() throws Exception {
+    void testSetStatus() {
                PropertyDataDefinition testSubject;
                String status = "";
 
@@ -523,7 +522,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetInputId() throws Exception {
+    void testGetInputId() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -534,7 +533,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetInputId() throws Exception {
+    void testSetInputId() {
                PropertyDataDefinition testSubject;
                String inputId = "";
 
@@ -545,7 +544,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetInstanceUniqueId() throws Exception {
+    void testGetInstanceUniqueId() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -556,7 +555,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetInstanceUniqueId() throws Exception {
+    void testSetInstanceUniqueId() {
                PropertyDataDefinition testSubject;
                String instanceUniqueId = "";
 
@@ -567,7 +566,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testGetPropertyId() throws Exception {
+    void testGetPropertyId() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -578,7 +577,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testSetPropertyId() throws Exception {
+    void testSetPropertyId() {
                PropertyDataDefinition testSubject;
                String propertyId = "";
 
@@ -589,7 +588,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testToString() throws Exception {
+    void testToString() {
                PropertyDataDefinition testSubject;
                String result;
 
@@ -600,7 +599,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testHashCode() throws Exception {
+    void testHashCode() {
                PropertyDataDefinition testSubject;
                int result;
 
@@ -611,7 +610,7 @@ public class PropertyDataDefinitionTest {
 
 
        @Test
-       public void testEquals() throws Exception {
+    void testEquals() {
                PropertyDataDefinition testSubject;
                Object obj = null;
                boolean result;
@@ -620,16 +619,16 @@ public class PropertyDataDefinitionTest {
                testSubject = createTestSubject();
                obj = null;
                result = testSubject.equals(obj);
-               Assert.assertEquals(false, result);
+               assertEquals(false, result);
                result = testSubject.equals(testSubject);
-               Assert.assertEquals(true, result);
+               assertEquals(true, result);
                PropertyDataDefinition other = createTestSubject();
                result = testSubject.equals(other);
-               Assert.assertEquals(true, result);
+               assertEquals(true, result);
        }
 
        @Test
-       public void testConvertPropertyDataToInstancePropertyData() throws Exception {
+    void testConvertPropertyDataToInstancePropertyData() {
                PropertyDataDefinition testSubject;
 
                // default test
@@ -638,7 +637,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void testTypeEquals() throws Exception {
+    void testTypeEquals() {
                PropertyDataDefinition testSubject;
 
                // default test
@@ -649,7 +648,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void testMergeFunction() throws Exception {
+    void testMergeFunction() {
                PropertyDataDefinition testSubject;
 
                // default test
@@ -659,7 +658,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void schemaTypeNullWhenSchemaIsNull() {
+    void schemaTypeNullWhenSchemaIsNull() {
                String sampleSchemaType = "sampleSchemaType";
                PropertyDataDefinition testSubject = createTestSubject();
                testSubject.setSchemaType(sampleSchemaType);
@@ -667,7 +666,7 @@ public class PropertyDataDefinitionTest {
        }
 
        @Test
-       public void schemaTypeIsReturnedWhenSchemaisPresent() {
+    void schemaTypeIsReturnedWhenSchemaIsPresent() {
                String sampleSchemaType = "sampleSchemaType";
                SchemaDefinition schemaDefinition = new SchemaDefinition();
                schemaDefinition.setProperty(new PropertyDataDefinition());
@@ -678,4 +677,62 @@ public class PropertyDataDefinitionTest {
 
                assertThat(testSubject.getSchemaType(), is(equalTo(sampleSchemaType)));
        }
+
+       @Test
+    void getToscaGetFunctionTypeTest() {
+               var propertyDataDefinition = new PropertyDataDefinition();
+               assertNull(propertyDataDefinition.getToscaGetFunctionType());
+
+               final var toscaGetFunction = new ToscaGetFunctionDataDefinition();
+               propertyDataDefinition.setToscaFunction(toscaGetFunction);
+
+               toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
+               assertEquals(ToscaGetFunctionType.GET_INPUT, propertyDataDefinition.getToscaGetFunctionType());
+
+               toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_PROPERTY);
+               assertEquals(ToscaGetFunctionType.GET_PROPERTY, propertyDataDefinition.getToscaGetFunctionType());
+
+               toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_ATTRIBUTE);
+               assertEquals(ToscaGetFunctionType.GET_ATTRIBUTE, propertyDataDefinition.getToscaGetFunctionType());
+
+               propertyDataDefinition = new PropertyDataDefinition();
+               propertyDataDefinition.setToscaGetFunctionType(ToscaGetFunctionType.GET_INPUT);
+               assertEquals(ToscaGetFunctionType.GET_INPUT, propertyDataDefinition.getToscaGetFunctionType());
+
+               propertyDataDefinition.setToscaGetFunctionType(ToscaGetFunctionType.GET_PROPERTY);
+               assertEquals(ToscaGetFunctionType.GET_PROPERTY, propertyDataDefinition.getToscaGetFunctionType());
+
+               propertyDataDefinition.setToscaGetFunctionType(ToscaGetFunctionType.GET_ATTRIBUTE);
+               assertEquals(ToscaGetFunctionType.GET_ATTRIBUTE, propertyDataDefinition.getToscaGetFunctionType());
+       }
+
+       @Test
+       void isToscaFunctionTest() {
+               var propertyDataDefinition = new PropertyDataDefinition();
+               assertFalse(propertyDataDefinition.isToscaFunction());
+
+               propertyDataDefinition.setToscaGetFunctionType(ToscaGetFunctionType.GET_PROPERTY);
+               assertTrue(propertyDataDefinition.isToscaFunction());
+
+               propertyDataDefinition = new PropertyDataDefinition();
+               propertyDataDefinition.setToscaFunction(new ToscaConcatFunction());
+               assertTrue(propertyDataDefinition.isToscaFunction());
+       }
+
+       @Test
+       void isToscaGetFunctionTest() {
+               var propertyDataDefinition = new PropertyDataDefinition();
+               propertyDataDefinition.setToscaGetFunctionType(ToscaGetFunctionType.GET_PROPERTY);
+               assertTrue(propertyDataDefinition.isToscaGetFunction());
+
+               propertyDataDefinition = new PropertyDataDefinition();
+               final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
+               toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
+               propertyDataDefinition.setToscaFunction(toscaGetFunction);
+               assertTrue(propertyDataDefinition.isToscaGetFunction());
+
+               propertyDataDefinition.setToscaFunction(new ToscaConcatFunction());
+               assertFalse(propertyDataDefinition.isToscaGetFunction());
+       }
+
 }
diff --git a/common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializerTest.java b/common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializerTest.java
new file mode 100644 (file)
index 0000000..e11b661
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * -
+ *  ============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.datatypes.elements;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.exc.ValueInstantiationException;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.datatypes.enums.PropertySource;
+import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
+
+class ToscaFunctionJsonDeserializerTest {
+
+    @Test
+    void testGetInputToscaFunction() throws JsonProcessingException {
+        final String toscaGetInputFunction = "{\n"
+            + "            \"propertyUniqueId\": \"e57525d7-2115-4934-9ba4-9cebfa22bad2.nf_naming\",\n"
+            + "            \"type\": \"GET_INPUT\",\n"
+            + "            \"propertySource\": \"SELF\",\n"
+            + "            \"propertyName\": \"instance_name\",\n"
+            + "            \"sourceName\": \"ciResVFc26a0b30ec20\",\n"
+            + "            \"sourceUniqueId\": \"aee643c9-6c8e-4a24-af7a-a9aff5c072c0\",\n"
+            + "            \"propertyPathFromSource\": [\n"
+            + "                \"nf_naming\",\n"
+            + "                \"instance_name\"\n"
+            + "            ]\n"
+            + "        }";
+        ToscaFunction toscaFunction = parseToscaFunction(toscaGetInputFunction);
+        assertTrue(toscaFunction instanceof ToscaGetFunctionDataDefinition);
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) toscaFunction;
+        assertEquals(ToscaFunctionType.GET_INPUT, toscaGetFunction.getType());
+        assertEquals(ToscaGetFunctionType.GET_INPUT, toscaGetFunction.getFunctionType());
+        assertEquals("e57525d7-2115-4934-9ba4-9cebfa22bad2.nf_naming", toscaGetFunction.getPropertyUniqueId());
+        assertEquals(PropertySource.SELF, toscaGetFunction.getPropertySource());
+        assertEquals("instance_name", toscaGetFunction.getPropertyName());
+        assertEquals("ciResVFc26a0b30ec20", toscaGetFunction.getSourceName());
+        assertEquals("aee643c9-6c8e-4a24-af7a-a9aff5c072c0", toscaGetFunction.getSourceUniqueId());
+        assertEquals(List.of("nf_naming", "instance_name"), toscaGetFunction.getPropertyPathFromSource());
+    }
+
+    @Test
+    void testGetInputToscaFunctionLegacyConversion() throws JsonProcessingException {
+        final String toscaGetInputFunction = "{\n"
+            + "            \"propertyUniqueId\": \"e57525d7-2115-4934-9ba4-9cebfa22bad2.nf_naming\",\n"
+            + "            \"functionType\": \"GET_INPUT\",\n"
+            + "            \"propertySource\": \"SELF\",\n"
+            + "            \"propertyName\": \"instance_name\",\n"
+            + "            \"sourceName\": \"ciResVFc26a0b30ec20\",\n"
+            + "            \"sourceUniqueId\": \"aee643c9-6c8e-4a24-af7a-a9aff5c072c0\",\n"
+            + "            \"propertyPathFromSource\": [\n"
+            + "                \"nf_naming\",\n"
+            + "                \"instance_name\"\n"
+            + "            ]\n"
+            + "        }";
+        ToscaFunction toscaFunction = parseToscaFunction(toscaGetInputFunction);
+        assertTrue(toscaFunction instanceof ToscaGetFunctionDataDefinition);
+        final ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) toscaFunction;
+        assertEquals(ToscaFunctionType.GET_INPUT, toscaGetFunction.getType());
+        assertEquals(ToscaGetFunctionType.GET_INPUT, toscaGetFunction.getFunctionType());
+    }
+
+    @Test
+    void testNoFunctionTypeProvided() {
+        final String toscaGetInputFunction = "{\n"
+            + "            \"propertyUniqueId\": \"e57525d7-2115-4934-9ba4-9cebfa22bad2.nf_naming\",\n"
+            + "            \"propertySource\": \"SELF\",\n"
+            + "            \"propertyName\": \"instance_name\",\n"
+            + "            \"sourceName\": \"ciResVFc26a0b30ec20\",\n"
+            + "            \"sourceUniqueId\": \"aee643c9-6c8e-4a24-af7a-a9aff5c072c0\",\n"
+            + "            \"propertyPathFromSource\": [\n"
+            + "                \"nf_naming\",\n"
+            + "                \"instance_name\"\n"
+            + "            ]\n"
+            + "        }";
+        final ValueInstantiationException actualException =
+            assertThrows(ValueInstantiationException.class, () -> parseToscaFunction(toscaGetInputFunction));
+        assertTrue(actualException.getMessage().contains("Attribute type not provided"));
+    }
+
+    @Test
+    void testConcatToscaFunction() throws JsonProcessingException {
+        final String toscaGetInputFunction = "{\n"
+            + "  \"type\": \"CONCAT\",\n"
+            + "  \"parameters\": [\n"
+            + "    {\n"
+            + "      \"propertyUniqueId\": \"e57525d7-2115-4934-9ba4-9cebfa22bad2.nf_naming\",\n"
+            + "      \"type\": \"GET_INPUT\",\n"
+            + "      \"propertySource\": \"SELF\",\n"
+            + "      \"propertyName\": \"instance_name\",\n"
+            + "      \"sourceName\": \"ciResVFc26a0b30ec20\",\n"
+            + "      \"sourceUniqueId\": \"aee643c9-6c8e-4a24-af7a-a9aff5c072c0\",\n"
+            + "      \"propertyPathFromSource\": [\n"
+            + "        \"nf_naming\",\n"
+            + "        \"instance_name\"\n"
+            + "      ]\n"
+            + "    }, {\n"
+            + "      \"type\": \"STRING\",\n"
+            + "      \"value\": \"my string\"\n"
+            + "    },\n"
+            + "    {\n"
+            + "      \"type\": \"CONCAT\",\n"
+            + "      \"parameters\": [\n"
+            + "        {\n"
+            + "          \"type\": \"STRING\",\n"
+            + "          \"value\": \"string1\"\n"
+            + "        },\n"
+            + "        {\n"
+            + "          \"type\": \"STRING\",\n"
+            + "          \"value\": \"string2\"\n"
+            + "        }\n"
+            + "      ]\n"
+            + "    }\n"
+            + "  ]\n"
+            + "}";
+        ToscaFunction toscaFunction = parseToscaFunction(toscaGetInputFunction);
+        assertTrue(toscaFunction instanceof ToscaConcatFunction);
+    }
+
+    @Test
+    void testYamlFunction() throws JsonProcessingException {
+        String yamlFunction = "{\n"
+            + "  \"type\": \"YAML\",\n"
+            + "  \"value\": \"tosca_definitions_version: tosca_simple_yaml_1_0_0\\nnode_types: \\n  tosca.nodes.Compute:\\n    derived_from: tosca.nodes.Root\\n    attributes:\\n      private_address:\\n        type: string\\n      public_address:\\n        type: string\\n      networks:\\n        type: map\\n        entry_schema:\\n          type: tosca.datatypes.network.NetworkInfo\\n      ports:\\n        type: map\\n        entry_schema:\\n          type: tosca.datatypes.network.PortInfo\\n    requirements:\\n      - local_storage: \\n          capability: tosca.capabilities.Attachment\\n          node: tosca.nodes.BlockStorage\\n          relationship: tosca.relationships.AttachesTo\\n          occurrences: [0, UNBOUNDED]  \\n    capabilities:\\n      host: \\n        type: tosca.capabilities.Container\\n        valid_source_types: [tosca.nodes.SoftwareComponent] \\n      endpoint :\\n        type: tosca.capabilities.Endpoint.Admin \\n      os: \\n        type: tosca.capabilities.OperatingSystem\\n      scalable:\\n        type: tosca.capabilities.Scalable\\n      binding:\\n        type: tosca.capabilities.network.Bindable\\n\"\n"
+            + "}";
+        ToscaFunction toscaFunction = parseToscaFunction(yamlFunction);
+        assertTrue(toscaFunction instanceof CustomYamlFunction);
+    }
+
+    private ToscaFunction parseToscaFunction(final String toscaFunctionJson) throws JsonProcessingException {
+        return new ObjectMapper().readValue(toscaFunctionJson, ToscaFunction.class);
+    }
+}
\ No newline at end of file
index a199f5e..5daeaa5 100644 (file)
@@ -23,6 +23,7 @@ package org.openecomp.sdc.be.datatypes.elements;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -185,6 +186,18 @@ class ToscaGetFunctionDataDefinitionTest {
         assertEquals("sourceName is required in order to generate the get_property from INSTANCE value", actualException.getMessage());
     }
 
+    @Test
+    void getTypeTest() {
+        final ToscaGetFunctionDataDefinition toscaGetFunctionDataDefinition = new ToscaGetFunctionDataDefinition();
+        assertNull(toscaGetFunctionDataDefinition.getType());
+        toscaGetFunctionDataDefinition.setFunctionType(ToscaGetFunctionType.GET_INPUT);
+        assertEquals(ToscaFunctionType.GET_INPUT, toscaGetFunctionDataDefinition.getType());
+        toscaGetFunctionDataDefinition.setFunctionType(ToscaGetFunctionType.GET_ATTRIBUTE);
+        assertEquals(ToscaFunctionType.GET_ATTRIBUTE, toscaGetFunctionDataDefinition.getType());
+        toscaGetFunctionDataDefinition.setFunctionType(ToscaGetFunctionType.GET_PROPERTY);
+        assertEquals(ToscaFunctionType.GET_PROPERTY, toscaGetFunctionDataDefinition.getType());
+    }
+
     private ToscaGetFunctionDataDefinition createGetFunction(final ToscaGetFunctionType toscaGetFunctionType,
                                                              final PropertySource propertySource,
                                                              final List<String> propertyPath, String sourceName) {