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