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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.openecomp.sdc.be.components.csar;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.Objects;
29 import java.util.Optional;
30 import java.util.stream.Collectors;
31 import java.util.stream.Stream;
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.openecomp.sdc.be.config.Configuration;
35 import org.openecomp.sdc.be.config.ConfigurationManager;
36 import org.openecomp.sdc.be.datatypes.elements.CustomYamlFunction;
37 import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction;
38 import org.openecomp.sdc.be.datatypes.elements.ToscaCustomFunction;
39 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
40 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionParameter;
41 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
42 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
43 import org.openecomp.sdc.be.datatypes.elements.ToscaStringParameter;
44 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
45 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
47 @org.springframework.stereotype.Component
48 public class ToscaFunctionYamlParsingHandler {
50 private static Optional<ToscaFunction> handleGetPropertyFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType,
51 ToscaFunctionType toscaFunctionType) {
52 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
53 toscaGetFunction.setFunctionType(
54 toscaFunctionType == ToscaFunctionType.GET_PROPERTY ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
56 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
57 if (!(functionValueObj instanceof List)) {
58 return Optional.empty();
60 final List<String> functionParameters;
62 functionParameters = ((List<Object>) functionValueObj).stream()
63 .map(object -> Objects.toString(object, null))
64 .collect(Collectors.toList());
65 } catch (final ClassCastException ignored) {
66 return Optional.empty();
68 if (functionParameters.size() < 2) {
69 return Optional.empty();
71 final String propertySourceType = functionParameters.get(0);
72 final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
73 if (propertySource == PropertySource.SELF) {
74 toscaGetFunction.setPropertySource(propertySource);
76 toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
77 toscaGetFunction.setSourceName(propertySourceType);
79 List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
80 List<String> propertySourcePath = new ArrayList<>();
81 propertySourcePath.add((String)propertySourceIndex.get(0));
82 if (propertySourceIndex.size() > 1 ) {
83 List<Object> indexParsedList = new ArrayList<Object>();
84 List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
85 boolean loopFlag = true;
86 for (String indexValue : indexObjectList) {
87 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
88 propertySourcePath.add(indexValue);
91 if (StringUtils.isNumeric(indexValue)) {
92 indexParsedList.add(Integer.parseInt(indexValue));
94 indexParsedList.add(indexValue);
98 toscaGetFunction.setToscaIndexList(indexParsedList);
100 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
101 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
102 toscaGetFunction.setPropertyName(propertyName);
103 return Optional.of(toscaGetFunction);
106 private static Optional<ToscaFunction> handleGetInputFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
107 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
108 toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
109 toscaGetFunction.setPropertySource(PropertySource.SELF);
110 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
111 if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
112 return Optional.empty();
114 if (functionValueObj instanceof String) {
115 toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
117 final List<String> functionParameters;
119 functionParameters = ((List<Object>) functionValueObj).stream()
120 .map(object -> Objects.toString(object, null))
121 .collect(Collectors.toList());
122 } catch (final ClassCastException ignored) {
123 return Optional.empty();
125 List<String> propertySourcePath = new ArrayList<>();
126 propertySourcePath.add((String)functionParameters.get(0));
127 if (functionParameters.size() > 1 ) {
128 List<Object> indexParsedList = new ArrayList<Object>();
129 List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
130 boolean loopFlag = true;
131 for (String indexValue : indexObjectList) {
132 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
133 propertySourcePath.add(indexValue);
136 if (StringUtils.isNumeric(indexValue)) {
137 indexParsedList.add(Integer.parseInt(indexValue));
139 indexParsedList.add(indexValue);
143 toscaGetFunction.setToscaIndexList(indexParsedList);
145 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
147 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
148 toscaGetFunction.setPropertyName(propertyName);
149 return Optional.of(toscaGetFunction);
153 * Builds a {@link ToscaFunction} based on the property value. It will build the object with the maximum information available in the property
154 * value, as not all the necessary information can be extracted from it. It will only parse values from supported functions in
155 * {@link ToscaFunctionType}.
157 * @param toscaFunctionPropertyValueMap the value of a property calls a TOSCA function
158 * @return the partially filled {@link ToscaFunction} object
160 public Optional<ToscaFunction> buildToscaFunctionBasedOnPropertyValue(final Map<String, Object> toscaFunctionPropertyValueMap) {
161 if (!isPropertyValueToscaFunction(toscaFunctionPropertyValueMap)) {
162 return Optional.empty();
164 final String functionType = toscaFunctionPropertyValueMap.keySet().iterator().next();
165 final ToscaFunctionType toscaFunctionType =
166 ToscaFunctionType.findType(functionType).orElse(functionType.startsWith("$") ? ToscaFunctionType.CUSTOM : null);
167 if (toscaFunctionType == null) {
168 return Optional.empty();
170 switch (toscaFunctionType) {
172 return handleGetInputFunction(toscaFunctionPropertyValueMap, functionType);
175 case GET_ATTRIBUTE: {
176 return handleGetPropertyFunction(toscaFunctionPropertyValueMap, functionType, toscaFunctionType);
179 return handleConcatFunction(toscaFunctionPropertyValueMap, functionType);
181 return handleCustomFunction(toscaFunctionPropertyValueMap, functionType);
183 return Optional.empty();
187 private Optional<ToscaFunction> handleCustomFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
188 final ToscaCustomFunction toscaCustomFunction = new ToscaCustomFunction();
189 toscaCustomFunction.setName(functionType.substring(1));
190 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
191 toscaCustomFunction.setToscaFunctionType(getCustomFunctionType(toscaCustomFunction.getName()));
192 if (ToscaFunctionType.GET_INPUT.equals(toscaCustomFunction.getToscaFunctionType())) {
193 return handelCustomFunctionGetInputType(toscaCustomFunction, functionValueObj);
195 return handelCustomFunctionCustomType(toscaCustomFunction, functionValueObj);
198 private Optional<ToscaFunction> handelCustomFunctionCustomType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
199 if (!(functionValueObj instanceof List)) {
200 return Optional.empty();
202 final List<Object> functionParameters = (List<Object>) functionValueObj;
203 functionParameters.forEach(parameter -> {
204 if (parameter instanceof String) {
205 final var stringParameter = new ToscaStringParameter();
206 stringParameter.setValue((String) parameter);
207 toscaCustomFunction.addParameter(stringParameter);
210 if (isPropertyValueToscaFunction(parameter)) {
211 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
212 if (toscaFunction instanceof ToscaFunctionParameter) {
213 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
218 final var customYamlFunction = new CustomYamlFunction();
219 customYamlFunction.setYamlValue(parameter);
220 toscaCustomFunction.addParameter(customYamlFunction);
222 return Optional.of(toscaCustomFunction);
225 private Optional<ToscaFunction> handelCustomFunctionGetInputType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
226 if (!(functionValueObj instanceof String) && !(functionValueObj instanceof List)) {
227 return Optional.empty();
229 Map<String, Object> parameterMap = new HashMap<>();
230 parameterMap.put(ToscaFunctionType.GET_INPUT.getName(), functionValueObj);
231 buildToscaFunctionBasedOnPropertyValue(parameterMap).ifPresent(toscaFunction -> {
232 if (toscaFunction instanceof ToscaFunctionParameter) {
233 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
236 return Optional.of(toscaCustomFunction);
239 private ToscaFunctionType getCustomFunctionType(String name) {
240 List<Configuration.CustomToscaFunction> customFunctions =
241 ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultCustomToscaFunctions();
242 if (CollectionUtils.isEmpty(customFunctions)) {
243 return ToscaFunctionType.CUSTOM;
245 Optional<Configuration.CustomToscaFunction> optionalFunc = customFunctions.stream().filter(func -> func.getName().equals(name)).findFirst();
246 if (optionalFunc.isEmpty()) {
247 return ToscaFunctionType.CUSTOM;
249 String type = optionalFunc.get().getType();
250 return ToscaFunctionType.findType(type).get();
254 * Checks if the property value is a supported TOSCA function.
256 * @param propValueObj the value of a property
257 * @return {@code true} if the value is a supported TOSCA function, {@code false} otherwise
259 public boolean isPropertyValueToscaFunction(final Object propValueObj) {
260 if (propValueObj instanceof Map) {
261 final Map<String, Object> propValueMap = (Map<String, Object>) propValueObj;
262 if (propValueMap.keySet().size() > 1) {
265 if (propValueMap.keySet().stream().anyMatch(keyValue -> keyValue.startsWith("$"))) {
269 return Stream.of(ToscaFunctionType.GET_INPUT, ToscaFunctionType.GET_PROPERTY, ToscaFunctionType.GET_ATTRIBUTE, ToscaFunctionType.CONCAT)
270 .anyMatch(type -> propValueMap.containsKey(type.getName()));
275 private Optional<ToscaFunction> handleConcatFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
276 final ToscaConcatFunction toscaConcatFunction = new ToscaConcatFunction();
277 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
278 if (!(functionValueObj instanceof List)) {
279 return Optional.empty();
281 final List<Object> functionParameters = (List<Object>) functionValueObj;
282 if (functionParameters.size() < 2) {
283 return Optional.empty();
285 functionParameters.forEach(parameter -> {
286 if (parameter instanceof String) {
287 final var stringParameter = new ToscaStringParameter();
288 stringParameter.setValue((String) parameter);
289 toscaConcatFunction.addParameter(stringParameter);
292 if (isPropertyValueToscaFunction(parameter)) {
293 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
294 if (toscaFunction instanceof ToscaFunctionParameter) {
295 toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction);
300 final var customYamlFunction = new CustomYamlFunction();
301 customYamlFunction.setYamlValue(parameter);
302 toscaConcatFunction.addParameter(customYamlFunction);
304 return Optional.of(toscaConcatFunction);