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