Support TOSCA functions in Node Filters
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / validation / NodeFilterValidator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.components.validation;
21
22 import com.google.gson.Gson;
23 import fj.data.Either;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Optional;
27 import java.util.Set;
28 import java.util.stream.Collectors;
29 import org.apache.commons.collections4.CollectionUtils;
30 import org.apache.commons.lang3.StringUtils;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
33 import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
34 import org.openecomp.sdc.be.datatypes.enums.PropertySource;
35 import org.openecomp.sdc.be.impl.ComponentsUtils;
36 import org.openecomp.sdc.be.model.CapabilityDefinition;
37 import org.openecomp.sdc.be.model.Component;
38 import org.openecomp.sdc.be.model.ComponentInstance;
39 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
40 import org.openecomp.sdc.be.model.DataTypeDefinition;
41 import org.openecomp.sdc.be.model.InputDefinition;
42 import org.openecomp.sdc.be.model.PropertyDefinition;
43 import org.openecomp.sdc.be.model.ToscaPropertyData;
44 import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache;
45 import org.openecomp.sdc.be.model.dto.FilterConstraintDto;
46 import org.openecomp.sdc.be.model.tosca.ToscaPropertyType;
47 import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter;
48 import org.openecomp.sdc.be.model.validation.FilterConstraintValidator;
49 import org.openecomp.sdc.exception.ResponseFormat;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.beans.factory.annotation.Autowired;
53
54 @org.springframework.stereotype.Component("NodeFilterValidator")
55 public class NodeFilterValidator {
56
57     private static final Logger LOGGER = LoggerFactory.getLogger(NodeFilterValidator.class);
58     private static final String SOURCE = "Source";
59     private static final String TARGET = "Target";
60     private static final String INPUT_NOT_FOUND_LOG = "Input '{}' not found in parent component '{}', unique id '{}'";
61     private static final Set<String> TYPES_WITH_SCHEMA = Set.of(ToscaPropertyType.MAP.getType(), ToscaPropertyType.LIST.getType());
62     private static final Set<String> COMPARABLE_TYPES = Set
63         .of(ToscaPropertyType.STRING.getType(), ToscaPropertyType.INTEGER.getType(), ToscaPropertyType.FLOAT.getType());
64     private final ComponentsUtils componentsUtils;
65     private final ApplicationDataTypeCache applicationDataTypeCache;
66     private final FilterConstraintValidator filterConstraintValidator;
67
68     @Autowired
69     public NodeFilterValidator(final ComponentsUtils componentsUtils, final ApplicationDataTypeCache applicationDataTypeCache,
70                                final FilterConstraintValidator filterConstraintValidator) {
71         this.componentsUtils = componentsUtils;
72         this.applicationDataTypeCache = applicationDataTypeCache;
73         this.filterConstraintValidator = filterConstraintValidator;
74     }
75
76     public Either<Boolean, ResponseFormat> validateComponentInstanceExist(final Component component, final String componentInstanceId) {
77         if (component == null || StringUtils.isEmpty(componentInstanceId)) {
78             LOGGER.error("Expecting a component and a component instance id, given was '{}' and '{}'", component, componentInstanceId);
79             final String componentName = component == null ? "?" : component.getName();
80             return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND, componentName, componentInstanceId));
81         }
82         if (CollectionUtils.isEmpty(component.getComponentInstances()) || component.getComponentInstances().stream()
83             .noneMatch(ci -> ci.getUniqueId().equals(componentInstanceId))) {
84             LOGGER.error("Component '{}' node instance list is empty or component instance '{}' not found",
85                 component.getUniqueId(), componentInstanceId);
86             return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND,
87                 component.getName(), componentInstanceId));
88         }
89         return Either.left(Boolean.TRUE);
90     }
91
92     public Either<Boolean, ResponseFormat> validateFilter(final Component parentComponent, final String componentInstanceId,
93                                                           final List<FilterConstraintDto> filterConstraint) {
94         if (CollectionUtils.isEmpty(filterConstraint)) {
95             return Either.left(true);
96         }
97         for (final FilterConstraintDto filterConstraintDto : filterConstraint) {
98             final Either<Boolean, ResponseFormat> validationEither =
99                 validateFilter(parentComponent, componentInstanceId, filterConstraintDto);
100             if (validationEither.isRight()) {
101                 return validationEither;
102             }
103         }
104         return Either.left(true);
105     }
106     public Either<Boolean, ResponseFormat> validateFilter(final Component parentComponent, final String componentInstanceId,
107                                                           final FilterConstraintDto filterConstraint) {
108         validateFilterConstraint(filterConstraint);
109         switch (filterConstraint.getValueType()) {
110             case STATIC:
111                 if (filterConstraint.isCapabilityPropertyFilter()) {
112                     return validateStaticValueAndOperatorOfCapabilityProperties(parentComponent, componentInstanceId, filterConstraint);
113                 } else {
114                     return validateStaticValueAndOperator(parentComponent, componentInstanceId, filterConstraint);
115                 }
116             case GET_PROPERTY:
117                 return validatePropertyConstraint(parentComponent, componentInstanceId, filterConstraint, filterConstraint.getCapabilityName());
118             case GET_INPUT:
119                 return validateInputConstraint(parentComponent, componentInstanceId, filterConstraint);
120             default:
121                 return Either.left(true);
122         }
123     }
124
125     private void validateFilterConstraint(final FilterConstraintDto filterConstraint) {
126         filterConstraintValidator.validate(filterConstraint);
127     }
128
129     private Either<Boolean, ResponseFormat> validatePropertyConstraint(final Component parentComponent, final String componentInstanceId,
130                                                                        final FilterConstraintDto filterConstraint, final String capabilityName) {
131         String source = SOURCE;
132         final ToscaGetFunctionDataDefinition toscaGetFunction = filterConstraint.getAsToscaGetFunction().orElse(null);
133         if (toscaGetFunction == null || !(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) {
134             return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
135         }
136         final Optional<? extends ToscaPropertyData> sourceSelectedProperty = findPropertyFromGetFunction(parentComponent, toscaGetFunction);
137         if (sourceSelectedProperty.isPresent()) {
138             Optional<? extends PropertyDefinition> targetComponentInstanceProperty =
139                 getInstanceProperties(parentComponent, componentInstanceId, capabilityName, filterConstraint.getPropertyName());
140
141             source = targetComponentInstanceProperty.isEmpty() ? TARGET : SOURCE;
142             if (targetComponentInstanceProperty.isPresent()) {
143                 final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get());
144                 if (responseFormat != null) {
145                     return Either.right(responseFormat);
146                 }
147                 return Either.left(true);
148             }
149         }
150         final String missingProperty = SOURCE.equals(source) ? filterConstraint.getValue().toString() : filterConstraint.getPropertyName();
151         return Either.right(componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, source, missingProperty));
152     }
153
154     private Optional<? extends ToscaPropertyData> findPropertyFromGetFunction(final Component parentComponent,
155                                                                               final ToscaGetFunctionDataDefinition toscaGetFunction) {
156         List<? extends ToscaPropertyData> sourcePropertyDefinitions;
157         if (PropertySource.SELF == toscaGetFunction.getPropertySource()) {
158             sourcePropertyDefinitions = getSelfPropertyFromGetFunction(parentComponent, toscaGetFunction);
159         } else {
160             sourcePropertyDefinitions = getInstancePropertiesBasedOnGetFunctionSource(parentComponent, toscaGetFunction);
161         }
162         final List<String> propertyPath = toscaGetFunction.getPropertyPathFromSource();
163         final Optional<? extends ToscaPropertyData> sourceProperty = sourcePropertyDefinitions.stream()
164             .filter(propertyDefinition -> propertyDefinition.getName().equals(propertyPath.get(0))).findFirst();
165         if (sourceProperty.isEmpty() || propertyPath.size() == 1) {
166             return sourceProperty;
167         }
168         final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither =
169             applicationDataTypeCache.getAll(parentComponent.getModel());
170         if (allDataTypesEither.isRight()) {
171             return Optional.empty();
172         }
173         return findSubProperty(propertyPath.subList(1, propertyPath.size()), sourceProperty.get().getType(), allDataTypesEither.left().value());
174     }
175
176     private List<? extends ToscaPropertyData> getInstancePropertiesBasedOnGetFunctionSource(final Component parentComponent,
177                                                                                             final ToscaGetFunctionDataDefinition toscaGetFunction) {
178         final ComponentInstance componentInstance = parentComponent.getComponentInstances().stream()
179             .filter(componentInstance1 -> componentInstance1.getName().equals(toscaGetFunction.getSourceName()))
180             .findFirst()
181             .orElse(null);
182         if (componentInstance == null) {
183             return List.of();
184         }
185         final List<? extends ToscaPropertyData> instanceProperties;
186         switch (toscaGetFunction.getFunctionType()) {
187             case GET_PROPERTY:
188                 instanceProperties = parentComponent.getComponentInstancesProperties().get(componentInstance.getUniqueId());
189                 break;
190             case GET_ATTRIBUTE:
191                 instanceProperties = parentComponent.getComponentInstancesAttributes().get(componentInstance.getUniqueId());
192                 break;
193             default:
194                 instanceProperties = List.of();
195         }
196         if (instanceProperties == null) {
197             return List.of();
198         }
199         return instanceProperties;
200     }
201
202     private static List<? extends ToscaPropertyData> getSelfPropertyFromGetFunction(final Component component,
203                                                                                     final ToscaGetFunctionDataDefinition toscaGetFunction) {
204         switch (toscaGetFunction.getFunctionType()) {
205             case GET_INPUT:
206                 if (component.getInputs() != null) {
207                     return component.getInputs();
208                 }
209                 break;
210             case GET_PROPERTY:
211                 if (component.getProperties() != null) {
212                     return component.getProperties();
213                 }
214                 break;
215             case GET_ATTRIBUTE:
216                 if (component.getAttributes() != null) {
217                     return component.getAttributes();
218                 }
219                 break;
220         }
221         return List.of();
222     }
223
224     private Optional<PropertyDefinition> findSubProperty(final List<String> propertyPath, final String parentPropertyType,
225                                                          final Map<String, DataTypeDefinition> modelDataTypes) {
226         final DataTypeDefinition dataTypeDefinition = modelDataTypes.get(parentPropertyType);
227         if (CollectionUtils.isEmpty(dataTypeDefinition.getProperties())) {
228             return Optional.empty();
229         }
230         final PropertyDefinition propertyDefinition = dataTypeDefinition.getProperties().stream()
231             .filter(propertyDefinition1 -> propertyDefinition1.getName().equals(propertyPath.get(0))).findFirst().orElse(null);
232         if (propertyDefinition == null) {
233             return Optional.empty();
234         }
235         if (propertyPath.size() == 1) {
236             return Optional.of(propertyDefinition);
237         }
238         return findSubProperty(propertyPath.subList(1, propertyPath.size()), propertyDefinition.getType(), modelDataTypes);
239     }
240     
241     private Optional<ComponentInstanceProperty> getInstanceProperties(final Component parentComponent, final String componentInstanceId,
242                                                                       final String capabilityName, final String propertyName) {
243         if (StringUtils.isEmpty(capabilityName)) {
244             return parentComponent.getComponentInstancesProperties().get(componentInstanceId).stream()
245                     .filter(property -> propertyName.equals(property.getName())).findFirst();
246         } else {
247             final Optional<ComponentInstance> componentInstanceOptional = parentComponent.getComponentInstances().stream()
248                     .filter(componentInstance -> componentInstance.getUniqueId().equals(componentInstanceId)).findAny();
249             if (componentInstanceOptional.isPresent()) {
250                 for (final List<CapabilityDefinition> listOfCaps : componentInstanceOptional.get().getCapabilities().values()) {
251                     final Optional<CapabilityDefinition> capDef = listOfCaps.stream().filter(cap -> cap.getName().equals(capabilityName)).findAny();
252                     if (capDef.isPresent()) {
253                         return capDef.get().getProperties().stream().filter(property -> propertyName.equals(property.getName())).findFirst();
254                     }
255                 }
256             }
257         }
258         return Optional.empty();
259     }
260
261     private Either<Boolean, ResponseFormat> validateInputConstraint(final Component parentComponent, final String componentInstanceId,
262                                                                     final FilterConstraintDto filterConstraint) {
263         final List<InputDefinition> sourceInputDefinition = parentComponent.getInputs();
264         if (CollectionUtils.isEmpty(sourceInputDefinition)) {
265             LOGGER.debug("Parent component '{}', unique id '{}', does not have inputs", parentComponent.getName(), parentComponent.getUniqueId());
266             return Either.right(componentsUtils.getResponseFormat(ActionStatus.COMPONENT_DOES_NOT_HAVE_INPUTS, parentComponent.getName()));
267         }
268         if (!(filterConstraint.getValue() instanceof ToscaGetFunctionDataDefinition)) {
269             return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
270         }
271         final ToscaGetFunctionDataDefinition getFunction = (ToscaGetFunctionDataDefinition) filterConstraint.getValue();
272         final List<String> propertyPathFromSource = getFunction.getPropertyPathFromSource();
273         Optional<? extends PropertyDefinition> sourceSelectedProperty =
274             sourceInputDefinition.stream().filter(input -> input.getName().equals(propertyPathFromSource.get(0))).findFirst();
275         if (sourceSelectedProperty.isEmpty()) {
276             LOGGER.debug(INPUT_NOT_FOUND_LOG,
277                 propertyPathFromSource.get(0), parentComponent.getName(), parentComponent.getUniqueId());
278             return Either.right(
279                 componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INPUT_NOT_FOUND, propertyPathFromSource.get(0), parentComponent.getName())
280             );
281         }
282         if (propertyPathFromSource.size() > 1) {
283             final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither =
284                 applicationDataTypeCache.getAll(parentComponent.getModel());
285             if (allDataTypesEither.isRight()) {
286                 LOGGER.error("Could not load data types for model {}", parentComponent.getModel());
287                 return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED, parentComponent.getModel()));
288             }
289             sourceSelectedProperty =
290                 findSubProperty(propertyPathFromSource.subList(1, propertyPathFromSource.size()), sourceSelectedProperty.get().getType(),
291                     allDataTypesEither.left().value());
292         }
293         final Optional<? extends PropertyDefinition> targetComponentInstanceProperty =
294             parentComponent.getComponentInstancesProperties()
295                 .get(componentInstanceId).stream()
296                 .filter(property -> filterConstraint.getPropertyName().equals(property.getName()))
297                 .findFirst();
298         if (sourceSelectedProperty.isPresent() && targetComponentInstanceProperty.isPresent()) {
299             final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentInstanceProperty.get());
300             if (responseFormat != null) {
301                 return Either.right(responseFormat);
302             }
303             return Either.left(true);
304         }
305
306         return Either.right(componentsUtils.getResponseFormat(ActionStatus.INPUTS_NOT_FOUND));
307     }
308
309     private <T extends ToscaPropertyData> ResponseFormat validatePropertyData(final T sourcePropDefinition,
310                                                                               final T targetPropDefinition) {
311         final String sourceType = sourcePropDefinition.getType();
312         final String targetType = targetPropDefinition.getType();
313         if (sourceType.equals(targetType)) {
314             if (TYPES_WITH_SCHEMA.contains(sourceType)) {
315                 final String sourceSchemaType = sourcePropDefinition.getSchemaType();
316                 final String targetSchemaType = targetPropDefinition.getSchemaType();
317                 if (sourceSchemaType != null && !sourceSchemaType.equals(targetSchemaType)) {
318                     return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_SCHEMA_MISMATCH,
319                         targetPropDefinition.getName(), targetSchemaType, sourcePropDefinition.getName(), sourceSchemaType);
320                 }
321             }
322             return null;
323         }
324         return componentsUtils.getResponseFormat(ActionStatus.SOURCE_TARGET_PROPERTY_TYPE_MISMATCH,
325             sourcePropDefinition.getName(), sourcePropDefinition.getType(), targetPropDefinition.getName(), targetPropDefinition.getType());
326     }
327
328     private Either<Boolean, ResponseFormat> validateStaticValueAndOperator(final Component parentComponent, final String componentInstanceId,
329                                                                            final FilterConstraintDto filterConstraint) {
330         final ComponentInstanceProperty componentInstanceProperty = parentComponent.getComponentInstancesProperties()
331             .get(componentInstanceId).stream().filter(property -> filterConstraint.getPropertyName().equals(property.getName()))
332             .findFirst()
333             .orElse(null);
334         if (componentInstanceProperty == null) {
335             return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName()));
336         }
337         if (filterConstraint.getOperator().isComparable() && !COMPARABLE_TYPES.contains(componentInstanceProperty.getType())) {
338             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(),
339                 filterConstraint.getOperator().getType()));
340         }
341         return isValidValueCheck(componentInstanceProperty.getType(), componentInstanceProperty.getSchemaType(), parentComponent.getModel(),
342             filterConstraint.getValue(), filterConstraint.getPropertyName());
343     }
344
345     private Either<Boolean, ResponseFormat> validateStaticSubstitutionFilter(final Component component,
346                                                                              final FilterConstraintDto filterConstraint) {
347
348         final PropertyDefinition componentProperty = component.getProperties().stream()
349             .filter(property -> property.getName().equals(filterConstraint.getPropertyName())).findFirst().orElse(null);
350         if (componentProperty == null) {
351             return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName()));
352         }
353         if (filterConstraint.getOperator().isComparable() && !COMPARABLE_TYPES.contains(componentProperty.getType())) {
354             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(),
355                 filterConstraint.getOperator().getType()));
356         }
357         return isValidValueCheck(componentProperty.getType(), componentProperty.getSchemaType(), component.getModel(),
358             filterConstraint.getValue(), filterConstraint.getPropertyName());
359     }
360
361     private Either<Boolean, ResponseFormat> validateStaticValueAndOperatorOfCapabilityProperties(final Component parentComponent,
362                                                                                                  final String componentInstanceId,
363                                                                                                  final FilterConstraintDto filterConstraint) {
364         ComponentInstanceProperty componentInstanceProperty = null;
365         final Optional<ComponentInstance> optionalComponentInstances = parentComponent.getComponentInstances().stream()
366             .filter(componentInstance -> componentInstanceId.equalsIgnoreCase(componentInstance.getUniqueId())).findFirst();
367         if (optionalComponentInstances.isPresent()) {
368             final Optional<List<CapabilityDefinition>> optionalCapabilityDefinitionList = optionalComponentInstances.get().getCapabilities().values()
369                 .stream().filter(capabilityDefinitions -> capabilityDefinitions.stream()
370                     .allMatch(capabilityDefinition -> capabilityDefinition.getProperties() != null)).collect(Collectors.toList()).stream().filter(
371                     capabilityDefinitions -> capabilityDefinitions.stream().allMatch(
372                         capabilityDefinition -> capabilityDefinition.getProperties().stream().anyMatch(
373                             componentInstanceProperty1 -> filterConstraint.getPropertyName()
374                                 .equalsIgnoreCase(componentInstanceProperty1.getName())))).findFirst();
375             if (optionalCapabilityDefinitionList.isPresent() && !optionalCapabilityDefinitionList.get().isEmpty()) {
376                 componentInstanceProperty =
377                     getComponentInstanceProperty(optionalCapabilityDefinitionList.get().get(0), filterConstraint.getPropertyName()).orElse(null);
378             }
379         }
380
381         if (componentInstanceProperty == null) {
382             return Either.right(componentsUtils.getResponseFormat(ActionStatus.SELECTED_PROPERTY_NOT_PRESENT, filterConstraint.getPropertyName()));
383         }
384         if (filterConstraint.getOperator().isComparable() && !COMPARABLE_TYPES.contains(componentInstanceProperty.getType())) {
385             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_OPERATOR_PROVIDED, filterConstraint.getPropertyName(),
386                 filterConstraint.getOperator().getType()));
387         }
388         return isValidValueCheck(componentInstanceProperty.getType(), componentInstanceProperty.getSchemaType(), parentComponent.getModel(),
389             filterConstraint.getValue(), filterConstraint.getPropertyName());
390     }
391     
392     private Optional<ComponentInstanceProperty> getComponentInstanceProperty(CapabilityDefinition capabilityDefinition, final String propertyName){
393         return capabilityDefinition.getProperties().stream().filter(property -> property.getName().equals(propertyName)).findAny();
394     }
395
396     private Either<Boolean, ResponseFormat> isValidValueCheck(final String type, final String schemaType, final String model,
397                                                               final Object value, final String propertyName) {
398         final Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypesEither =
399             applicationDataTypeCache.getAll(model);
400         if (allDataTypesEither.isRight()) {
401             LOGGER.error("Could not validate filter value. Could not load data types for model {}", model);
402             return Either.right(componentsUtils.getResponseFormat(ActionStatus.DATA_TYPES_NOT_LOADED, model));
403         }
404         final Map<String, DataTypeDefinition> modelDataTypesMap = allDataTypesEither.left().value();
405         final ToscaPropertyType toscaPropertyType = ToscaPropertyType.isValidType(type);
406         if (toscaPropertyType == null && !modelDataTypesMap.containsKey(type)) {
407             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_PROPERTY_TYPE, type, propertyName));
408         }
409         final String valueAsJsonString;
410         try {
411             valueAsJsonString = new Gson().toJson(value);
412         } catch (final Exception e) {
413             LOGGER.debug("Unsupported property filter value", e);
414             return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, String.valueOf(value)));
415         }
416         if (toscaPropertyType != null) {
417             if (toscaPropertyType.getValidator().isValid(valueAsJsonString, schemaType, modelDataTypesMap)) {
418                 return Either.left(true);
419             }
420         } else {
421             if (DataTypeValidatorConverter.getInstance().isValid(valueAsJsonString, modelDataTypesMap.get(type), modelDataTypesMap)) {
422                 return Either.left(true);
423             }
424         }
425
426         return Either.right(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_VALUE_PROVIDED, type, propertyName, valueAsJsonString));
427     }
428
429     public Either<Boolean, ResponseFormat> validateSubstitutionFilter(final Component component, final List<FilterConstraintDto> filterConstraintList) {
430         if (CollectionUtils.isEmpty(filterConstraintList)) {
431             return Either.right(componentsUtils.getResponseFormat(ActionStatus.CONSTRAINT_FORMAT_INCORRECT));
432         }
433         for (final FilterConstraintDto filterConstraintDto : filterConstraintList) {
434             final Either<Boolean, ResponseFormat> validationEither = validateSubstitutionFilter(component, filterConstraintDto);
435             if (validationEither.isRight()) {
436                 return validationEither;
437             }
438         }
439         return Either.left(true);
440     }
441
442     public Either<Boolean, ResponseFormat> validateSubstitutionFilter(final Component component, final FilterConstraintDto filterConstraint) {
443         validateFilterConstraint(filterConstraint);
444         switch (filterConstraint.getValueType()) {
445             case STATIC:
446                 return validateStaticSubstitutionFilter(component, filterConstraint);
447             case GET_PROPERTY:
448             case GET_ATTRIBUTE:
449             case GET_INPUT:
450                 return validateSubstitutionFilterGetFunctionConstraint(component, filterConstraint);
451             default:
452                 return Either.left(true);
453         }
454     }
455
456     private Either<Boolean, ResponseFormat> validateSubstitutionFilterGetFunctionConstraint(final Component component,
457                                                                                             final FilterConstraintDto filterConstraint) {
458         final ToscaGetFunctionDataDefinition toscaGetFunction = filterConstraint.getAsToscaGetFunction().orElse(null);
459         if (toscaGetFunction == null) {
460             return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_FUNCTION_EXPECTED_ERROR));
461         }
462
463         if (CollectionUtils.isEmpty(component.getProperties())) {
464             return Either.right(
465                 componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, TARGET, getPropertyType(toscaGetFunction),
466                     filterConstraint.getPropertyName())
467             );
468         }
469
470         final Optional<? extends PropertyDefinition> targetComponentProperty = component.getProperties().stream()
471             .filter(property -> property.getName().equals(filterConstraint.getPropertyName())).findFirst();
472         if (targetComponentProperty.isEmpty()) {
473             return Either.right(
474                 componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, TARGET, getPropertyType(toscaGetFunction),
475                     filterConstraint.getPropertyName())
476             );
477         }
478
479         final Optional<? extends ToscaPropertyData> sourceSelectedProperty = findPropertyFromGetFunction(component, toscaGetFunction);
480         if (sourceSelectedProperty.isEmpty()) {
481             return Either.right(componentsUtils.getResponseFormat(ActionStatus.FILTER_PROPERTY_NOT_FOUND, SOURCE, getPropertyType(toscaGetFunction),
482                 String.join("->", toscaGetFunction.getPropertyPathFromSource())));
483         }
484
485         final ResponseFormat responseFormat = validatePropertyData(sourceSelectedProperty.get(), targetComponentProperty.get());
486         if (responseFormat != null) {
487             return Either.right(responseFormat);
488         }
489         return Either.left(true);
490     }
491
492     private String getPropertyType(final ToscaGetFunctionDataDefinition toscaGetFunction) {
493         switch (toscaGetFunction.getType()) {
494             case GET_INPUT:
495                 return "input";
496             case GET_PROPERTY:
497                 return "property";
498             case GET_ATTRIBUTE:
499                 return "attribute";
500             default:
501                 return "";
502         }
503     }
504
505 }