Fail to import service with node filter using 'in_range'
[sdc.git] / common-be / src / main / java / org / openecomp / sdc / be / utils / PropertyFilterConstraintDataDefinitionHelper.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.utils;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Objects;
29 import java.util.Optional;
30 import java.util.Set;
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.jetbrains.annotations.Nullable;
38 import org.openecomp.sdc.be.config.Configuration;
39 import org.openecomp.sdc.be.config.ConfigurationManager;
40 import org.openecomp.sdc.be.datatypes.elements.CustomYamlFunction;
41 import org.openecomp.sdc.be.datatypes.elements.PropertyFilterConstraintDataDefinition;
42 import org.openecomp.sdc.be.datatypes.elements.ToscaConcatFunction;
43 import org.openecomp.sdc.be.datatypes.elements.ToscaCustomFunction;
44 import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
45 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionParameter;
46 import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
47 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
48 import org.openecomp.sdc.be.datatypes.elements.ToscaStringParameter;
49 import org.openecomp.sdc.be.datatypes.enums.ConstraintType;
50 import org.openecomp.sdc.be.datatypes.enums.FilterValueType;
51 import org.openecomp.sdc.be.datatypes.enums.PropertyFilterTargetType;
52 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
53 import org.openecomp.sdc.be.datatypes.tosca.ToscaGetFunctionType;
54 import org.yaml.snakeyaml.Yaml;
55
56 @NoArgsConstructor(access = AccessLevel.PRIVATE)
57 public class PropertyFilterConstraintDataDefinitionHelper {
58
59     public static PropertyFilterConstraintDataDefinition convertLegacyConstraint(final String constraint) {
60         final var propertyFilterConstraint = new PropertyFilterConstraintDataDefinition();
61         final Map<String, Object> constraintYaml = new Yaml().load(constraint);
62         final String propertyName = constraintYaml.keySet().iterator().next();
63         propertyFilterConstraint.setPropertyName(propertyName);
64         final Map<String, Object> operatorYaml = (Map<String, Object>) constraintYaml.get(propertyName);
65         final String operator = operatorYaml.keySet().iterator().next();
66         propertyFilterConstraint.setOperator(ConstraintType.findByType(operator).orElse(null));
67         final Object valueYaml = operatorYaml.get(operator);
68         final Optional<ToscaFunction> toscaFunction = createToscaFunctionFromLegacyConstraintValue(valueYaml);
69         if (toscaFunction.isPresent()) {
70             if (valueYaml instanceof List) {
71                 List<ToscaFunction> listToscaFunction = new ArrayList<>();
72                 ((List<?>) valueYaml).stream().forEach(val -> {
73                     final Optional<ToscaFunction> optToscaFunctionLst = createToscaFunctionFromLegacyConstraintValue(val);
74                     if (optToscaFunctionLst.isPresent()) {
75                         listToscaFunction.add(optToscaFunctionLst.get());
76                     }
77                 });
78                 propertyFilterConstraint.setValue(listToscaFunction);
79                 propertyFilterConstraint.setValueType(FilterValueType.SEVERAL);
80             }
81             else {
82                 propertyFilterConstraint.setValue(toscaFunction.get());
83                 propertyFilterConstraint.setValueType(detectValueType(valueYaml));
84             }
85         }
86         else {
87             propertyFilterConstraint.setValue(valueYaml);
88             propertyFilterConstraint.setValueType(detectValueType(valueYaml));
89         }
90         propertyFilterConstraint.setTargetType(PropertyFilterTargetType.PROPERTY);
91         return propertyFilterConstraint;
92     }
93
94     public static Optional<ToscaFunction> createToscaFunctionFromLegacyConstraintValue(final Object filterValue) {
95         if (!(filterValue instanceof Map) && !(filterValue instanceof List)) {
96             return Optional.empty();
97         }
98         if (filterValue instanceof List) {
99             final Map<String, Object>[] filterValueAsMap = new Map[] {new HashMap<>()};
100             final String[] toscaFunctionType = new String[1];
101             try {
102                 ((List<?>) filterValue).stream().forEach(filterArrayValue -> {
103
104                     filterValueAsMap[0] = (Map<String, Object>) filterArrayValue;
105                     final Set<?> keys = filterValueAsMap[0].keySet();
106                     toscaFunctionType[0] = (String) keys.iterator().next();
107
108                 });
109             }
110             catch (Exception ex) {
111                 return Optional.empty();
112             }
113             return buildToscaFunctionBasedOnPropertyValue(filterValueAsMap[0]);
114         }
115         final Map<?, ?> filterValueAsMap = (Map<?, ?>) filterValue;
116         final Set<?> keys = filterValueAsMap.keySet();
117         if (keys.size() != 1) {
118             return Optional.empty();
119         }
120         final Object toscaFunctionTypeObject = keys.iterator().next();
121         if (!(toscaFunctionTypeObject instanceof String)) {
122             return Optional.empty();
123         }
124         ToscaFunctionType toscaFunctionType = ToscaFunctionType.findType((String) toscaFunctionTypeObject).orElse(null);
125         if (toscaFunctionType == null) {
126             if (((String) toscaFunctionTypeObject).startsWith("$")) {
127                 toscaFunctionType = ToscaFunctionType.CUSTOM;
128             }
129             else {
130                 return Optional.empty();
131             }
132         }
133         switch (toscaFunctionType) {
134             case GET_INPUT:
135                 return readLegacyGetInputConstraintValue(filterValueAsMap, toscaFunctionTypeObject);
136             case GET_ATTRIBUTE:
137             case GET_PROPERTY:
138                 return readLegacyGetPropertyConstraintValue(filterValueAsMap, toscaFunctionTypeObject, toscaFunctionType);
139             case CONCAT:
140                 return readLegacyConcatConstraintValue(filterValueAsMap, toscaFunctionTypeObject);
141             case CUSTOM:
142                 return handleCustomFunction((Map<String, Object>)filterValueAsMap, (String)toscaFunctionTypeObject);
143             default:
144                 return Optional.empty();
145         }
146     }
147
148     private static Optional<ToscaFunction> handleCustomFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
149         final ToscaCustomFunction toscaCustomFunction = new ToscaCustomFunction();
150         toscaCustomFunction.setName(functionType.substring(1));
151         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
152         toscaCustomFunction.setToscaFunctionType(getCustomFunctionType(toscaCustomFunction.getName()));
153         if (ToscaFunctionType.GET_INPUT.equals(toscaCustomFunction.getToscaFunctionType())) {
154             return handleCustomFunctionGetInputType(toscaCustomFunction, functionValueObj);
155         }
156         return handelCustomFunctionCustomType(toscaCustomFunction, functionValueObj);
157     }
158
159     private static Optional<ToscaFunction> handleCustomFunctionGetInputType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
160         if (!(functionValueObj instanceof String) && !(functionValueObj instanceof List)) {
161             return Optional.empty();
162         }
163         Map<String, Object> parameterMap = new HashMap<>();
164         parameterMap.put(ToscaFunctionType.GET_INPUT.getName(), functionValueObj);
165         buildToscaFunctionBasedOnPropertyValue(parameterMap).ifPresent(toscaFunction -> {
166             if (toscaFunction instanceof ToscaFunctionParameter) {
167                 toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
168             }
169         });
170         return Optional.of(toscaCustomFunction);
171     }
172
173     private static Optional<ToscaFunction> buildToscaFunctionBasedOnPropertyValue(final Map<String, Object> toscaFunctionPropertyValueMap) {
174         if (!isPropertyValueToscaFunction(toscaFunctionPropertyValueMap)) {
175             return Optional.empty();
176         }
177         final String functionType = toscaFunctionPropertyValueMap.keySet().iterator().next();
178         final ToscaFunctionType toscaFunctionType =
179             ToscaFunctionType.findType(functionType).orElse(functionType.startsWith("$") ? ToscaFunctionType.CUSTOM : null);
180         if (toscaFunctionType == null) {
181             return Optional.empty();
182         }
183         switch (toscaFunctionType) {
184             case GET_INPUT: {
185                 return handleGetInputFunction(toscaFunctionPropertyValueMap, functionType);
186             }
187             case GET_PROPERTY:
188             case GET_ATTRIBUTE: {
189                 return handleGetPropertyFunction(toscaFunctionPropertyValueMap, functionType, toscaFunctionType);
190             }
191             case CONCAT:
192                 return handleConcatFunction(toscaFunctionPropertyValueMap, functionType);
193             case CUSTOM:
194                 return handleCustomFunction(toscaFunctionPropertyValueMap, functionType);
195             default:
196                 return Optional.empty();
197         }
198     }
199
200     private static Optional<ToscaFunction> handleConcatFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
201         final ToscaConcatFunction toscaConcatFunction = new ToscaConcatFunction();
202         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
203         if (!(functionValueObj instanceof List)) {
204             return Optional.empty();
205         }
206         final List<Object> functionParameters = (List<Object>) functionValueObj;
207         if (functionParameters.size() < 2) {
208             return Optional.empty();
209         }
210         functionParameters.forEach(parameter -> {
211             if (parameter instanceof String) {
212                 final var stringParameter = new ToscaStringParameter();
213                 stringParameter.setValue((String) parameter);
214                 toscaConcatFunction.addParameter(stringParameter);
215                 return;
216             }
217             if (isPropertyValueToscaFunction(parameter)) {
218                 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
219                     if (toscaFunction instanceof ToscaFunctionParameter) {
220                         toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction);
221                     }
222                 });
223                 return;
224             }
225             final var customYamlFunction = new CustomYamlFunction();
226             customYamlFunction.setYamlValue(parameter);
227             toscaConcatFunction.addParameter(customYamlFunction);
228         });
229         return Optional.of(toscaConcatFunction);
230     }
231
232     private static Optional<ToscaFunction> handleGetPropertyFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType,
233                                                                      ToscaFunctionType toscaFunctionType) {
234         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
235         toscaGetFunction.setFunctionType(
236             toscaFunctionType == ToscaFunctionType.GET_PROPERTY ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
237         );
238         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
239         if (!(functionValueObj instanceof List)) {
240             return Optional.empty();
241         }
242         final List<String> functionParameters;
243         try {
244             functionParameters = ((List<Object>) functionValueObj).stream()
245                 .map(object -> Objects.toString(object, null))
246                 .collect(Collectors.toList());
247         } catch (final ClassCastException ignored) {
248             return Optional.empty();
249         }
250         if (functionParameters.size() < 2) {
251             return Optional.empty();
252         }
253         final String propertySourceType = functionParameters.get(0);
254         final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
255         if (propertySource == PropertySource.SELF) {
256             toscaGetFunction.setPropertySource(propertySource);
257         } else {
258             toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
259             toscaGetFunction.setSourceName(propertySourceType);
260         }
261         List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
262         List<String> propertySourcePath = new ArrayList<>();
263         propertySourcePath.add((String)propertySourceIndex.get(0));
264         if (propertySourceIndex.size() > 1 ) {
265             List<Object> indexParsedList = new ArrayList<Object>();
266             List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
267             boolean loopFlag = true;
268             for (String indexValue : indexObjectList) {
269                 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
270                     propertySourcePath.add(indexValue);
271                 } else {
272                     loopFlag = false;
273                     if (StringUtils.isNumeric(indexValue)) {
274                         indexParsedList.add(Integer.parseInt(indexValue));
275                     } else {
276                         indexParsedList.add(indexValue);
277                     }
278                 }
279             }
280             toscaGetFunction.setToscaIndexList(indexParsedList);
281         }
282         toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
283         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
284         toscaGetFunction.setPropertyName(propertyName);
285         return Optional.of(toscaGetFunction);
286     }
287
288     private static Optional<ToscaFunction> handleGetInputFunction(Map<String, Object> toscaFunctionPropertyValueMap, String functionType) {
289         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
290         toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
291         toscaGetFunction.setPropertySource(PropertySource.SELF);
292         final Object functionValueObj = toscaFunctionPropertyValueMap.get(functionType);
293         if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
294             return Optional.empty();
295         }
296         if (functionValueObj instanceof String) {
297             toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
298         } else {
299             final List<String> functionParameters;
300             try {
301                 functionParameters = ((List<Object>) functionValueObj).stream()
302                     .map(object -> Objects.toString(object, null))
303                     .collect(Collectors.toList());
304             } catch (final ClassCastException ignored) {
305                 return Optional.empty();
306             }
307             List<String> propertySourcePath = new ArrayList<>();
308             propertySourcePath.add((String)functionParameters.get(0));
309             if (functionParameters.size() > 1 ) {
310                 List<Object> indexParsedList = new ArrayList<Object>();
311                 List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
312                 boolean loopFlag = true;
313                 for (String indexValue : indexObjectList) {
314                     if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
315                         propertySourcePath.add(indexValue);
316                     } else {
317                         loopFlag = false;
318                         if (StringUtils.isNumeric(indexValue)) {
319                             indexParsedList.add(Integer.parseInt(indexValue));
320                         } else {
321                             indexParsedList.add(indexValue);
322                         }
323                     }
324                 }
325                 toscaGetFunction.setToscaIndexList(indexParsedList);
326             }
327             toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
328         }
329         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
330         toscaGetFunction.setPropertyName(propertyName);
331         return Optional.of(toscaGetFunction);
332     }
333
334     public static boolean isPropertyValueToscaFunction(final Object propValueObj) {
335         if (propValueObj instanceof Map) {
336             final Map<String, Object> propValueMap = (Map<String, Object>) propValueObj;
337             if (propValueMap.keySet().size() > 1) {
338                 return false;
339             }
340             if (propValueMap.keySet().stream().anyMatch(keyValue -> keyValue.startsWith("$"))) {
341                 return true;
342             }
343
344             return Stream.of(ToscaFunctionType.GET_INPUT, ToscaFunctionType.GET_PROPERTY, ToscaFunctionType.GET_ATTRIBUTE, ToscaFunctionType.CONCAT)
345                 .anyMatch(type -> propValueMap.containsKey(type.getName()));
346         }
347         return false;
348     }
349
350     private static ToscaFunctionType getCustomFunctionType(String name) {
351         List<Configuration.CustomToscaFunction> customFunctions =
352             ConfigurationManager.getConfigurationManager().getConfiguration().getDefaultCustomToscaFunctions();
353         if (CollectionUtils.isEmpty(customFunctions)) {
354             return ToscaFunctionType.CUSTOM;
355         }
356         Optional<Configuration.CustomToscaFunction> optionalFunc = customFunctions.stream().filter(func -> func.getName().equals(name)).findFirst();
357         if (optionalFunc.isEmpty()) {
358             return ToscaFunctionType.CUSTOM;
359         }
360         String type = optionalFunc.get().getType();
361         return ToscaFunctionType.findType(type).get();
362     }
363
364     private static Optional<ToscaFunction> handelCustomFunctionCustomType(ToscaCustomFunction toscaCustomFunction, Object functionValueObj) {
365         if (!(functionValueObj instanceof List)) {
366             return Optional.empty();
367         }
368         final List<Object> functionParameters = (List<Object>) functionValueObj;
369         functionParameters.forEach(parameter -> {
370             if (parameter instanceof String) {
371                 final var stringParameter = new ToscaStringParameter();
372                 stringParameter.setValue((String) parameter);
373                 toscaCustomFunction.addParameter(stringParameter);
374                 return;
375             }
376             if (isPropertyValueToscaFunction(parameter)) {
377                 buildToscaFunctionBasedOnPropertyValue((Map<String, Object>) parameter).ifPresent(toscaFunction -> {
378                     if (toscaFunction instanceof ToscaFunctionParameter) {
379                         toscaCustomFunction.addParameter((ToscaFunctionParameter) toscaFunction);
380                     }
381                 });
382                 return;
383             }
384             final var customYamlFunction = new CustomYamlFunction();
385             customYamlFunction.setYamlValue(parameter);
386             toscaCustomFunction.addParameter(customYamlFunction);
387         });
388         return Optional.of(toscaCustomFunction);
389     }
390
391     public static Optional<FilterValueType> convertFromToscaFunctionType(final ToscaFunctionType toscaFunctionType) {
392         return FilterValueType.findByName(toscaFunctionType.getName());
393     }
394
395     private static Optional<ToscaFunction> readLegacyConcatConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType) {
396         final List<Object> concatValue;
397         try {
398             concatValue = (List<Object>) filterValueAsMap.get(toscaFunctionType);
399         } catch (final Exception ignored) {
400             return Optional.empty();
401         }
402         if (concatValue.isEmpty()) {
403             return Optional.empty();
404         }
405         final var toscaConcatFunction = new ToscaConcatFunction();
406         for (Object parameter : concatValue) {
407             if (parameter instanceof String) {
408                 final ToscaStringParameter toscaStringParameter = new ToscaStringParameter();
409                 toscaStringParameter.setValue((String) parameter);
410                 toscaConcatFunction.addParameter(toscaStringParameter);
411             } else {
412                 createToscaFunctionFromLegacyConstraintValue(parameter)
413                     .ifPresent(toscaFunction -> toscaConcatFunction.addParameter((ToscaFunctionParameter) toscaFunction));
414             }
415         }
416         return Optional.of(toscaConcatFunction);
417     }
418
419     private static Optional<ToscaFunction> readLegacyGetPropertyConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType,
420                                                                                 ToscaFunctionType toscaFunctionType1) {
421         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
422         toscaGetFunction.setFunctionType(
423             toscaFunctionType.toString().equalsIgnoreCase(ToscaFunctionType.GET_PROPERTY.getName()) ? ToscaGetFunctionType.GET_PROPERTY : ToscaGetFunctionType.GET_ATTRIBUTE
424         );
425         final Object functionValueObj = null != filterValueAsMap.get(toscaFunctionType1) ?
426             filterValueAsMap.get(toscaFunctionType1) : filterValueAsMap.get(toscaFunctionType);
427         if (!(functionValueObj instanceof List)) {
428             return Optional.empty();
429         }
430         final List<String> functionParameters;
431         try {
432             functionParameters = ((List<Object>) functionValueObj).stream()
433                 .map(object -> Objects.toString(object, null))
434                 .collect(Collectors.toList());
435         } catch (final ClassCastException ignored) {
436             return Optional.empty();
437         }
438         if (functionParameters.size() < 2) {
439             return Optional.empty();
440         }
441         final String propertySourceType = functionParameters.get(0);
442         final PropertySource propertySource = PropertySource.findType(propertySourceType).orElse(null);
443         if (propertySource == PropertySource.SELF) {
444             toscaGetFunction.setPropertySource(propertySource);
445         } else {
446             toscaGetFunction.setPropertySource(PropertySource.INSTANCE);
447             toscaGetFunction.setSourceName(propertySourceType);
448         }
449         List<String> propertySourceIndex = functionParameters.subList(1, functionParameters.size());
450         List<String> propertySourcePath = new ArrayList<>();
451         propertySourcePath.add((String)propertySourceIndex.get(0));
452         if (propertySourceIndex.size() > 1 ) {
453             List<Object> indexParsedList = new ArrayList<Object>();
454             List<String> indexObjectList = propertySourceIndex.subList(1,propertySourceIndex.size());
455             boolean loopFlag = true;
456             for (String indexValue : indexObjectList) {
457                 if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
458                     propertySourcePath.add(indexValue);
459                 } else {
460                     loopFlag = false;
461                     if (StringUtils.isNumeric(indexValue)) {
462                         indexParsedList.add(Integer.parseInt(indexValue));
463                     } else {
464                         indexParsedList.add(indexValue);
465                     }
466                 }
467             }
468             toscaGetFunction.setToscaIndexList(indexParsedList);
469         }
470         toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
471         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
472         toscaGetFunction.setPropertyName(propertyName);
473         return Optional.of(toscaGetFunction);
474     }
475
476     private static Optional<ToscaFunction> readLegacyGetInputConstraintValue(Map<?, ?> filterValueAsMap, Object toscaFunctionType) {
477         final ToscaGetFunctionDataDefinition toscaGetFunction = new ToscaGetFunctionDataDefinition();
478         toscaGetFunction.setFunctionType(ToscaGetFunctionType.GET_INPUT);
479         toscaGetFunction.setPropertySource(PropertySource.SELF);
480         final Object functionValueObj = filterValueAsMap.get(toscaFunctionType);
481         if (!(functionValueObj instanceof List) && !(functionValueObj instanceof String)) {
482             return Optional.empty();
483         }
484         if (functionValueObj instanceof String) {
485             toscaGetFunction.setPropertyPathFromSource(List.of((String) functionValueObj));
486         } else {
487             final List<String> functionParameters;
488             try {
489                 functionParameters = ((List<Object>) functionValueObj).stream()
490                     .map(object -> Objects.toString(object, null))
491                     .collect(Collectors.toList());
492             } catch (final ClassCastException ignored) {
493                 return Optional.empty();
494             }
495             List<String> propertySourcePath = new ArrayList<>();
496             propertySourcePath.add((String)functionParameters.get(0));
497             if (functionParameters.size() > 1 ) {
498                 List<Object> indexParsedList = new ArrayList<Object>();
499                 List<String> indexObjectList = functionParameters.subList(1,functionParameters.size());
500                 boolean loopFlag = true;
501                 for (String indexValue : indexObjectList) {
502                     if (!indexValue.equalsIgnoreCase("INDEX") && !StringUtils.isNumeric(indexValue) && loopFlag) {
503                         propertySourcePath.add(indexValue);
504                     } else {
505                         loopFlag = false;
506                         if (StringUtils.isNumeric(indexValue)) {
507                             indexParsedList.add(Integer.parseInt(indexValue));
508                         } else {
509                             indexParsedList.add(indexValue);
510                         }
511                     }
512                 }
513                 toscaGetFunction.setToscaIndexList(indexParsedList);
514             }
515             toscaGetFunction.setPropertyPathFromSource(propertySourcePath);
516         }
517         final String propertyName = toscaGetFunction.getPropertyPathFromSource().get(toscaGetFunction.getPropertyPathFromSource().size() - 1);
518         toscaGetFunction.setPropertyName(propertyName);
519         return Optional.of(toscaGetFunction);
520     }
521
522     private static FilterValueType detectValueType(final Object value) {
523         if (value instanceof Map) {
524             final Map<?, ?> valueAsMap = (Map<?, ?>) value;
525             FilterValueType filterValueType = getFilterValueType(valueAsMap);
526             if (filterValueType != null) {
527                 return filterValueType;
528             }
529         }
530         else if (value instanceof List) {
531             try {
532                 final Map<?, ?> valueAsMap = (Map<?, ?>) ((List<?>) value).get(0);
533                 FilterValueType filterValueType = getFilterValueType(valueAsMap);
534                 if (filterValueType != null) {
535                     return filterValueType;
536                 }
537             } catch (ClassCastException ex) {
538                 return FilterValueType.SEVERAL;
539             }
540         }
541         return FilterValueType.STATIC;
542     }
543
544     @Nullable
545     private static FilterValueType getFilterValueType(Map<?, ?> valueAsMap) {
546         if (valueAsMap.containsKey(ToscaFunctionType.CONCAT.getName())) {
547             return FilterValueType.CONCAT;
548         }
549         if (valueAsMap.containsKey(ToscaFunctionType.GET_ATTRIBUTE.getName())) {
550             return FilterValueType.GET_ATTRIBUTE;
551         }
552         if (valueAsMap.containsKey(ToscaFunctionType.GET_PROPERTY.getName())) {
553             return FilterValueType.GET_PROPERTY;
554         }
555         if (valueAsMap.containsKey(ToscaFunctionType.GET_INPUT.getName())) {
556             return FilterValueType.GET_INPUT;
557         }
558         if (valueAsMap.containsKey("$get_input_ext") ||
559             valueAsMap.containsKey("$juel") ||
560             valueAsMap.containsKey("$other")) {
561             return FilterValueType.CUSTOM;
562         }
563         return null;
564     }
565 }