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