Backend support for custom functions 10/133910/7
authorJvD_Ericsson <jeff.van.dam@est.tech>
Wed, 29 Mar 2023 11:34:59 +0000 (12:34 +0100)
committerJvD_Ericsson <jeff.van.dam@est.tech>
Thu, 13 Apr 2023 08:03:40 +0000 (09:03 +0100)
Issue-ID: SDC-4455
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: Idb0fd38681066ba9d541f8564c85e316cf03e927

common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaCustomFunction.java [new file with mode: 0644]
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializer.java
common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionType.java
common-be/src/test/java/org/openecomp/sdc/be/datatypes/elements/ToscaFunctionJsonDeserializerTest.java
common-be/src/test/resources/toscaFunctionJsonDeserializer/customFunction.json [new file with mode: 0644]

diff --git a/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaCustomFunction.java b/common-be/src/main/java/org/openecomp/sdc/be/datatypes/elements/ToscaCustomFunction.java
new file mode 100644 (file)
index 0000000..3f0c4fa
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * -
+ *  ============LICENSE_START=======================================================
+ *  Copyright (C) 2023 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 lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Getter
+@Setter
+public class ToscaCustomFunction implements ToscaFunction, ToscaFunctionParameter {
+
+    private String name;
+    private List<ToscaFunctionParameter> parameters = new ArrayList<>();
+
+    @Override
+    public ToscaFunctionType getType() {
+        return ToscaFunctionType.CUSTOM;
+    }
+
+    @Override
+    public String getValue() {
+        return new Gson().toJson(getJsonObjectValue());
+    }
+
+    @Override
+    public Object getJsonObjectValue() {
+        return Map.of(
+                "$" + name,
+                parameters.stream().map(ToscaFunctionParameter::getJsonObjectValue).collect(Collectors.toList())
+        );
+    }
+
+    public void addParameter(final ToscaFunctionParameter functionParameter) {
+        this.parameters.add(functionParameter);
+    }
+
+}
index c262699..ec34599 100644 (file)
@@ -81,6 +81,10 @@ public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction
             return this.deserializeYamlFunction(node, context);
         }
 
+        if (toscaFunctionType == ToscaFunctionType.CUSTOM) {
+            return this.deserializeCustomFunction(node, context);
+        }
+
         return null;
     }
 
@@ -144,23 +148,43 @@ public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction
     private ToscaConcatFunction deserializeConcatFunction(final JsonNode concatFunctionJsonNode,
                                                           final DeserializationContext context) throws IOException {
         final var toscaConcatFunction = new ToscaConcatFunction();
+        List<ToscaFunctionParameter> functionParameterList = getParameters(concatFunctionJsonNode, context);
+        toscaConcatFunction.setParameters(functionParameterList);
+        return toscaConcatFunction;
+    }
+
+    private ToscaCustomFunction deserializeCustomFunction(final JsonNode customFunctionJsonNode,
+                                                          final DeserializationContext context) throws IOException {
+        final var toscaCustomFunction = new ToscaCustomFunction();
+        final String name = getAsTextOrElseNull(customFunctionJsonNode, "name");
+        if (name == null) {
+            throw context.instantiationException(List.class, "Expecting a string for the 'name' entry");
+        }
+        toscaCustomFunction.setName(name);
+        List<ToscaFunctionParameter> functionParameterList = getParameters(customFunctionJsonNode, context);
+        toscaCustomFunction.setParameters(functionParameterList);
+        return toscaCustomFunction;
+    }
+
+    private List<ToscaFunctionParameter> getParameters(final JsonNode functionJsonNode, final DeserializationContext context) throws IOException {
         final List<ToscaFunctionParameter> functionParameterList = new ArrayList<>();
-        final JsonNode parametersNode = concatFunctionJsonNode.get("parameters");
+        final JsonNode parametersNode = functionJsonNode.get("parameters");
         if (parametersNode == null) {
-            return toscaConcatFunction;
+            return functionParameterList;
         }
         if (!parametersNode.isArray()) {
             throw context.instantiationException(List.class, "Expecting an array for the 'parameters' entry");
         }
+
         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");
+                throw context.instantiationException(ToscaFunction.class, "TOSCA 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))
+                .orElseThrow(() -> context.instantiationException(ToscaFunction.class,
+                    String.format("Invalid TOSCA function parameter type '%s'", parameterType))
                 );
             if (toscaFunctionType == ToscaFunctionType.STRING) {
                 final ToscaStringParameter toscaStringParameter = new ToscaStringParameter();
@@ -171,8 +195,7 @@ public class ToscaFunctionJsonDeserializer extends StdDeserializer<ToscaFunction
                 functionParameterList.add((ToscaFunctionParameter) toscaFunction);
             }
         }
-        toscaConcatFunction.setParameters(functionParameterList);
-        return toscaConcatFunction;
+        return functionParameterList;
     }
 
 }
index 450c7d0..e65174b 100644 (file)
@@ -35,6 +35,7 @@ public enum ToscaFunctionType {
     GET_PROPERTY("get_property"),
     GET_ATTRIBUTE("get_attribute"),
     CONCAT("concat"),
+    CUSTOM("custom"),
     YAML("yaml"),
     STRING("string");
 
index b17a3dc..d7c2e7c 100644 (file)
@@ -139,6 +139,56 @@ class ToscaFunctionJsonDeserializerTest {
         assertDoesNotThrow(() -> new Yaml().load(toscaFunction.getValue()));
     }
 
+    @Test
+    void testCustomToscaFunction() throws IOException {
+        //given
+        final String toscaCustomFunction = Files.readString(TEST_RESOURCES_PATH.resolve("customFunction.json"));
+        //when
+        final ToscaFunction toscaFunction = parseToscaFunction(toscaCustomFunction);
+        //then
+        assertTrue(toscaFunction instanceof ToscaCustomFunction);
+        final Object yamlObject = new Yaml().load(toscaFunction.getValue());
+        assertTrue(yamlObject instanceof Map);
+        final Map<String, Object> yamlMap = (Map<String, Object>) yamlObject;
+        final Object customFunctionObj = yamlMap.get("$" + ((ToscaCustomFunction) toscaFunction).getName());
+        assertNotNull(customFunctionObj);
+        assertTrue(customFunctionObj instanceof List);
+        final List<Object> customFunctionParameters = (List<Object>) customFunctionObj;
+        assertEquals(3, customFunctionParameters.size(), "Expecting three parameters");
+        assertEquals("string1", customFunctionParameters.get(0));
+
+        assertTrue(customFunctionParameters.get(1) instanceof Map);
+        final Map<String, Object> parameter1Map = (Map<String, Object>) customFunctionParameters.get(1);
+        assertNotNull(parameter1Map.get(ToscaFunctionType.GET_ATTRIBUTE.getName()));
+        assertTrue(parameter1Map.get(ToscaFunctionType.GET_ATTRIBUTE.getName()) instanceof List);
+        List<String> getAttributeParameters = (List<String>) parameter1Map.get(ToscaFunctionType.GET_ATTRIBUTE.getName());
+        assertEquals(2, getAttributeParameters.size(), "Expecting two parameters in the get_attribute function");
+        assertEquals("SELF", getAttributeParameters.get(0));
+        assertEquals("descriptor_id", getAttributeParameters.get(1));
+
+        assertTrue(customFunctionParameters.get(2) instanceof Map);
+        final Map<String, Object> parameter2Map = (Map<String, Object>) customFunctionParameters.get(2);
+        Object customFunctionObj2 = parameter2Map.get(parameter2Map.keySet().stream().iterator().next());
+        assertNotNull(customFunctionObj2);
+        assertTrue(customFunctionObj2 instanceof List);
+        List<Object> customParameters = (List<Object>) customFunctionObj2;
+        assertEquals(2, customParameters.size(), "Expecting two parameters in the sub custom function");
+        assertTrue(customParameters.get(0) instanceof Map);
+        final Map<String, Object> concatFunctionValueMap = (Map<String, Object>) customParameters.get(0);
+        assertNotNull(concatFunctionValueMap.get(ToscaFunctionType.CONCAT.getName()));
+        assertTrue(concatFunctionValueMap.get(ToscaFunctionType.CONCAT.getName()) instanceof List);
+        List<Object> concatParameters = (List<Object>) concatFunctionValueMap.get(ToscaFunctionType.CONCAT.getName());
+        assertEquals(2, concatParameters.size(), "Expecting two parameters in the sub concat function");
+        assertEquals("string2", concatParameters.get(0));
+        assertTrue(concatParameters.get(1) instanceof Map);
+        Map<String, Object> yamlFunctionValueMap = (Map<String, Object>) concatParameters.get(1);
+        assertTrue(yamlFunctionValueMap.get("myList") instanceof List);
+        assertTrue(yamlFunctionValueMap.get("get_something") instanceof List);
+        assertTrue(yamlFunctionValueMap.get("string") instanceof String);
+
+        assertEquals("string3", customParameters.get(1));
+    }
+
     private ToscaFunction parseToscaFunction(final String toscaFunctionJson) throws JsonProcessingException {
         return new ObjectMapper().readValue(toscaFunctionJson, ToscaFunction.class);
     }
diff --git a/common-be/src/test/resources/toscaFunctionJsonDeserializer/customFunction.json b/common-be/src/test/resources/toscaFunctionJsonDeserializer/customFunction.json
new file mode 100644 (file)
index 0000000..0042975
--- /dev/null
@@ -0,0 +1,45 @@
+{
+  "type": "CUSTOM",
+  "name": "first_custom_function_name",
+  "parameters": [
+    {
+      "type": "STRING",
+      "value": "string1"
+    },
+    {
+      "type": "GET_ATTRIBUTE",
+      "propertyUniqueId": "36897651-f5e5-4603-8064-b60c771a3c37.descriptor_id",
+      "propertyName": "descriptor_id",
+      "propertySource": "SELF",
+      "sourceUniqueId": "36897651-f5e5-4603-8064-b60c771a3c37",
+      "sourceName": "testService",
+      "functionType": "GET_ATTRIBUTE",
+      "propertyPathFromSource": [
+        "descriptor_id"
+      ]
+    },
+    {
+      "type": "CUSTOM",
+      "name": "second_custom_function_name",
+      "parameters": [
+        {
+          "type": "CONCAT",
+          "parameters": [
+            {
+              "type": "STRING",
+              "value": "string2"
+            },
+            {
+              "type": "YAML",
+              "value": "myList: [1, two, three three]\nget_something: [SELF, something]\nstring: this is my string\n"
+            }
+          ]
+        },
+        {
+          "type": "STRING",
+          "value": "string3"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file