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.utils;
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;
31 import java.util.stream.Collectors;
32 import java.util.stream.Stream;
33 import lombok.AccessLevel;
34 import lombok.NoArgsConstructor;
35 import org.apache.commons.collections.CollectionUtils;
36 import org.apache.commons.lang3.StringUtils;
37 import org.openecomp.sdc.be.config.Configuration;
38 import org.openecomp.sdc.be.config.ConfigurationManager;
39 import org.openecomp.sdc.be.datatypes.elements.CustomYamlFunction;
40 import org.openecomp.sdc.be.datatypes.elements.PropertyFilterConstraintDataDefinition;
41 import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction;
42 import org.openecomp.sdc.be.datatypes.elements.ToscaCustomFunction;
43 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
44 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionParameter;
45 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
46 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
47 import org.openecomp.sdc.be.datatypes.elements.ToscaStringParameter;
48 import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
49 import org.openecomp.sdc.be.datatypes.enums.FilterValueType;
50 import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType;
51 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
52 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
53 import org.yaml.snakeyaml.Yaml;
55 @NoArgsConstructor(access = AccessLevel.PRIVATE)
56 public class PropertyFilterConstraintDataDefinitionHelper {
58 public static PropertyFilterConstraintDataDefinition convertLegacyConstraint(final String constraint) {
59 final var propertyFilterConstraint = new PropertyFilterConstraintDataDefinition();
60 final Map<String, Object> constraintYaml = new Yaml().load(constraint);
61 final String propertyName = constraintYaml.keySet().iterator().next();
62 propertyFilterConstraint.setPropertyName(propertyName);
63 final Map<String, Object> operatorYaml = (Map<String, Object>) constraintYaml.get(propertyName);
64 final String operator = operatorYaml.keySet().iterator().next();
65 propertyFilterConstraint.setOperator(ConstraintType.findByType(operator).orElse(null));
66 final Object valueYaml = operatorYaml.get(operator);
67 final Optional<ToscaFunction> toscaFunction = createToscaFunctionFromLegacyConstraintValue(valueYaml);
68 if (toscaFunction.isPresent()) {
69 propertyFilterConstraint.setValue(toscaFunction.get());
71 propertyFilterConstraint.setValue(valueYaml);
73 propertyFilterConstraint.setValueType(detectValueType(valueYaml));
74 propertyFilterConstraint.setTargetType(PropertyFilterTargetType.PROPERTY);
75 return propertyFilterConstraint;
78 public static Optional<ToscaFunction> createToscaFunctionFromLegacyConstraintValue(final Object filterValue) {
79 if (!(filterValue instanceof Map)) {
80 return Optional.empty();
82 final Map<?, ?> filterValueAsMap = (Map<?, ?>) filterValue;
83 final Set<?> keys = filterValueAsMap.keySet();
84 if (keys.size() != 1) {
85 return Optional.empty();
87 final Object toscaFunctionTypeObject = keys.iterator().next();
88 if (!(toscaFunctionTypeObject instanceof String)) {
89 return Optional.empty();
91 ToscaFunctionType toscaFunctionType = ToscaFunctionType.findType((String) toscaFunctionTypeObject).orElse(null);
92 if (toscaFunctionType == null) {
93 if (((String) toscaFunctionTypeObject).equalsIgnoreCase("$get_input_ext") ||
94 ((String) toscaFunctionTypeObject).equalsIgnoreCase("$juel") ||
95 ((String) toscaFunctionTypeObject).equalsIgnoreCase("$other")) {
96 toscaFunctionType = ToscaFunctionType.CUSTOM;
99 return Optional.empty();
102 switch (toscaFunctionType) {
104 return readLegacyGetInputConstraintValue(filterValueAsMap, toscaFunctionTypeObject);
107 return readLegacyGetPropertyConstraintValue(filterValueAsMap, toscaFunctionTypeObject, toscaFunctionType);
109 return readLegacyConcatConstraintValue(filterValueAsMap, toscaFunctionTypeObject);
111 return handleCustomFunction((Map<String, Object>)filterValueAsMap, (String)toscaFunctionTypeObject);
113 return Optional.empty();
117 private static Optional<ToscaFunction> handleCustomFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
118 final ToscaCustomFunction toscaCustomFunction = new ToscaCustomFunction();
119 toscaCustomFunction.setName(functionType.substring(1));
120 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
121 toscaCustomFunction.setToscaFunctionType(getCustomFunctionType(toscaCustomFunction.getName()));
122 if (ToscaFunctionType.GET_INPUT.equals(toscaCustomFunction.getToscaFunctionType())) {
123 return handleCustomFunctionGetInputType(toscaCustomFunction, functionValueObj);
125 return handelCustomFunctionCustomType(toscaCustomFunction, functionValueObj);
128 private static Optional<ToscaFunction> handleCustomFunctionGetInputType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
129 if (!(functionValueObj instanceof String) && !(functionValueObj instanceof List)) {
130 return Optional.empty();
132 Map<String, Object> parameterMap = new HashMap<>();
133 parameterMap.put(ToscaFunctionType.GET_INPUT.getName(), functionValueObj);
134 buildToscaFunctionBasedOnPropertyValue(parameterMap).ifPresent(toscaFunction -> {
135 if (toscaFunction instanceof ToscaFunctionParameter) {
136 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
139 return Optional.of(toscaCustomFunction);
142 private static Optional<ToscaFunction> buildToscaFunctionBasedOnPropertyValue(final Map<String, Object> toscaFunctionPropertyValueMap) {
143 if (!isPropertyValueToscaFunction(toscaFunctionPropertyValueMap)) {
144 return Optional.empty();
146 final String functionType = toscaFunctionPropertyValueMap.keySet().iterator().next();
147 final ToscaFunctionType toscaFunctionType =
148 ToscaFunctionType.findType(functionType).orElse(functionType.startsWith("$") ? ToscaFunctionType.CUSTOM : null);
149 if (toscaFunctionType == null) {
150 return Optional.empty();
152 switch (toscaFunctionType) {
154 return handleGetInputFunction(toscaFunctionPropertyValueMap, functionType);
157 case GET_ATTRIBUTE: {
158 return handleGetPropertyFunction(toscaFunctionPropertyValueMap, functionType, toscaFunctionType);
161 return handleConcatFunction(toscaFunctionPropertyValueMap, functionType);
163 return handleCustomFunction(toscaFunctionPropertyValueMap, functionType);
165 return Optional.empty();
169 private static Optional<ToscaFunction> handleConcatFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
170 final ToscaConcatFunction toscaConcatFunction = new ToscaConcatFunction();
171 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
172 if (!(functionValueObj instanceof List)) {
173 return Optional.empty();
175 final List<Object> functionParameters = (List<Object>) functionValueObj;
176 if (functionParameters.size() < 2) {
177 return Optional.empty();
179 functionParameters.forEach(parameter -> {
180 if (parameter instanceof String) {
181 final var stringParameter = new ToscaStringParameter();
182 stringParameter.setValue((String) parameter);
183 toscaConcatFunction.addParameter(stringParameter);
186 if (isPropertyValueToscaFunction(parameter)) {
187 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
188 if (toscaFunction instanceof ToscaFunctionParameter) {
189 toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction);
194 final var customYamlFunction = new CustomYamlFunction();
195 customYamlFunction.setYamlValue(parameter);
196 toscaConcatFunction.addParameter(customYamlFunction);
198 return Optional.of(toscaConcatFunction);
201 private static Optional<ToscaFunction> handleGetPropertyFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType,
202 ToscaFunctionType toscaFunctionType) {
203 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
204 toscaGetFunction.setFunctionType(
205 toscaFunctionType == ToscaFunctionType.GET_PROPERTY ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
207 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
208 if (!(functionValueObj instanceof List)) {
209 return Optional.empty();
211 final List<String> functionParameters;
213 functionParameters = ((List<Object>) functionValueObj).stream()
214 .map(object -> Objects.toString(object, null))
215 .collect(Collectors.toList());
216 } catch (final ClassCastException ignored) {
217 return Optional.empty();
219 if (functionParameters.size() < 2) {
220 return Optional.empty();
222 final String propertySourceType = functionParameters.get(0);
223 final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
224 if (propertySource == PropertySource.SELF) {
225 toscaGetFunction.setPropertySource(propertySource);
227 toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
228 toscaGetFunction.setSourceName(propertySourceType);
230 List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
231 List<String> propertySourcePath = new ArrayList<>();
232 propertySourcePath.add((String)propertySourceIndex.get(0));
233 if (propertySourceIndex.size() > 1 ) {
234 List<Object> indexParsedList = new ArrayList<Object>();
235 List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
236 boolean loopFlag = true;
237 for (String indexValue : indexObjectList) {
238 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
239 propertySourcePath.add(indexValue);
242 if (StringUtils.isNumeric(indexValue)) {
243 indexParsedList.add(Integer.parseInt(indexValue));
245 indexParsedList.add(indexValue);
249 toscaGetFunction.setToscaIndexList(indexParsedList);
251 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
252 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
253 toscaGetFunction.setPropertyName(propertyName);
254 return Optional.of(toscaGetFunction);
257 private static Optional<ToscaFunction> handleGetInputFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
258 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
259 toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
260 toscaGetFunction.setPropertySource(PropertySource.SELF);
261 final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
262 if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
263 return Optional.empty();
265 if (functionValueObj instanceof String) {
266 toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
268 final List<String> functionParameters;
270 functionParameters = ((List<Object>) functionValueObj).stream()
271 .map(object -> Objects.toString(object, null))
272 .collect(Collectors.toList());
273 } catch (final ClassCastException ignored) {
274 return Optional.empty();
276 List<String> propertySourcePath = new ArrayList<>();
277 propertySourcePath.add((String)functionParameters.get(0));
278 if (functionParameters.size() > 1 ) {
279 List<Object> indexParsedList = new ArrayList<Object>();
280 List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
281 boolean loopFlag = true;
282 for (String indexValue : indexObjectList) {
283 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
284 propertySourcePath.add(indexValue);
287 if (StringUtils.isNumeric(indexValue)) {
288 indexParsedList.add(Integer.parseInt(indexValue));
290 indexParsedList.add(indexValue);
294 toscaGetFunction.setToscaIndexList(indexParsedList);
296 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
298 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
299 toscaGetFunction.setPropertyName(propertyName);
300 return Optional.of(toscaGetFunction);
303 public static boolean isPropertyValueToscaFunction(final Object propValueObj) {
304 if (propValueObj instanceof Map) {
305 final Map<String, Object> propValueMap = (Map<String, Object>) propValueObj;
306 if (propValueMap.keySet().size() > 1) {
309 if (propValueMap.keySet().stream().anyMatch(keyValue -> keyValue.startsWith("$"))) {
313 return Stream.of(ToscaFunctionType.GET_INPUT, ToscaFunctionType.GET_PROPERTY, ToscaFunctionType.GET_ATTRIBUTE, ToscaFunctionType.CONCAT)
314 .anyMatch(type -> propValueMap.containsKey(type.getName()));
319 private static ToscaFunctionType getCustomFunctionType(String name) {
320 List<Configuration.CustomToscaFunction> customFunctions =
321 ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultCustomToscaFunctions();
322 if (CollectionUtils.isEmpty(customFunctions)) {
323 return ToscaFunctionType.CUSTOM;
325 Optional<Configuration.CustomToscaFunction> optionalFunc = customFunctions.stream().filter(func -> func.getName().equals(name)).findFirst();
326 if (optionalFunc.isEmpty()) {
327 return ToscaFunctionType.CUSTOM;
329 String type = optionalFunc.get().getType();
330 return ToscaFunctionType.findType(type).get();
333 private static Optional<ToscaFunction> handelCustomFunctionCustomType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
334 if (!(functionValueObj instanceof List)) {
335 return Optional.empty();
337 final List<Object> functionParameters = (List<Object>) functionValueObj;
338 functionParameters.forEach(parameter -> {
339 if (parameter instanceof String) {
340 final var stringParameter = new ToscaStringParameter();
341 stringParameter.setValue((String) parameter);
342 toscaCustomFunction.addParameter(stringParameter);
345 if (isPropertyValueToscaFunction(parameter)) {
346 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
347 if (toscaFunction instanceof ToscaFunctionParameter) {
348 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
353 final var customYamlFunction = new CustomYamlFunction();
354 customYamlFunction.setYamlValue(parameter);
355 toscaCustomFunction.addParameter(customYamlFunction);
357 return Optional.of(toscaCustomFunction);
360 public static Optional<FilterValueType> convertFromToscaFunctionType(final ToscaFunctionType toscaFunctionType) {
361 return FilterValueType.findByName(toscaFunctionType.getName());
364 private static Optional<ToscaFunction> readLegacyConcatConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType) {
365 final List<Object> concatValue;
367 concatValue = (List<Object>) filterValueAsMap.get(toscaFunctionType);
368 } catch (final Exception ignored) {
369 return Optional.empty();
371 if (concatValue.isEmpty()) {
372 return Optional.empty();
374 final var toscaConcatFunction = new ToscaConcatFunction();
375 for (Object parameter : concatValue) {
376 if (parameter instanceof String) {
377 final ToscaStringParameter toscaStringParameter = new ToscaStringParameter();
378 toscaStringParameter.setValue((String) parameter);
379 toscaConcatFunction.addParameter(toscaStringParameter);
381 createToscaFunctionFromLegacyConstraintValue(parameter)
382 .ifPresent(toscaFunction -> toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction));
385 return Optional.of(toscaConcatFunction);
388 private static Optional<ToscaFunction> readLegacyGetPropertyConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType,
389 ToscaFunctionType toscaFunctionType1) {
390 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
391 toscaGetFunction.setFunctionType(
392 toscaFunctionType.toString().equalsIgnoreCase(ToscaFunctionType.GET_PROPERTY.getName()) ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
394 final Object functionValueObj = null != filterValueAsMap.get(toscaFunctionType1) ?
395 filterValueAsMap.get(toscaFunctionType1) : filterValueAsMap.get(toscaFunctionType);
396 if (!(functionValueObj instanceof List)) {
397 return Optional.empty();
399 final List<String> functionParameters;
401 functionParameters = ((List<Object>) functionValueObj).stream()
402 .map(object -> Objects.toString(object, null))
403 .collect(Collectors.toList());
404 } catch (final ClassCastException ignored) {
405 return Optional.empty();
407 if (functionParameters.size() < 2) {
408 return Optional.empty();
410 final String propertySourceType = functionParameters.get(0);
411 final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
412 if (propertySource == PropertySource.SELF) {
413 toscaGetFunction.setPropertySource(propertySource);
415 toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
416 toscaGetFunction.setSourceName(propertySourceType);
418 List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
419 List<String> propertySourcePath = new ArrayList<>();
420 propertySourcePath.add((String)propertySourceIndex.get(0));
421 if (propertySourceIndex.size() > 1 ) {
422 List<Object> indexParsedList = new ArrayList<Object>();
423 List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
424 boolean loopFlag = true;
425 for (String indexValue : indexObjectList) {
426 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
427 propertySourcePath.add(indexValue);
430 if (StringUtils.isNumeric(indexValue)) {
431 indexParsedList.add(Integer.parseInt(indexValue));
433 indexParsedList.add(indexValue);
437 toscaGetFunction.setToscaIndexList(indexParsedList);
439 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
440 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
441 toscaGetFunction.setPropertyName(propertyName);
442 return Optional.of(toscaGetFunction);
445 private static Optional<ToscaFunction> readLegacyGetInputConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType) {
446 final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
447 toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
448 toscaGetFunction.setPropertySource(PropertySource.SELF);
449 final Object functionValueObj = filterValueAsMap.get(toscaFunctionType);
450 if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
451 return Optional.empty();
453 if (functionValueObj instanceof String) {
454 toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
456 final List<String> functionParameters;
458 functionParameters = ((List<Object>) functionValueObj).stream()
459 .map(object -> Objects.toString(object, null))
460 .collect(Collectors.toList());
461 } catch (final ClassCastException ignored) {
462 return Optional.empty();
464 List<String> propertySourcePath = new ArrayList<>();
465 propertySourcePath.add((String)functionParameters.get(0));
466 if (functionParameters.size() > 1 ) {
467 List<Object> indexParsedList = new ArrayList<Object>();
468 List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
469 boolean loopFlag = true;
470 for (String indexValue : indexObjectList) {
471 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
472 propertySourcePath.add(indexValue);
475 if (StringUtils.isNumeric(indexValue)) {
476 indexParsedList.add(Integer.parseInt(indexValue));
478 indexParsedList.add(indexValue);
482 toscaGetFunction.setToscaIndexList(indexParsedList);
484 toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
486 final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
487 toscaGetFunction.setPropertyName(propertyName);
488 return Optional.of(toscaGetFunction);
491 private static FilterValueType detectValueType(final Object value) {
492 if (value instanceof Map) {
493 final Map<?, ?> valueAsMap = (Map<?, ?>) value;
494 if (valueAsMap.containsKey(ToscaFunctionType.CONCAT.getName())) {
495 return FilterValueType.CONCAT;
497 if (valueAsMap.containsKey(ToscaFunctionType.GET_ATTRIBUTE.getName())) {
498 return FilterValueType.GET_ATTRIBUTE;
500 if (valueAsMap.containsKey(ToscaFunctionType.GET_PROPERTY.getName())) {
501 return FilterValueType.GET_PROPERTY;
503 if (valueAsMap.containsKey(ToscaFunctionType.GET_INPUT.getName())) {
504 return FilterValueType.GET_INPUT;
506 if (valueAsMap.containsKey("$get_input_ext") ||
507 valueAsMap.containsKey("$juel") ||
508 valueAsMap.containsKey("$other")) {
509 return FilterValueType.CUSTOM;
512 return FilterValueType.STATIC;