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.List;
26 import java.util.Objects;
27 import java.util.Optional;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30 import org.apache.commons.lang3.StringUtils;
31 import org.openecomp.sdc.be.datatypes.elements.CustomYamlFunction;
32 import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction;
33 import org.openecomp.sdc.be.datatypes.elements.ToscaCustomFunction;
34 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
35 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionParameter;
36 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
37 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
38 import org.openecomp.sdc.be.datatypes.elements.ToscaStringParameter;
39 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
40 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
42 @org.springframework.stereotype.Component
43 public class ToscaFunctionYamlParsingHandler {
45 private static Optional<ToscaFunction> handleGetPropertyFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType,
46 ToscaFunctionType toscaFunctionType) {
47 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
48 toscaGetFunction.setFunctionType(
49 toscaFunctionType == ToscaFunctionType.GET_PROPERTY ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
51 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
52 if (!(functionValueObj instanceof List)) {
53 return Optional.empty();
55 final List<String> functionParameters;
57 functionParameters = ((List<Object>) functionValueObj).stream()
58 .map(object -> Objects.toString(object, null))
59 .collect(Collectors.toList());
60 } catch (final ClassCastException ignored) {
61 return Optional.empty();
63 if (functionParameters.size() < 2) {
64 return Optional.empty();
66 final String propertySourceType = functionParameters.get(0);
67 final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
68 if (propertySource == PropertySource.SELF) {
69 toscaGetFunction.setPropertySource(propertySource);
71 toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
72 toscaGetFunction.setSourceName(propertySourceType);
74 List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
75 String toscaIndexValue = propertySourceIndex.get((propertySourceIndex.size() - 1));
76 if (propertySourceIndex.size() > 1 && (toscaIndexValue.equalsIgnoreCase("INDEX") || StringUtils.isNumeric(toscaIndexValue))) {
77 toscaGetFunction.setPropertyPathFromSource(propertySourceIndex.subList(0,(propertySourceIndex.size() - 1)));
78 toscaGetFunction.setToscaIndex(toscaIndexValue);
80 toscaGetFunction.setPropertyPathFromSource(propertySourceIndex);
82 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
83 toscaGetFunction.setPropertyName(propertyName);
84 return Optional.of(toscaGetFunction);
87 private static Optional<ToscaFunction> handleGetInputFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
88 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
89 toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
90 toscaGetFunction.setPropertySource(PropertySource.SELF);
91 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
92 if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
93 return Optional.empty();
95 if (functionValueObj instanceof String) {
96 toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
98 final List<String> functionParameters;
100 functionParameters = ((List<Object>) functionValueObj).stream()
101 .map(object -> Objects.toString(object, null))
102 .collect(Collectors.toList());
103 } catch (final ClassCastException ignored) {
104 return Optional.empty();
106 String toscaIndexValue = functionParameters.get((functionParameters.size() - 1));
107 if (functionParameters.size() > 1 && (toscaIndexValue.equalsIgnoreCase("INDEX") || StringUtils.isNumeric(toscaIndexValue))) {
108 toscaGetFunction.setPropertyPathFromSource(functionParameters.subList(0,(functionParameters.size() - 1)));
109 toscaGetFunction.setToscaIndex(toscaIndexValue);
111 toscaGetFunction.setPropertyPathFromSource(functionParameters);
114 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
115 toscaGetFunction.setPropertyName(propertyName);
116 return Optional.of(toscaGetFunction);
120 * Builds a {@link ToscaFunction} based on the property value. It will build the object with the maximum information available in the property
121 * value, as not all the necessary information can be extracted from it. It will only parse values from supported functions in
122 * {@link ToscaFunctionType}.
124 * @param toscaFunctionPropertyValueMap the value of a property calls a TOSCA function
125 * @return the partially filled {@link ToscaFunction} object
127 public Optional<ToscaFunction> buildToscaFunctionBasedOnPropertyValue(final Map<String, Object> toscaFunctionPropertyValueMap) {
128 if (!isPropertyValueToscaFunction(toscaFunctionPropertyValueMap)) {
129 return Optional.empty();
131 final String functionType = toscaFunctionPropertyValueMap.keySet().iterator().next();
132 final ToscaFunctionType toscaFunctionType =
133 ToscaFunctionType.findType(functionType).orElse(functionType.startsWith("$") ? ToscaFunctionType.CUSTOM : null);
134 if (toscaFunctionType == null) {
135 return Optional.empty();
137 switch (toscaFunctionType) {
139 return handleGetInputFunction(toscaFunctionPropertyValueMap, functionType);
142 case GET_ATTRIBUTE: {
143 return handleGetPropertyFunction(toscaFunctionPropertyValueMap, functionType, toscaFunctionType);
146 return handleConcatFunction(toscaFunctionPropertyValueMap, functionType);
148 return handleCustomFunction(toscaFunctionPropertyValueMap, functionType);
150 return Optional.empty();
154 private Optional<ToscaFunction> handleCustomFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
155 final ToscaCustomFunction toscaCustomFunction = new ToscaCustomFunction();
156 toscaCustomFunction.setName(functionType.substring(1));
157 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
158 if (!(functionValueObj instanceof List)) {
159 return Optional.empty();
161 final List<Object> functionParameters = (List<Object>) functionValueObj;
162 functionParameters.forEach(parameter -> {
163 if (parameter instanceof String) {
164 final var stringParameter = new ToscaStringParameter();
165 stringParameter.setValue((String) parameter);
166 toscaCustomFunction.addParameter(stringParameter);
169 if (isPropertyValueToscaFunction(parameter)) {
170 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
171 if (toscaFunction instanceof ToscaFunctionParameter) {
172 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
177 final var customYamlFunction = new CustomYamlFunction();
178 customYamlFunction.setYamlValue(parameter);
179 toscaCustomFunction.addParameter(customYamlFunction);
181 return Optional.of(toscaCustomFunction);
185 * Checks if the property value is a supported TOSCA function.
187 * @param propValueObj the value of a property
188 * @return {@code true} if the value is a supported TOSCA function, {@code false} otherwise
190 public boolean isPropertyValueToscaFunction(final Object propValueObj) {
191 if (propValueObj instanceof Map) {
192 final Map<String, Object> propValueMap = (Map<String, Object>) propValueObj;
193 if (propValueMap.keySet().size() > 1) {
196 if (propValueMap.keySet().stream().anyMatch(keyValue -> keyValue.startsWith("$"))) {
200 return Stream.of(ToscaFunctionType.GET_INPUT, ToscaFunctionType.GET_PROPERTY, ToscaFunctionType.GET_ATTRIBUTE, ToscaFunctionType.CONCAT)
201 .anyMatch(type -> propValueMap.containsKey(type.getName()));
206 private Optional<ToscaFunction> handleConcatFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
207 final ToscaConcatFunction toscaConcatFunction = new ToscaConcatFunction();
208 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
209 if (!(functionValueObj instanceof List)) {
210 return Optional.empty();
212 final List<Object> functionParameters = (List<Object>) functionValueObj;
213 if (functionParameters.size() < 2) {
214 return Optional.empty();
216 functionParameters.forEach(parameter -> {
217 if (parameter instanceof String) {
218 final var stringParameter = new ToscaStringParameter();
219 stringParameter.setValue((String) parameter);
220 toscaConcatFunction.addParameter(stringParameter);
223 if (isPropertyValueToscaFunction(parameter)) {
224 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
225 if (toscaFunction instanceof ToscaFunctionParameter) {
226 toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction);
231 final var customYamlFunction = new CustomYamlFunction();
232 customYamlFunction.setYamlValue(parameter);
233 toscaConcatFunction.addParameter(customYamlFunction);
235 return Optional.of(toscaConcatFunction);