Support for TOSCA functions for Service Import
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / csar / ToscaFunctionYamlParsingHandler.java
1 /*
2  * -
3  *  ============LICENSE_START=======================================================
4  *  Copyright (C) 2022 Nordix Foundation.
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.sdc.be.components.csar;
23
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.stream.Stream;
28 import org.openecomp.sdc.be.datatypes.elements.CustomYamlFunction;
29 import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction;
30 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
31 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionParameter;
32 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
33 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
34 import org.openecomp.sdc.be.datatypes.elements.ToscaStringParameter;
35 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
36 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
37
38 @org.springframework.stereotype.Component
39 public class ToscaFunctionYamlParsingHandler {
40
41     /**
42      * Builds a {@link ToscaFunction} based on the property value. It will build the object with the maximum information available in the property
43      * value, as not all the necessary information can be extracted from it. It will only parse values from supported functions in
44      * {@link ToscaFunctionType}.
45      *
46      * @param toscaFunctionPropertyValueMap the value of a property calls a TOSCA function
47      * @return the partially filled {@link ToscaFunction} object
48      */
49     public Optional<ToscaFunction> buildToscaFunctionBasedOnPropertyValue(final Map<String, Object> toscaFunctionPropertyValueMap) {
50         if (!isPropertyValueToscaFunction(toscaFunctionPropertyValueMap)) {
51             return Optional.empty();
52         }
53         final String functionType = toscaFunctionPropertyValueMap.keySet().iterator().next();
54         final ToscaFunctionType toscaFunctionType = ToscaFunctionType.findType(functionType).orElse(null);
55         if (toscaFunctionType == null) {
56             return Optional.empty();
57         }
58         switch (toscaFunctionType) {
59             case GET_INPUT: {
60                 return handleGetInputFunction(toscaFunctionPropertyValueMap, functionType);
61             }
62             case GET_PROPERTY:
63             case GET_ATTRIBUTE: {
64                 return handleGetPropertyFunction(toscaFunctionPropertyValueMap, functionType, toscaFunctionType);
65             }
66             case CONCAT:
67                 return handleConcatFunction(toscaFunctionPropertyValueMap, functionType);
68             default:
69                 return Optional.empty();
70         }
71     }
72
73     /**
74      * Checks if the property value is a supported TOSCA function.
75      *
76      * @param propValueObj the value of a property
77      * @return {@code true} if the value is a supported TOSCA function, {@code false} otherwise
78      */
79     public boolean isPropertyValueToscaFunction(final Object propValueObj) {
80         if (propValueObj instanceof Map) {
81             final Map<String, Object> propValueMap = (Map<String, Object>) propValueObj;
82             if (propValueMap.keySet().size() > 1) {
83                 return false;
84             }
85             return Stream.of(ToscaFunctionType.GET_INPUT, ToscaFunctionType.GET_PROPERTY, ToscaFunctionType.GET_ATTRIBUTE, ToscaFunctionType.CONCAT)
86                 .anyMatch(type -> propValueMap.containsKey(type.getName()));
87         }
88         return false;
89     }
90
91     private Optional<ToscaFunction> handleConcatFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
92         final ToscaConcatFunction toscaConcatFunction = new ToscaConcatFunction();
93         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
94         if (!(functionValueObj instanceof List)) {
95             return Optional.empty();
96         }
97         final List<Object> functionParameters = (List<Object>) functionValueObj;
98         if (functionParameters.size() < 2) {
99             return Optional.empty();
100         }
101         functionParameters.forEach(parameter -> {
102             if (parameter instanceof String) {
103                 final var stringParameter = new ToscaStringParameter();
104                 stringParameter.setValue((String) parameter);
105                 toscaConcatFunction.addParameter(stringParameter);
106                 return;
107             }
108             if (isPropertyValueToscaFunction(parameter)) {
109                 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
110                     if (toscaFunction instanceof ToscaFunctionParameter) {
111                         toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction);
112                     }
113                 });
114                 return;
115             }
116             final var customYamlFunction = new CustomYamlFunction();
117             customYamlFunction.setYamlValue(parameter);
118             toscaConcatFunction.addParameter(customYamlFunction);
119         });
120         return Optional.of(toscaConcatFunction);
121     }
122
123     private static Optional<ToscaFunction> handleGetPropertyFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType,
124                                                                      ToscaFunctionType toscaFunctionType) {
125         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
126         toscaGetFunction.setFunctionType(
127             toscaFunctionType == ToscaFunctionType.GET_PROPERTY ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
128         );
129         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
130         if (!(functionValueObj instanceof List)) {
131             return Optional.empty();
132         }
133         final List<String> functionParameters;
134         try {
135             functionParameters = (List<String>) functionValueObj;
136         } catch (final ClassCastException ignored) {
137             return Optional.empty();
138         }
139         if (functionParameters.size() < 2) {
140             return Optional.empty();
141         }
142         final String propertySourceType = functionParameters.get(0);
143         final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
144         if (propertySource == PropertySource.SELF) {
145             toscaGetFunction.setPropertySource(propertySource);
146         } else {
147             toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
148             toscaGetFunction.setSourceName(propertySourceType);
149         }
150         toscaGetFunction.setPropertyPathFromSource(functionParameters.subList(1, functionParameters.size()));
151         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
152         toscaGetFunction.setPropertyName(propertyName);
153         return Optional.of(toscaGetFunction);
154     }
155
156     private static Optional<ToscaFunction> handleGetInputFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
157         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
158         toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
159         toscaGetFunction.setPropertySource(PropertySource.SELF);
160         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
161         if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
162             return Optional.empty();
163         }
164         if (functionValueObj instanceof String) {
165             toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
166         } else {
167             final List<String> functionParameters;
168             try {
169                 functionParameters = (List<String>) functionValueObj;
170             } catch (final ClassCastException ignored) {
171                 return Optional.empty();
172             }
173             toscaGetFunction.setPropertyPathFromSource(functionParameters);
174         }
175         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
176         toscaGetFunction.setPropertyName(propertyName);
177         return Optional.of(toscaGetFunction);
178     }
179
180 }